From 0c184d985a7fa213ad02c6b0dac2a00e1483baeb Mon Sep 17 00:00:00 2001 From: Gavin1012 Date: Wed, 11 Aug 2021 11:23:51 +0800 Subject: [PATCH] upgrade jerry from v2.1 to v2.3 Signed-off-by: Gavin1012 --- .travis.yml | 32 +- BUILD.gn | 26 + Doxyfile | 1 - README.OpenSource | 2 +- README.md | 7 +- appveyor.yml | 12 +- cmake/toolchain_linux_aarch64.cmake | 18 + docs/00.GETTING-STARTED.md | 2 +- docs/01.CONFIGURATION.md | 31 +- docs/02.API-REFERENCE.md | 1000 ++++- docs/03.API-EXAMPLE.md | 3 +- engine.gni | 48 +- jerry-core/BUILD.gn | 14 + jerry-core/CMakeLists.txt | 10 + jerry-core/api/generate-bytecode.c | 1056 ++--- jerry-core/api/generate-bytecode.h | 102 +- jerry-core/api/jerry-snapshot.c | 154 +- jerry-core/api/jerry.c | 950 +++- jerry-core/api/jerryscript_adapter.c | 82 +- jerry-core/config.h | 149 +- jerry-core/debugger/debugger.c | 72 +- jerry-core/debugger/debugger.h | 2 +- jerry-core/ecma/base/ecma-gc.c | 1121 +++-- jerry-core/ecma/base/ecma-gc.h | 1 + jerry-core/ecma/base/ecma-globals.h | 355 +- .../ecma/base/ecma-helpers-collection.c | 43 + .../ecma/base/ecma-helpers-conversion.c | 120 +- .../base/ecma-helpers-external-pointers.c | 13 +- jerry-core/ecma/base/ecma-helpers-number.c | 418 +- jerry-core/ecma/base/ecma-helpers-string.c | 205 +- jerry-core/ecma/base/ecma-helpers-value.c | 112 +- jerry-core/ecma/base/ecma-helpers.c | 239 +- jerry-core/ecma/base/ecma-helpers.h | 107 +- jerry-core/ecma/base/ecma-init-finalize.c | 38 +- jerry-core/ecma/base/ecma-literal-storage.c | 12 +- jerry-core/ecma/base/ecma-module.c | 81 +- jerry-core/ecma/base/ecma-module.h | 2 +- jerry-core/ecma/base/ecma-property-hashmap.c | 1 - jerry-core/ecma/base/ecma-property-hashmap.h | 1 - .../ecma-builtin-array-iterator-prototype.c | 50 +- ...cma-builtin-array-iterator-prototype.inc.h | 4 +- ...ecma-builtin-array-prototype-unscopables.c | 28 + ...-builtin-array-prototype-unscopables.inc.h | 54 + .../ecma-builtin-array-prototype.c | 1055 +++-- .../ecma-builtin-array-prototype.inc.h | 25 +- .../ecma/builtin-objects/ecma-builtin-array.c | 445 +- .../builtin-objects/ecma-builtin-array.inc.h | 12 +- .../ecma-builtin-arraybuffer-prototype.c | 35 +- .../ecma-builtin-arraybuffer-prototype.inc.h | 6 +- .../ecma-builtin-arraybuffer.c | 21 +- .../ecma-builtin-arraybuffer.inc.h | 7 +- .../ecma-builtin-boolean.inc.h | 3 +- .../ecma-builtin-dataview-prototype.c | 11 + .../ecma-builtin-dataview-prototype.inc.h | 10 +- .../ecma-builtin-dataview.inc.h | 2 +- .../ecma-builtin-date-prototype.c | 61 +- .../ecma-builtin-date-prototype.inc.h | 3 + .../ecma/builtin-objects/ecma-builtin-date.c | 552 ++- .../builtin-objects/ecma-builtin-date.inc.h | 2 +- .../ecma-builtin-error-prototype.c | 180 +- .../builtin-objects/ecma-builtin-error.inc.h | 3 +- .../ecma-builtin-evalerror.inc.h | 3 +- .../ecma-builtin-function-prototype.c | 155 +- .../ecma-builtin-function-prototype.h | 23 + .../ecma-builtin-function-prototype.inc.h | 19 +- .../builtin-objects/ecma-builtin-function.c | 120 +- .../ecma-builtin-function.inc.h | 3 +- .../ecma-builtin-generator-function.c | 72 + .../ecma-builtin-generator-function.inc.h | 41 + .../ecma-builtin-generator-prototype.c | 250 ++ .../ecma-builtin-generator-prototype.inc.h | 45 + .../builtin-objects/ecma-builtin-generator.c | 43 + .../ecma-builtin-generator.inc.h | 41 + .../builtin-objects/ecma-builtin-global.c | 422 +- .../builtin-objects/ecma-builtin-global.inc.h | 40 +- .../ecma-builtin-helpers-date.c | 38 +- .../ecma-builtin-helpers-error.c | 25 +- .../ecma-builtin-helpers-macro-defines.inc.h | 18 +- .../ecma-builtin-helpers-macro-undefs.inc.h | 7 +- .../builtin-objects/ecma-builtin-helpers.c | 580 ++- .../builtin-objects/ecma-builtin-helpers.h | 55 +- ...a-builtin-internal-routines-template.inc.h | 61 +- .../builtin-objects/ecma-builtin-intrinsic.c | 143 + .../ecma-builtin-intrinsic.inc.h | 73 + .../ecma-builtin-iterator-prototype.c | 4 +- .../ecma-builtin-iterator-prototype.inc.h | 4 +- .../ecma/builtin-objects/ecma-builtin-json.c | 164 +- .../builtin-objects/ecma-builtin-json.inc.h | 4 +- .../ecma-builtin-map-iterator-prototype.c | 4 - .../ecma-builtin-map-prototype.c | 7 +- .../ecma-builtin-map-prototype.inc.h | 12 +- .../ecma/builtin-objects/ecma-builtin-map.c | 12 + .../builtin-objects/ecma-builtin-map.inc.h | 7 +- .../ecma/builtin-objects/ecma-builtin-math.c | 254 +- .../builtin-objects/ecma-builtin-math.inc.h | 23 +- .../ecma-builtin-number-prototype.c | 57 +- .../builtin-objects/ecma-builtin-number.c | 9 +- .../builtin-objects/ecma-builtin-number.inc.h | 28 +- .../ecma-builtin-object-prototype.c | 58 +- .../ecma-builtin-object-prototype.inc.h | 5 + .../builtin-objects/ecma-builtin-object.c | 908 ++-- .../builtin-objects/ecma-builtin-object.h | 36 + .../builtin-objects/ecma-builtin-object.inc.h | 12 +- .../ecma-builtin-promise-prototype.inc.h | 8 +- .../builtin-objects/ecma-builtin-promise.c | 480 +- .../ecma-builtin-promise.inc.h | 7 +- .../ecma/builtin-objects/ecma-builtin-proxy.c | 120 + .../builtin-objects/ecma-builtin-proxy.inc.h | 38 + .../ecma-builtin-rangeerror.inc.h | 3 +- .../ecma-builtin-referenceerror.inc.h | 3 +- .../builtin-objects/ecma-builtin-reflect.c | 341 ++ .../ecma-builtin-reflect.inc.h | 38 + .../ecma-builtin-regexp-prototype.c | 510 ++- .../ecma-builtin-regexp-prototype.inc.h | 25 +- .../builtin-objects/ecma-builtin-regexp.c | 209 +- .../builtin-objects/ecma-builtin-regexp.inc.h | 10 +- .../ecma-builtin-set-iterator-prototype.c | 4 - .../ecma-builtin-set-prototype.c | 5 +- .../ecma-builtin-set-prototype.inc.h | 10 +- .../ecma/builtin-objects/ecma-builtin-set.c | 12 + .../builtin-objects/ecma-builtin-set.inc.h | 7 +- .../ecma-builtin-string-iterator-prototype.c | 9 +- ...ma-builtin-string-iterator-prototype.inc.h | 4 +- .../ecma-builtin-string-prototype.c | 1924 +++----- .../ecma-builtin-string-prototype.inc.h | 8 +- .../builtin-objects/ecma-builtin-string.c | 242 +- .../builtin-objects/ecma-builtin-string.inc.h | 8 +- .../ecma-builtin-symbol-prototype.c | 4 +- .../ecma-builtin-symbol-prototype.inc.h | 8 +- .../builtin-objects/ecma-builtin-symbol.c | 14 +- .../builtin-objects/ecma-builtin-symbol.inc.h | 61 +- .../ecma-builtin-syntaxerror.inc.h | 3 +- .../ecma-builtin-type-error-thrower.c | 7 +- .../ecma-builtin-typeerror.inc.h | 3 +- .../ecma-builtin-urierror.inc.h | 3 +- .../ecma-builtin-weakmap-prototype.c | 108 + .../ecma-builtin-weakmap-prototype.inc.h | 46 + .../builtin-objects/ecma-builtin-weakmap.c | 74 + .../ecma-builtin-weakmap.inc.h | 47 + .../ecma-builtin-weakset-prototype.c | 91 + .../ecma-builtin-weakset-prototype.inc.h | 45 + .../builtin-objects/ecma-builtin-weakset.c | 74 + .../ecma-builtin-weakset.inc.h | 47 + .../builtin-objects/ecma-builtins-internal.h | 12 +- .../ecma/builtin-objects/ecma-builtins.c | 463 +- .../ecma/builtin-objects/ecma-builtins.h | 11 +- .../ecma/builtin-objects/ecma-builtins.inc.h | 230 +- .../ecma-builtin-typedarray-prototype.c | 741 ++-- .../ecma-builtin-typedarray-prototype.inc.h | 16 +- .../ecma-builtin-typedarray-template.inc.h | 7 +- .../typedarray/ecma-builtin-typedarray.c | 68 +- .../typedarray/ecma-builtin-typedarray.inc.h | 7 +- .../ecma/operations/ecma-array-object.c | 460 +- .../ecma/operations/ecma-array-object.h | 52 +- .../ecma/operations/ecma-arraybuffer-object.c | 75 +- .../ecma/operations/ecma-arraybuffer-object.h | 6 + jerry-core/ecma/operations/ecma-comparison.c | 12 +- .../ecma/operations/ecma-container-object.c | 1172 +++-- .../ecma/operations/ecma-container-object.h | 12 +- jerry-core/ecma/operations/ecma-conversion.c | 264 +- jerry-core/ecma/operations/ecma-conversion.h | 7 +- .../ecma/operations/ecma-dataview-object.c | 79 +- .../ecma/operations/ecma-dataview-object.h | 1 + jerry-core/ecma/operations/ecma-eval.c | 8 +- jerry-core/ecma/operations/ecma-exceptions.c | 42 +- .../ecma/operations/ecma-function-object.c | 1993 +++++---- .../ecma/operations/ecma-function-object.h | 67 +- .../ecma/operations/ecma-get-put-value.c | 150 +- .../ecma/operations/ecma-iterator-object.c | 294 +- .../ecma/operations/ecma-iterator-object.h | 21 +- jerry-core/ecma/operations/ecma-jobqueue.c | 195 +- jerry-core/ecma/operations/ecma-jobqueue.h | 18 +- jerry-core/ecma/operations/ecma-lex-env.c | 231 +- jerry-core/ecma/operations/ecma-lex-env.h | 29 +- .../ecma/operations/ecma-objects-arguments.c | 20 +- .../ecma/operations/ecma-objects-general.c | 270 +- .../ecma/operations/ecma-objects-general.h | 9 + jerry-core/ecma/operations/ecma-objects.c | 1353 ++++-- jerry-core/ecma/operations/ecma-objects.h | 44 +- .../ecma/operations/ecma-promise-object.c | 603 ++- .../ecma/operations/ecma-promise-object.h | 49 +- .../ecma/operations/ecma-proxy-object.c | 1818 ++++++++ .../ecma/operations/ecma-proxy-object.h | 120 + jerry-core/ecma/operations/ecma-reference.c | 286 +- jerry-core/ecma/operations/ecma-reference.h | 7 +- .../ecma/operations/ecma-regexp-object.c | 3941 +++++++++++++---- .../ecma/operations/ecma-regexp-object.h | 119 +- .../ecma/operations/ecma-string-object.c | 24 +- .../ecma/operations/ecma-string-object.h | 3 +- .../ecma/operations/ecma-symbol-object.c | 27 +- .../ecma/operations/ecma-symbol-object.h | 4 +- .../ecma/operations/ecma-typedarray-object.c | 524 ++- .../ecma/operations/ecma-typedarray-object.h | 5 +- jerry-core/ext/debug-utils.c | 13 +- jerry-core/ext/heapdump.c | 11 +- jerry-core/include/jerryscript-core.h | 54 +- jerry-core/include/jerryscript-port.h | 1 + jerry-core/include/jerryscript-snapshot.h | 2 +- jerry-core/jcontext/jcontext.c | 99 + jerry-core/jcontext/jcontext.h | 62 +- jerry-core/jmem/jmem-allocator.c | 1 - jerry-core/jmem/jmem-heap.c | 16 +- jerry-core/jmem/jmem.h | 74 + jerry-core/jrt/jrt-fatals.c | 9 +- jerry-core/libjerry-core.pc.in | 2 +- jerry-core/lit/lit-char-helpers.c | 327 +- jerry-core/lit/lit-char-helpers.h | 26 +- jerry-core/lit/lit-magic-strings.h | 7 +- jerry-core/lit/lit-magic-strings.inc.h | 310 +- jerry-core/lit/lit-magic-strings.ini | 43 +- jerry-core/lit/lit-strings.c | 53 +- jerry-core/lit/lit-strings.h | 13 +- jerry-core/lit/lit-unicode-conversions.inc.h | 23 +- jerry-core/lit/lit-unicode-ranges.inc.h | 195 +- jerry-core/parser/js/byte-code.h | 302 +- jerry-core/parser/js/common.c | 9 +- jerry-core/parser/js/common.h | 17 +- jerry-core/parser/js/js-lexer.c | 2295 +++++++--- jerry-core/parser/js/js-lexer.h | 127 +- jerry-core/parser/js/js-parser-expr.c | 2202 ++++++--- jerry-core/parser/js/js-parser-internal.h | 352 +- jerry-core/parser/js/js-parser-limits.h | 40 +- jerry-core/parser/js/js-parser-mem.c | 19 +- jerry-core/parser/js/js-parser-module.c | 69 +- jerry-core/parser/js/js-parser-statm.c | 1543 ++++--- .../js/js-parser-tagged-template-literal.c | 152 + .../js/js-parser-tagged-template-literal.h | 51 + jerry-core/parser/js/js-parser-util.c | 333 +- jerry-core/parser/js/js-parser.c | 1714 +++---- jerry-core/parser/js/js-parser.h | 60 +- jerry-core/parser/js/js-scanner-internal.h | 340 +- jerry-core/parser/js/js-scanner-ops.c | 590 +++ jerry-core/parser/js/js-scanner-util.c | 2221 +++++++++- jerry-core/parser/js/js-scanner.c | 2122 +++++++-- jerry-core/parser/js/js-scanner.h | 143 +- jerry-core/parser/regexp/re-bytecode.c | 762 ++-- jerry-core/parser/regexp/re-bytecode.h | 120 +- .../parser/regexp/re-compiler-context.h | 60 + jerry-core/parser/regexp/re-compiler.c | 878 +--- jerry-core/parser/regexp/re-compiler.h | 21 +- jerry-core/parser/regexp/re-parser.c | 1577 +++++-- jerry-core/parser/regexp/re-parser.h | 70 +- jerry-core/parser/regexp/re-token.h | 72 + jerry-core/profiles/README.md | 56 +- jerry-core/vm/opcodes-ecma-arithmetics.c | 25 +- .../vm/opcodes-ecma-relational-equality.c | 30 +- jerry-core/vm/opcodes.c | 1075 ++++- jerry-core/vm/opcodes.h | 56 +- jerry-core/vm/vm-defines.h | 31 +- jerry-core/vm/vm-stack.c | 188 +- jerry-core/vm/vm-stack.h | 68 +- jerry-core/vm/vm-utils.c | 35 +- jerry-core/vm/vm.c | 2402 ++++++---- jerry-core/vm/vm.h | 181 +- jerry-debugger/jerry_client.py | 98 +- jerry-debugger/jerry_client_main.py | 267 +- jerry-ext/BUILD.gn | 1 + jerry-ext/CMakeLists.txt | 2 +- jerry-ext/arg/arg.c | 1 - jerry-ext/debugger/debugger-tcp.c | 4 +- jerry-ext/handler/handler-register.c | 17 +- jerry-ext/handler/handler-resource-name.c | 42 + .../include/jerryscript-ext/handle-scope.h | 1 - jerry-ext/include/jerryscript-ext/handler.h | 2 + jerry-ext/module/module.c | 1 - jerry-libm/BUILD.gn | 103 +- jerry-libm/acos.c | 2 +- jerry-libm/acosh.c | 92 + jerry-libm/asin.c | 2 +- jerry-libm/asinh.c | 95 + jerry-libm/atan2.c | 2 +- jerry-libm/atanh.c | 100 + jerry-libm/cbrt.c | 103 + jerry-libm/cosh.c | 113 + jerry-libm/exp.c | 2 +- jerry-libm/expm1.c | 305 ++ jerry-libm/fmod.c | 6 +- jerry-libm/include/math.h | 15 + jerry-libm/jerry-libm-internal.h | 14 +- jerry-libm/log10.c | 116 + jerry-libm/log1p.c | 245 + jerry-libm/log2.c | 160 + jerry-libm/pow.c | 4 +- jerry-libm/sinh.c | 115 + jerry-libm/sqrt.c | 6 +- jerry-libm/tanh.c | 117 + jerry-main/benchmarking.c | 1 - jerry-main/cli.c | 2 +- jerry-main/libfuzzer.c | 1 - jerry-main/main-unix-snapshot.c | 2 +- jerry-main/main-unix-test.c | 7 +- jerry-main/main-unix.c | 89 +- jerry-port/default/BUILD.gn | 72 +- jerry-port/default/default-date.c | 1 - targets/curie_bsp/jerry_app/quark/main.c | 3 +- targets/esp8266/user/jerry_run.c | 3 +- .../source/launcher.cpp | 3 +- targets/mbedos5/source/jerry_port_mbed.c | 2 +- targets/riot-stm32f4/source/main-riotos.c | 3 +- targets/zephyr/Makefile.travis | 10 +- targets/zephyr/src/main-zephyr.c | 3 +- tests/.gitattributes | 2 + tests/debugger/do_eval_at.cmd | 4 +- tests/debugger/do_eval_at.expected | 4 +- tests/debugger/do_help.expected | 10 +- tests/debugger/do_scope.cmd | 19 + tests/debugger/do_scope.expected | 63 + tests/debugger/{do_scopes.js => do_scope.js} | 0 tests/debugger/do_scopes.cmd | 19 - tests/debugger/do_scopes.expected | 63 - tests/debugger/do_src.expected | 2 + tests/debugger/do_variables.cmd | 10 +- tests/debugger/do_variables.expected | 86 +- .../07/07.06/07.06.01/07.06.01-001.js | 2 +- .../es2015/15.03.04.02-001.js | 17 + .../es2015/15.03.04.02-004.js | 17 + .../es2015/25/25.04/25.04.05/25.04.05-001.js | 2 +- .../{13/13.02 => es5.1}/13.02-002.js | 0 .../15.03.04.02 => es5.1}/15.03.04.02-001.js | 0 .../15.03.04.02 => es5.1}/15.03.04.02-004.js | 0 .../15.07.03.01 => es5.1}/15.07.03.01-004.js | 0 .../15.07.03.01 => es5.1}/15.07.03.01-008.js | 0 .../15.07.03.01 => es5.1}/15.07.03.01-009.js | 0 .../15.07.03.01 => es5.1}/15.07.03.01-010.js | 0 .../15.07.03.01 => es5.1}/15.07.03.01-011.js | 0 .../15.07/15.07.04 => es5.1}/15.07.04-001.js | 0 .../15.07/15.07.04 => es5.1}/15.07.04-002.js | 0 .../15.07.04.02 => es5.1}/15.07.04.02-006.js | 0 .../15.07.04.02 => es5.1}/15.07.04.02-008.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-001.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-002.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-003.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-004.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-005.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-006.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-007.js | 0 .../15.07.04.05 => es5.1}/15.07.04.05-008.js | 0 tests/jerry-test-suite/es51-profile-list | 1468 ------ tests/jerry/arguments.js | 14 + tests/jerry/arithmetic-parse.js | 49 + tests/jerry/array-prototype-indexof.js | 30 + tests/jerry/array-prototype-lastindexof.js | 30 + tests/jerry/array-prototype-push.js | 9 - tests/jerry/array-prototype-reduce-right.js | 10 +- tests/jerry/array-prototype-reduce.js | 2 + tests/jerry/array-prototype-slice.js | 38 + tests/jerry/date-construct.js | 3 - tests/jerry/date-parse.js | 48 +- tests/jerry/date-setters.js | 16 - tests/jerry/date-tostring.js | 38 +- tests/jerry/es2015/argument-spread.js | 111 + tests/jerry/es2015/arguments-iterator.js | 50 + tests/jerry/es2015/array-from.js | 344 ++ tests/jerry/es2015/array-isarray.js | 48 + .../jerry/es2015/array-new-target-support.js | 32 + tests/jerry/es2015/array-of.js | 78 + tests/jerry/es2015/array-pattern.js | 313 ++ .../es2015/array-prototype-copywithin.js | 119 + tests/jerry/es2015/array-prototype-fill.js | 218 + .../es2015/array-prototype-find-index.js | 15 +- tests/jerry/es2015/array-prototype-find.js | 7 + tests/jerry/es2015/array-prototype-slice.js | 55 + tests/jerry/es2015/array-species.js | 184 + tests/jerry/es2015/array-spread.js | 79 + tests/jerry/es2015/arraybuffer-isview.js | 37 + tests/jerry/es2015/arrow-assignment.js | 46 + tests/jerry/es2015/arrow-eval.js | 41 + tests/jerry/es2015/arrow-function.js | 40 +- tests/jerry/es2015/binary-literal.js | 52 + ...-objects-accessor-property-configurable.js | 48 + tests/jerry/es2015/builtin-prototypes.js | 117 + .../es2015/class-inheritance-builtin-array.js | 2 - .../class-inheritance-early-semantics.js | 8 + .../es2015/class-inheritance-has-instance.js | 2 +- .../es2015/class-inheritance-inner-class.js | 3 + tests/jerry/es2015/class.js | 96 + tests/jerry/es2015/const1.js | 74 + tests/jerry/es2015/continue.js | 44 + tests/jerry/es2015/dataview.js | 9 +- .../es2015/date-prototype-toprimitive.js | 51 + tests/jerry/es2015/directive.js | 35 + tests/jerry/es2015/error.js | 21 + tests/jerry/es2015/exponentiation.js | 73 + tests/jerry/es2015/for-let-reference-error.js | 30 + tests/jerry/es2015/for-let.js | 105 + tests/jerry/es2015/for-of-iterator-close.js | 244 + tests/jerry/es2015/for-pattern.js | 77 + tests/jerry/es2015/forin-header-strict.js | 61 + tests/jerry/es2015/function-accessor.js | 31 + .../jerry/es2015/function-arguments-caller.js | 47 + tests/jerry/es2015/function-async1.js | 146 + tests/jerry/es2015/function-async2.js | 69 + tests/jerry/es2015/function-await1.js | 138 + tests/jerry/es2015/function-call.js | 38 + tests/jerry/es2015/function-if.js | 119 + tests/jerry/es2015/function-name.js | 297 ++ tests/jerry/es2015/function-new-target.js | 32 + tests/jerry/es2015/function-param-init2.js | 100 + tests/jerry/es2015/function-param-init3.js | 68 + tests/jerry/es2015/function-param-init4.js | 164 + tests/jerry/es2015/function-pattern1.js | 94 + tests/jerry/es2015/function-pattern2.js | 93 + tests/jerry/es2015/function-properties.js | 2 +- tests/jerry/es2015/function-prototype-bind.js | 69 + .../function-prototype-hasinstance-class.js | 53 + .../es2015/function-prototype-hasinstance.js | 81 + tests/jerry/es2015/function-rest-parameter.js | 16 + tests/jerry/es2015/function-scope.js | 67 + tests/jerry/es2015/function-scope2.js | 111 + tests/jerry/es2015/generator-function.js | 97 + tests/jerry/es2015/generator-initializer.js | 138 + tests/jerry/es2015/generator-return.js | 74 + tests/jerry/es2015/generator-throw.js | 82 + .../jerry/es2015/generator-yield-iterator.js | 121 + tests/jerry/es2015/generator-yield.js | 86 + tests/jerry/es2015/generator.js | 199 + tests/jerry/es2015/identifier-escape.js | 36 + .../instanceof-symbol-hasinstance-class.js | 50 + .../es2015/instanceof-symbol-hasinstance.js | 86 + tests/jerry/es2015/json-stringify.js | 48 + tests/jerry/es2015/length-property.js | 146 + tests/jerry/es2015/let1.js | 42 + tests/jerry/es2015/let10.js | 45 + tests/jerry/es2015/let11.js | 18 + tests/jerry/es2015/let12.js | 41 + tests/jerry/es2015/let13.js | 110 + tests/jerry/es2015/let14.js | 54 + tests/jerry/es2015/let15.js | 65 + tests/jerry/es2015/let2.js | 47 + tests/jerry/es2015/let3.js | 87 + tests/jerry/es2015/let4.js | 87 + tests/jerry/es2015/let5.js | 35 + tests/jerry/es2015/let6.js | 79 + tests/jerry/es2015/let7.js | 84 + tests/jerry/es2015/let8.js | 58 + tests/jerry/es2015/let9.js | 48 + tests/jerry/es2015/map-iterators.js | 104 +- tests/jerry/es2015/map-prototype-foreach.js | 10 + tests/jerry/es2015/map.js | 34 + tests/jerry/es2015/math-acosh.js | 29 + tests/jerry/es2015/math-asinh.js | 29 + tests/jerry/es2015/math-atanh.js | 32 + tests/jerry/es2015/math-cbrt.js | 33 + tests/jerry/es2015/math-cosh.js | 22 + tests/jerry/es2015/math-expm1.js | 31 + .../es2015/math-functions-tonumber-rule2.js | 23 + tests/jerry/es2015/math-log10.js | 26 + tests/jerry/es2015/math-log1p.js | 30 + tests/jerry/es2015/math-log2.js | 27 + tests/jerry/es2015/math-sinh.js | 27 + tests/jerry/es2015/math-tanh.js | 27 + tests/jerry/es2015/math-trunc.js | 13 +- tests/jerry/es2015/module-export-fail-test.js | 17 + tests/jerry/es2015/new-target-async.js | 20 + tests/jerry/es2015/new-target-class.js | 63 + .../jerry/es2015/new-target-for-containers.js | 86 + .../es2015/new-target-for-date-object.js | 40 + tests/jerry/es2015/new-target-generator.js | 33 + tests/jerry/es2015/new-target.js | 161 + tests/jerry/es2015/number-constants.js | 19 + tests/jerry/es2015/number-methods.js | 22 + tests/jerry/es2015/object-assign.js | 9 + .../jerry/es2015/object-freeze-with-symbol.js | 28 + .../es2015/object-get-own-property-names.js | 23 + .../es2015/object-get-own-property-symbols.js | 8 - tests/jerry/es2015/object-initializer.js | 5 + tests/jerry/es2015/object-is.js | 59 + tests/jerry/es2015/object-methods.js | 60 + tests/jerry/es2015/object-pattern.js | 234 + tests/jerry/es2015/object-prototype-proto.js | 89 + tests/jerry/es2015/object-seal-with-symbol.js | 28 + tests/jerry/es2015/octal-literal.js | 46 + tests/jerry/es2015/promise-all-iterator.js | 81 + tests/jerry/es2015/promise-new-target.js | 26 + tests/jerry/es2015/promise-race-iterator.js | 69 + tests/jerry/es2015/promise-species.js | 53 + tests/jerry/es2015/promise-thenable.js | 32 + tests/jerry/es2015/proxy_call.js | 355 ++ tests/jerry/es2015/proxy_construct.js | 165 + tests/jerry/es2015/proxy_create.js | 58 + .../jerry/es2015/proxy_define_own_property.js | 176 + tests/jerry/es2015/proxy_delete.js | 164 + tests/jerry/es2015/proxy_get.js | 140 + .../proxy_get_own_property_descriptor.js | 270 ++ tests/jerry/es2015/proxy_get_prototoype_of.js | 168 + tests/jerry/es2015/proxy_has.js | 172 + tests/jerry/es2015/proxy_is_extensible.js | 164 + tests/jerry/es2015/proxy_own_keys.js | 225 + .../jerry/es2015/proxy_prevent_extensions.js | 147 + tests/jerry/es2015/proxy_revocable.js | 64 + tests/jerry/es2015/proxy_set.js | 140 + .../jerry/es2015/proxy_set_apply_receiver.js | 30 + tests/jerry/es2015/proxy_set_prototoype_of.js | 158 + tests/jerry/es2015/reflect-apply.js | 18 + tests/jerry/es2015/reflect-construct.js | 80 + tests/jerry/es2015/reflect-define-Property.js | 23 + tests/jerry/es2015/reflect-deleteproperty.js | 61 + .../reflect-get-own-property-description.js | 21 + tests/jerry/es2015/reflect-get.js | 55 + tests/jerry/es2015/reflect-getPrototypeOf.js | 31 + tests/jerry/es2015/reflect-has.js | 64 + tests/jerry/es2015/reflect-isextensible.js | 22 + tests/jerry/es2015/reflect-own-keys.js | 144 + .../jerry/es2015/reflect-preventextensions.js | 20 + tests/jerry/es2015/reflect-set.js | 68 + tests/jerry/es2015/reflect-setPrototypeOf.js | 21 + .../es2015/regexp-accessors-descriptors.js | 23 + tests/jerry/es2015/regexp-construct.js | 57 + tests/jerry/es2015/regexp-flags.js | 72 + tests/jerry/es2015/regexp-lastindex.js | 2 + tests/jerry/es2015/regexp-new-target.js | 19 + tests/jerry/es2015/regexp-prototype-match.js | 74 + tests/jerry/es2015/regexp-prototype-source.js | 55 + tests/jerry/es2015/regexp-prototype-test.js | 24 + tests/jerry/es2015/regexp-routines.js | 146 + tests/jerry/es2015/regexp-unicode.js | 361 ++ .../regression-test-issue-2544.js | 7 +- .../es2015/regression-test-issue-2825.js | 4 +- .../es2015/regression-test-issue-2891.js | 26 + .../es2015/regression-test-issue-3070.js | 17 + .../es2015/regression-test-issue-3084.js | 2 +- .../es2015/regression-test-issue-3222.js | 22 + .../es2015/regression-test-issue-3237.js | 17 + .../es2015/regression-test-issue-3243.js | 20 + .../es2015/regression-test-issue-3250.js | 16 + .../es2015/regression-test-issue-3252.js | 21 + .../es2015/regression-test-issue-3262.js | 15 + .../es2015/regression-test-issue-3267.js | 22 + .../es2015/regression-test-issue-3298.js | 22 + .../es2015/regression-test-issue-3306.js | 21 + .../es2015/regression-test-issue-3348.js | 19 + ...class.js => regression-test-issue-3355.js} | 3 +- .../es2015/regression-test-issue-3356.js | 19 + .../es2015/regression-test-issue-3360.js | 16 + .../es2015/regression-test-issue-3361.js | 17 + .../es2015/regression-test-issue-3363.js | 17 + .../es2015/regression-test-issue-3364.js | 15 + .../es2015/regression-test-issue-3376.js | 22 + .../es2015/regression-test-issue-3381.js | 17 + .../es2015/regression-test-issue-3383.js | 15 + .../es2015/regression-test-issue-3390.js | 20 + .../es2015/regression-test-issue-3396.js | 19 + .../es2015/regression-test-issue-3408.js | 17 + .../es2015/regression-test-issue-3409.js | 28 + .../es2015/regression-test-issue-3411.js | 17 + .../es2015/regression-test-issue-3419.js | 20 + .../es2015/regression-test-issue-3420.js | 21 + .../es2015/regression-test-issue-3421.js | 19 + .../es2015/regression-test-issue-3422.js | 16 + .../es2015/regression-test-issue-3431.js | 27 + .../es2015/regression-test-issue-3434.js | 19 + .../es2015/regression-test-issue-3437.js | 17 + .../es2015/regression-test-issue-3454.js | 21 + .../es2015/regression-test-issue-3455.js | 42 + .../es2015/regression-test-issue-3458.js | 28 + .../es2015/regression-test-issue-3459.js | 21 + .../es2015/regression-test-issue-3478.js | 21 + .../es2015/regression-test-issue-3479.js | 21 + .../es2015/regression-test-issue-3483.js | 26 + .../es2015/regression-test-issue-3485.js | 22 + .../es2015/regression-test-issue-3519.js | 24 + .../es2015/regression-test-issue-3527.js | 34 + .../es2015/regression-test-issue-3534.js | 23 + .../es2015/regression-test-issue-3536.js | 36 + .../es2015/regression-test-issue-3580.js | 19 + .../es2015/regression-test-issue-3588.js | 19 + .../es2015/regression-test-issue-3589.js | 27 + .../es2015/regression-test-issue-3595.js | 25 + .../es2015/regression-test-issue-3606.js | 17 + .../es2015/regression-test-issue-3611.js | 40 + .../es2015/regression-test-issue-3625.js | 27 + .../es2015/regression-test-issue-3628.js | 25 + .../es2015/regression-test-issue-3630.js | 23 + .../es2015/regression-test-issue-3636.js | 39 + .../es2015/regression-test-issue-3637.js | 24 + .../es2015/regression-test-issue-3640.js | 23 + .../es2015/regression-test-issue-3641.js | 26 + .../es2015/regression-test-issue-3647.js | 19 + .../es2015/regression-test-issue-3655.js | 22 + .../es2015/regression-test-issue-3656.js | 16 + .../es2015/regression-test-issue-3658.js | 24 + .../es2015/regression-test-issue-3665.js | 20 + .../es2015/regression-test-issue-3671.js | 32 + .../es2015/regression-test-issue-3715.js | 21 + .../es2015/regression-test-issue-3751.js | 26 + .../es2015/regression-test-issue-3760.js | 22 + .../es2015/regression-test-issue-3784.js | 32 + .../es2015/regression-test-issue-3785.js | 37 + .../es2015/regression-test-issue-3787.js | 22 + .../es2015/regression-test-issue-3812.js | 19 + .../es2015/regression-test-issue-3814.js | 17 + .../es2015/regression-test-issue-3817.js | 16 + .../es2015/regression-test-issue-3819.js | 20 + .../es2015/regression-test-issue-3820.js | 20 + .../es2015/regression-test-issue-3822.js | 21 + .../es2015/regression-test-issue-3823.js | 21 + .../es2015/regression-test-issue-3824.js | 21 + .../es2015/regression-test-issue-3825.js | 34 + .../es2015/regression-test-issue-3836.js | 56 + .../es2015/regression-test-issue-3837.js | 33 + .../es2015/regression-test-issue-3845.js | 21 + .../es2015/regression-test-issue-3849.js | 21 + .../es2015/regression-test-issue-3860.js | 53 + .../es2015/regression-test-issue-3861.js | 26 + .../es2015/regression-test-issue-3862.js | 29 + .../es2015/regression-test-issue-3866.js | 34 + .../es2015/regression-test-issue-3868.js | 22 + .../es2015/regression-test-issue-3870.js | 15 + .../es2015/regression-test-issue-3871.js | 20 + .../es2015/regression-test-issue-3880.js | 21 + .../es2015/regression-test-issue-3893.js | 17 + .../es2015/regresssion-test-issue-3302.js | 26 + .../es2015/regresssion-test-issue-3395.js | 16 + .../es2015/regresssion-test-issue-3713.js | 18 + .../es2015/regresssion-test-issue-3727.js | 15 + .../es2015/regresssion-test-issue-3841.js | 20 + .../es2015/regresssion-test-issue-3842.js | 20 + .../es2015/regresssion-test-issue-3856.js | 18 + .../es2015/regresssion-test-issue-3857.js | 17 + .../es2015/regresssion-test-issue-3869.js | 20 + .../es2015/regresssion-test-issue-3888.js | 19 + tests/jerry/es2015/set-iterators.js | 46 + tests/jerry/es2015/set.js | 45 + tests/jerry/es2015/string-fromcodepoint.js | 64 + .../es2015/string-prototype-codepointat.js | 54 + .../jerry/es2015/string-prototype-endswith.js | 17 + .../jerry/es2015/string-prototype-includes.js | 17 + tests/jerry/es2015/string-prototype-match.js | 82 + tests/jerry/es2015/string-prototype-split.js | 23 + .../es2015/string-prototype-startswith.js | 20 + .../string-raw-crash-escaping-backslash.js | 26 + tests/jerry/es2015/string-raw.js | 71 + tests/jerry/es2015/super-assignment.js | 75 + .../jerry/es2015/symbol-isconcatspreadable.js | 81 + .../jerry/es2015/symbol-prototype-tostring.js | 8 +- .../es2015/symbol-prototype.toprimitive.js | 30 + tests/jerry/es2015/symbol-replace.js | 674 +++ tests/jerry/es2015/symbol-search.js | 228 + tests/jerry/es2015/symbol-split.js | 109 + tests/jerry/es2015/symbol-unscopables.js | 127 + tests/jerry/es2015/symbol.js | 5 + tests/jerry/es2015/tagged-template-literal.js | 139 + tests/jerry/es2015/template_string.js | 18 +- tests/jerry/es2015/to-number-string.js | 49 + tests/jerry/es2015/try-catch.js | 130 + tests/jerry/es2015/try-pattern.js | 94 + tests/jerry/es2015/typedarray-from.js | 157 + tests/jerry/es2015/typedarray-of.js | 131 + tests/jerry/es2015/weakmap.js | 184 + tests/jerry/es2015/weakset.js | 168 + tests/jerry/es5.1/array-prototype-push.js | 34 + tests/jerry/es5.1/builtin-prototypes.js | 81 + tests/jerry/es5.1/func-decl.js | 25 + .../es5.1/func-length.js} | 2 +- tests/jerry/es5.1/object-methods.js | 89 + tests/jerry/es5.1/regexp-construct.js | 25 + tests/jerry/es5.1/regexp-routines.js | 20 + .../{ => es5.1}/regression-test-issue-1065.js | 0 .../{ => es5.1}/regression-test-issue-1080.js | 0 .../{ => es5.1}/regression-test-issue-1546.js | 0 .../{ => es5.1}/regression-test-issue-1641.js | 0 .../regression-test-issue-3151-function.js | 0 .../jerry/es5.1/regression-test-issue-3637.js | 24 + .../{ => es5.1}/regression-test-issue-787.js | 0 tests/jerry/es5.1/string-prototype-split.js | 23 + tests/jerry/es5.1/string-regexp-methods.js | 20 + tests/jerry/es5.1/try-catch.js | 26 + tests/jerry/eval-with.js | 53 + tests/jerry/eval.js | 37 + tests/jerry/fail/module-032.js | 17 + tests/jerry/fail/module-033.js | 17 + tests/jerry/fail/module-034.js | 17 + tests/jerry/fail/module-035.js | 17 + .../{ => fail}/regression-test-issue-1387.js | 0 .../regression-test-issue-2819.js | 0 ...-3121.js => regression-test-issue-3121.js} | 0 .../regression-test-issue-3123.js | 0 ...-3145.js => regression-test-issue-3145.js} | 0 ...-3152.js => regression-test-issue-3152.js} | 0 .../fail/regression-test-issue-3253-1.js | 16 + .../fail/regression-test-issue-3253-2.js | 16 + .../jerry/fail/regression-test-issue-3275.js | 15 + .../jerry/fail/regression-test-issue-3276.js | 15 + .../jerry/fail/regression-test-issue-3297.js | 15 + .../jerry/fail/regression-test-issue-3299.js | 27 + .../jerry/fail/regression-test-issue-3300.js | 23 + .../jerry/fail/regression-test-issue-3394.js | 24 + .../jerry/fail/regression-test-issue-3398.js | 20 + .../jerry/fail/regression-test-issue-3410.js | 20 + .../jerry/fail/regression-test-issue-3554.js | 15 + .../jerry/fail/regression-test-issue-3714.js | 18 + .../jerry/fail/regression-test-issue-3735.js | 15 + .../jerry/fail/regression-test-issue-3882.js | 15 + tests/jerry/for-in.js | 8 + tests/jerry/func-decl.js | 2 +- tests/jerry/function-construct.js | 4 + tests/jerry/function-external.js | 9 - tests/jerry/getter-setter-this-value.js | 16 + tests/jerry/keyword.js | 47 + tests/jerry/large_literal.js | 34 + tests/jerry/math-functions-tonumber-rule.js | 33 + tests/jerry/math-round.js | 14 + tests/jerry/number-prototype-to-fixed.js | 32 + tests/jerry/object-defineproperty.js | 9 + tests/jerry/object-get-own-property-names.js | 8 - tests/jerry/object-is-extensible.js | 17 - tests/jerry/object-keys.js | 8 - tests/jerry/regexp-alternatives.js | 3 + tests/jerry/regexp-backreference.js | 3 + tests/jerry/regexp-backtrack.js | 115 + tests/jerry/regexp-capture-groups.js | 9 + tests/jerry/regexp-construct.js | 32 - tests/jerry/regexp-routines.js | 9 - .../regexp-simple-atom-and-iterations.js | 3 + tests/jerry/regexp-web-compatibility.js | 193 + tests/jerry/regression-test-issue-1555.js | 2 +- tests/jerry/regression-test-issue-2105.js | 2 +- tests/jerry/regression-test-issue-2190.js | 2 +- tests/jerry/regression-test-issue-3229.js | 33 + tests/jerry/regression-test-issue-3271.js | 42 + tests/jerry/regression-test-issue-3313.js | 20 + tests/jerry/regression-test-issue-3325.js | 23 + tests/jerry/regression-test-issue-3397.js | 18 + tests/jerry/regression-test-issue-3467.js | 15 + tests/jerry/regression-test-issue-3477.js | 28 + tests/jerry/regression-test-issue-3523.js | 19 + tests/jerry/regression-test-issue-3532.js | 23 + tests/jerry/regression-test-issue-3553.js | 22 + tests/jerry/regression-test-issue-3608.js | 22 + tests/jerry/regression-test-issue-3648.js | 23 + tests/jerry/regression-test-issue-3650.js | 17 + tests/jerry/regression-test-issue-3711.js | 42 + .../jerry/regression-test-issue-3748-3749.js | 19 + tests/jerry/regression-test-issue-3761.js | 16 + tests/jerry/regression-test-issue-3778.js | 15 + tests/jerry/regression-test-issue-3779.js | 32 + tests/jerry/regression-test-issue-3813.js | 23 + tests/jerry/regression-test-issue-3815.js | 22 + tests/jerry/regression-test-issue-3821.js | 35 + tests/jerry/regression-test-issue-3878.js | 21 + tests/jerry/regression-test-issue-736.js | 10 +- tests/jerry/strict2.js | 82 + tests/jerry/string-prototype-charat.js | 12 +- tests/jerry/string-prototype-charcodeat.js | 12 +- tests/jerry/string-prototype-concat.js | 12 +- tests/jerry/string-prototype-indexof.js | 12 +- tests/jerry/string-prototype-lastindexof.js | 12 +- tests/jerry/string-prototype-match.js | 12 +- tests/jerry/string-prototype-replace.js | 25 +- tests/jerry/string-prototype-search.js | 19 - tests/jerry/string-prototype-split.js | 9 - tests/jerry/string-prototype-substr.js | 12 +- tests/jerry/string-prototype-substring.js | 12 +- tests/jerry/string-prototype-trim.js | 14 +- tests/jerry/try-eval.js | 31 + .../unicode-format-control-characters.js | 31 + tests/jerry/windows-line-ending.js | 44 +- tests/test262-es6-excludelist.xml | 596 +++ .../test-api-binary-operations-arithmetics.c | 290 ++ tests/unit-core/test-api-errortype.c | 12 + tests/unit-core/test-api-promise.c | 205 + tests/unit-core/test-api-property.c | 34 +- tests/unit-core/test-api-strings.c | 2 +- tests/unit-core/test-api.c | 93 +- tests/unit-core/test-arraybuffer.c | 71 +- tests/unit-core/test-common.h | 3 +- tests/unit-core/test-container.c | 86 + tests/unit-core/test-context-data.c | 2 - tests/unit-core/test-internal-properties.c | 240 + tests/unit-core/test-lit-char-helpers.c | 82 +- tests/unit-core/test-mem-stats.c | 1 - tests/unit-core/test-native-callback-nested.c | 68 + tests/unit-core/test-native-instanceof.c | 86 + tests/unit-core/test-newtarget.c | 213 + tests/unit-core/test-objects-foreach.c | 122 + tests/unit-core/test-promise.c | 1 - tests/unit-core/test-proxy.c | 250 ++ tests/unit-core/test-regression-3588.c | 107 + tests/unit-core/test-resource-name.c | 126 + tests/unit-core/test-snapshot.c | 63 +- tests/unit-core/test-stringbuilder.c | 1 - tests/unit-core/test-strings.c | 10 +- tests/unit-core/test-to-integer.c | 4 +- tests/unit-core/test-to-length.c | 2 +- tests/unit-core/test-typedarray.c | 81 +- tests/unit-core/test-unicode.c | 61 + tests/unit-ext/test-ext-arg.c | 4 +- tests/unit-ext/test-ext-method-register.c | 1 - tests/unit-libm/test-libm.inc.h | 329 ++ tools/apt-get-install-deps.sh | 8 +- tools/apt-get-install-qemu-arm.sh | 8 +- tools/babel/README.md | 11 +- tools/build.py | 5 + tools/check-cppcheck.sh | 1 + tools/cppcheck/suppressions-list | 7 +- tools/gen-magic-strings.py | 2 - tools/gen-unicode.py | 10 +- tools/pylint/pylintrc | 2 +- tools/run-tests.py | 79 +- tools/runners/run-test-suite-test262.py | 126 +- tools/runners/run-test-suite.py | 214 + tools/runners/run-test-suite.sh | 227 - tools/runners/run-unittests.py | 29 +- tools/runners/util.py | 67 + tools/settings.py | 3 +- tools/unit-tests/gen-test-libm.c | 351 ++ tools/vera++/profiles/jerry | 2 + .../jerry_no_consecutive_empty_lines.tcl | 36 + ...erry_no_leading_or_trailing_empty_line.tcl | 30 + .../jerry_typecast_space_parentheses.tcl | 2 +- 810 files changed, 67456 insertions(+), 19128 deletions(-) create mode 100644 cmake/toolchain_linux_aarch64.cmake create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-object.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-reflect.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h create mode 100644 jerry-core/ecma/operations/ecma-proxy-object.c create mode 100644 jerry-core/ecma/operations/ecma-proxy-object.h create mode 100644 jerry-core/parser/js/js-parser-tagged-template-literal.c create mode 100644 jerry-core/parser/js/js-parser-tagged-template-literal.h create mode 100644 jerry-core/parser/js/js-scanner-ops.c create mode 100644 jerry-core/parser/regexp/re-compiler-context.h create mode 100644 jerry-core/parser/regexp/re-token.h create mode 100644 jerry-ext/handler/handler-resource-name.c create mode 100644 jerry-libm/acosh.c create mode 100644 jerry-libm/asinh.c create mode 100644 jerry-libm/atanh.c create mode 100644 jerry-libm/cbrt.c create mode 100644 jerry-libm/cosh.c create mode 100644 jerry-libm/expm1.c create mode 100644 jerry-libm/log10.c create mode 100644 jerry-libm/log1p.c create mode 100644 jerry-libm/log2.c create mode 100644 jerry-libm/sinh.c create mode 100644 jerry-libm/tanh.c create mode 100644 tests/.gitattributes create mode 100644 tests/debugger/do_scope.cmd create mode 100644 tests/debugger/do_scope.expected rename tests/debugger/{do_scopes.js => do_scope.js} (100%) delete mode 100644 tests/debugger/do_scopes.cmd delete mode 100644 tests/debugger/do_scopes.expected create mode 100644 tests/jerry-test-suite/es2015/15.03.04.02-001.js create mode 100644 tests/jerry-test-suite/es2015/15.03.04.02-004.js rename tests/jerry-test-suite/{13/13.02 => es5.1}/13.02-002.js (100%) rename tests/jerry-test-suite/{15/15.03/15.03.04/15.03.04.02 => es5.1}/15.03.04.02-001.js (100%) rename tests/jerry-test-suite/{15/15.03/15.03.04/15.03.04.02 => es5.1}/15.03.04.02-004.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.03/15.07.03.01 => es5.1}/15.07.03.01-004.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.03/15.07.03.01 => es5.1}/15.07.03.01-008.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.03/15.07.03.01 => es5.1}/15.07.03.01-009.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.03/15.07.03.01 => es5.1}/15.07.03.01-010.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.03/15.07.03.01 => es5.1}/15.07.03.01-011.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04 => es5.1}/15.07.04-001.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04 => es5.1}/15.07.04-002.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.02 => es5.1}/15.07.04.02-006.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.02 => es5.1}/15.07.04.02-008.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-001.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-002.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-003.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-004.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-005.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-006.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-007.js (100%) rename tests/jerry-test-suite/{15/15.07/15.07.04/15.07.04.05 => es5.1}/15.07.04.05-008.js (100%) delete mode 100644 tests/jerry-test-suite/es51-profile-list create mode 100644 tests/jerry/es2015/argument-spread.js create mode 100644 tests/jerry/es2015/arguments-iterator.js create mode 100644 tests/jerry/es2015/array-from.js create mode 100644 tests/jerry/es2015/array-isarray.js create mode 100644 tests/jerry/es2015/array-new-target-support.js create mode 100644 tests/jerry/es2015/array-of.js create mode 100644 tests/jerry/es2015/array-pattern.js create mode 100644 tests/jerry/es2015/array-prototype-copywithin.js create mode 100644 tests/jerry/es2015/array-prototype-fill.js create mode 100644 tests/jerry/es2015/array-prototype-slice.js create mode 100644 tests/jerry/es2015/array-species.js create mode 100644 tests/jerry/es2015/array-spread.js create mode 100644 tests/jerry/es2015/arraybuffer-isview.js create mode 100644 tests/jerry/es2015/arrow-assignment.js create mode 100644 tests/jerry/es2015/arrow-eval.js create mode 100644 tests/jerry/es2015/binary-literal.js create mode 100644 tests/jerry/es2015/builtin-objects-accessor-property-configurable.js create mode 100644 tests/jerry/es2015/builtin-prototypes.js create mode 100644 tests/jerry/es2015/const1.js create mode 100644 tests/jerry/es2015/continue.js create mode 100644 tests/jerry/es2015/date-prototype-toprimitive.js create mode 100644 tests/jerry/es2015/directive.js create mode 100644 tests/jerry/es2015/error.js create mode 100644 tests/jerry/es2015/exponentiation.js create mode 100644 tests/jerry/es2015/for-let-reference-error.js create mode 100644 tests/jerry/es2015/for-let.js create mode 100644 tests/jerry/es2015/for-of-iterator-close.js create mode 100644 tests/jerry/es2015/for-pattern.js create mode 100644 tests/jerry/es2015/forin-header-strict.js create mode 100644 tests/jerry/es2015/function-accessor.js create mode 100644 tests/jerry/es2015/function-arguments-caller.js create mode 100644 tests/jerry/es2015/function-async1.js create mode 100644 tests/jerry/es2015/function-async2.js create mode 100644 tests/jerry/es2015/function-await1.js create mode 100644 tests/jerry/es2015/function-call.js create mode 100644 tests/jerry/es2015/function-if.js create mode 100644 tests/jerry/es2015/function-name.js create mode 100644 tests/jerry/es2015/function-new-target.js create mode 100644 tests/jerry/es2015/function-param-init2.js create mode 100644 tests/jerry/es2015/function-param-init3.js create mode 100644 tests/jerry/es2015/function-param-init4.js create mode 100644 tests/jerry/es2015/function-pattern1.js create mode 100644 tests/jerry/es2015/function-pattern2.js create mode 100644 tests/jerry/es2015/function-prototype-bind.js create mode 100644 tests/jerry/es2015/function-prototype-hasinstance-class.js create mode 100644 tests/jerry/es2015/function-prototype-hasinstance.js create mode 100644 tests/jerry/es2015/function-scope.js create mode 100644 tests/jerry/es2015/function-scope2.js create mode 100644 tests/jerry/es2015/generator-function.js create mode 100644 tests/jerry/es2015/generator-initializer.js create mode 100644 tests/jerry/es2015/generator-return.js create mode 100644 tests/jerry/es2015/generator-throw.js create mode 100644 tests/jerry/es2015/generator-yield-iterator.js create mode 100644 tests/jerry/es2015/generator-yield.js create mode 100644 tests/jerry/es2015/generator.js create mode 100644 tests/jerry/es2015/identifier-escape.js create mode 100644 tests/jerry/es2015/instanceof-symbol-hasinstance-class.js create mode 100644 tests/jerry/es2015/instanceof-symbol-hasinstance.js create mode 100644 tests/jerry/es2015/json-stringify.js create mode 100644 tests/jerry/es2015/length-property.js create mode 100644 tests/jerry/es2015/let1.js create mode 100644 tests/jerry/es2015/let10.js create mode 100644 tests/jerry/es2015/let11.js create mode 100644 tests/jerry/es2015/let12.js create mode 100644 tests/jerry/es2015/let13.js create mode 100644 tests/jerry/es2015/let14.js create mode 100644 tests/jerry/es2015/let15.js create mode 100644 tests/jerry/es2015/let2.js create mode 100644 tests/jerry/es2015/let3.js create mode 100644 tests/jerry/es2015/let4.js create mode 100644 tests/jerry/es2015/let5.js create mode 100644 tests/jerry/es2015/let6.js create mode 100644 tests/jerry/es2015/let7.js create mode 100644 tests/jerry/es2015/let8.js create mode 100644 tests/jerry/es2015/let9.js create mode 100644 tests/jerry/es2015/math-acosh.js create mode 100644 tests/jerry/es2015/math-asinh.js create mode 100644 tests/jerry/es2015/math-atanh.js create mode 100644 tests/jerry/es2015/math-cbrt.js create mode 100644 tests/jerry/es2015/math-cosh.js create mode 100644 tests/jerry/es2015/math-expm1.js create mode 100644 tests/jerry/es2015/math-functions-tonumber-rule2.js create mode 100644 tests/jerry/es2015/math-log10.js create mode 100644 tests/jerry/es2015/math-log1p.js create mode 100644 tests/jerry/es2015/math-log2.js create mode 100644 tests/jerry/es2015/math-sinh.js create mode 100644 tests/jerry/es2015/math-tanh.js create mode 100644 tests/jerry/es2015/module-export-fail-test.js create mode 100644 tests/jerry/es2015/new-target-async.js create mode 100644 tests/jerry/es2015/new-target-class.js create mode 100644 tests/jerry/es2015/new-target-for-containers.js create mode 100644 tests/jerry/es2015/new-target-for-date-object.js create mode 100644 tests/jerry/es2015/new-target-generator.js create mode 100644 tests/jerry/es2015/new-target.js create mode 100644 tests/jerry/es2015/number-constants.js create mode 100644 tests/jerry/es2015/number-methods.js create mode 100644 tests/jerry/es2015/object-freeze-with-symbol.js create mode 100644 tests/jerry/es2015/object-get-own-property-names.js create mode 100644 tests/jerry/es2015/object-is.js create mode 100644 tests/jerry/es2015/object-methods.js create mode 100644 tests/jerry/es2015/object-pattern.js create mode 100644 tests/jerry/es2015/object-prototype-proto.js create mode 100644 tests/jerry/es2015/object-seal-with-symbol.js create mode 100644 tests/jerry/es2015/octal-literal.js create mode 100644 tests/jerry/es2015/promise-all-iterator.js create mode 100644 tests/jerry/es2015/promise-new-target.js create mode 100644 tests/jerry/es2015/promise-race-iterator.js create mode 100644 tests/jerry/es2015/promise-species.js create mode 100644 tests/jerry/es2015/promise-thenable.js create mode 100644 tests/jerry/es2015/proxy_call.js create mode 100644 tests/jerry/es2015/proxy_construct.js create mode 100644 tests/jerry/es2015/proxy_create.js create mode 100644 tests/jerry/es2015/proxy_define_own_property.js create mode 100644 tests/jerry/es2015/proxy_delete.js create mode 100644 tests/jerry/es2015/proxy_get.js create mode 100644 tests/jerry/es2015/proxy_get_own_property_descriptor.js create mode 100644 tests/jerry/es2015/proxy_get_prototoype_of.js create mode 100644 tests/jerry/es2015/proxy_has.js create mode 100644 tests/jerry/es2015/proxy_is_extensible.js create mode 100644 tests/jerry/es2015/proxy_own_keys.js create mode 100644 tests/jerry/es2015/proxy_prevent_extensions.js create mode 100644 tests/jerry/es2015/proxy_revocable.js create mode 100644 tests/jerry/es2015/proxy_set.js create mode 100644 tests/jerry/es2015/proxy_set_apply_receiver.js create mode 100644 tests/jerry/es2015/proxy_set_prototoype_of.js create mode 100644 tests/jerry/es2015/reflect-apply.js create mode 100644 tests/jerry/es2015/reflect-construct.js create mode 100644 tests/jerry/es2015/reflect-define-Property.js create mode 100644 tests/jerry/es2015/reflect-deleteproperty.js create mode 100644 tests/jerry/es2015/reflect-get-own-property-description.js create mode 100644 tests/jerry/es2015/reflect-get.js create mode 100644 tests/jerry/es2015/reflect-getPrototypeOf.js create mode 100644 tests/jerry/es2015/reflect-has.js create mode 100644 tests/jerry/es2015/reflect-isextensible.js create mode 100644 tests/jerry/es2015/reflect-own-keys.js create mode 100644 tests/jerry/es2015/reflect-preventextensions.js create mode 100644 tests/jerry/es2015/reflect-set.js create mode 100644 tests/jerry/es2015/reflect-setPrototypeOf.js create mode 100644 tests/jerry/es2015/regexp-accessors-descriptors.js create mode 100644 tests/jerry/es2015/regexp-construct.js create mode 100644 tests/jerry/es2015/regexp-flags.js create mode 100644 tests/jerry/es2015/regexp-new-target.js create mode 100644 tests/jerry/es2015/regexp-prototype-match.js create mode 100644 tests/jerry/es2015/regexp-prototype-source.js create mode 100644 tests/jerry/es2015/regexp-prototype-test.js create mode 100644 tests/jerry/es2015/regexp-routines.js create mode 100644 tests/jerry/es2015/regexp-unicode.js rename tests/jerry/{fail => es2015}/regression-test-issue-2544.js (79%) create mode 100644 tests/jerry/es2015/regression-test-issue-2891.js create mode 100644 tests/jerry/es2015/regression-test-issue-3070.js create mode 100644 tests/jerry/es2015/regression-test-issue-3222.js create mode 100644 tests/jerry/es2015/regression-test-issue-3237.js create mode 100644 tests/jerry/es2015/regression-test-issue-3243.js create mode 100644 tests/jerry/es2015/regression-test-issue-3250.js create mode 100644 tests/jerry/es2015/regression-test-issue-3252.js create mode 100644 tests/jerry/es2015/regression-test-issue-3262.js create mode 100644 tests/jerry/es2015/regression-test-issue-3267.js create mode 100644 tests/jerry/es2015/regression-test-issue-3298.js create mode 100644 tests/jerry/es2015/regression-test-issue-3306.js create mode 100644 tests/jerry/es2015/regression-test-issue-3348.js rename tests/jerry/es2015/{regression-test-issue-3151-class.js => regression-test-issue-3355.js} (96%) create mode 100644 tests/jerry/es2015/regression-test-issue-3356.js create mode 100644 tests/jerry/es2015/regression-test-issue-3360.js create mode 100644 tests/jerry/es2015/regression-test-issue-3361.js create mode 100644 tests/jerry/es2015/regression-test-issue-3363.js create mode 100644 tests/jerry/es2015/regression-test-issue-3364.js create mode 100644 tests/jerry/es2015/regression-test-issue-3376.js create mode 100644 tests/jerry/es2015/regression-test-issue-3381.js create mode 100644 tests/jerry/es2015/regression-test-issue-3383.js create mode 100644 tests/jerry/es2015/regression-test-issue-3390.js create mode 100644 tests/jerry/es2015/regression-test-issue-3396.js create mode 100644 tests/jerry/es2015/regression-test-issue-3408.js create mode 100644 tests/jerry/es2015/regression-test-issue-3409.js create mode 100644 tests/jerry/es2015/regression-test-issue-3411.js create mode 100644 tests/jerry/es2015/regression-test-issue-3419.js create mode 100644 tests/jerry/es2015/regression-test-issue-3420.js create mode 100644 tests/jerry/es2015/regression-test-issue-3421.js create mode 100644 tests/jerry/es2015/regression-test-issue-3422.js create mode 100644 tests/jerry/es2015/regression-test-issue-3431.js create mode 100644 tests/jerry/es2015/regression-test-issue-3434.js create mode 100644 tests/jerry/es2015/regression-test-issue-3437.js create mode 100644 tests/jerry/es2015/regression-test-issue-3454.js create mode 100644 tests/jerry/es2015/regression-test-issue-3455.js create mode 100644 tests/jerry/es2015/regression-test-issue-3458.js create mode 100644 tests/jerry/es2015/regression-test-issue-3459.js create mode 100644 tests/jerry/es2015/regression-test-issue-3478.js create mode 100644 tests/jerry/es2015/regression-test-issue-3479.js create mode 100644 tests/jerry/es2015/regression-test-issue-3483.js create mode 100644 tests/jerry/es2015/regression-test-issue-3485.js create mode 100644 tests/jerry/es2015/regression-test-issue-3519.js create mode 100644 tests/jerry/es2015/regression-test-issue-3527.js create mode 100644 tests/jerry/es2015/regression-test-issue-3534.js create mode 100644 tests/jerry/es2015/regression-test-issue-3536.js create mode 100644 tests/jerry/es2015/regression-test-issue-3580.js create mode 100644 tests/jerry/es2015/regression-test-issue-3588.js create mode 100644 tests/jerry/es2015/regression-test-issue-3589.js create mode 100644 tests/jerry/es2015/regression-test-issue-3595.js create mode 100644 tests/jerry/es2015/regression-test-issue-3606.js create mode 100644 tests/jerry/es2015/regression-test-issue-3611.js create mode 100644 tests/jerry/es2015/regression-test-issue-3625.js create mode 100644 tests/jerry/es2015/regression-test-issue-3628.js create mode 100644 tests/jerry/es2015/regression-test-issue-3630.js create mode 100644 tests/jerry/es2015/regression-test-issue-3636.js create mode 100644 tests/jerry/es2015/regression-test-issue-3637.js create mode 100644 tests/jerry/es2015/regression-test-issue-3640.js create mode 100644 tests/jerry/es2015/regression-test-issue-3641.js create mode 100644 tests/jerry/es2015/regression-test-issue-3647.js create mode 100644 tests/jerry/es2015/regression-test-issue-3655.js create mode 100644 tests/jerry/es2015/regression-test-issue-3656.js create mode 100644 tests/jerry/es2015/regression-test-issue-3658.js create mode 100644 tests/jerry/es2015/regression-test-issue-3665.js create mode 100644 tests/jerry/es2015/regression-test-issue-3671.js create mode 100644 tests/jerry/es2015/regression-test-issue-3715.js create mode 100644 tests/jerry/es2015/regression-test-issue-3751.js create mode 100644 tests/jerry/es2015/regression-test-issue-3760.js create mode 100644 tests/jerry/es2015/regression-test-issue-3784.js create mode 100644 tests/jerry/es2015/regression-test-issue-3785.js create mode 100644 tests/jerry/es2015/regression-test-issue-3787.js create mode 100644 tests/jerry/es2015/regression-test-issue-3812.js create mode 100644 tests/jerry/es2015/regression-test-issue-3814.js create mode 100644 tests/jerry/es2015/regression-test-issue-3817.js create mode 100644 tests/jerry/es2015/regression-test-issue-3819.js create mode 100644 tests/jerry/es2015/regression-test-issue-3820.js create mode 100644 tests/jerry/es2015/regression-test-issue-3822.js create mode 100644 tests/jerry/es2015/regression-test-issue-3823.js create mode 100644 tests/jerry/es2015/regression-test-issue-3824.js create mode 100644 tests/jerry/es2015/regression-test-issue-3825.js create mode 100644 tests/jerry/es2015/regression-test-issue-3836.js create mode 100644 tests/jerry/es2015/regression-test-issue-3837.js create mode 100644 tests/jerry/es2015/regression-test-issue-3845.js create mode 100644 tests/jerry/es2015/regression-test-issue-3849.js create mode 100644 tests/jerry/es2015/regression-test-issue-3860.js create mode 100644 tests/jerry/es2015/regression-test-issue-3861.js create mode 100644 tests/jerry/es2015/regression-test-issue-3862.js create mode 100644 tests/jerry/es2015/regression-test-issue-3866.js create mode 100644 tests/jerry/es2015/regression-test-issue-3868.js create mode 100644 tests/jerry/es2015/regression-test-issue-3870.js create mode 100644 tests/jerry/es2015/regression-test-issue-3871.js create mode 100644 tests/jerry/es2015/regression-test-issue-3880.js create mode 100644 tests/jerry/es2015/regression-test-issue-3893.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3302.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3395.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3713.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3727.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3841.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3842.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3856.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3857.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3869.js create mode 100644 tests/jerry/es2015/regresssion-test-issue-3888.js create mode 100644 tests/jerry/es2015/string-fromcodepoint.js create mode 100644 tests/jerry/es2015/string-prototype-codepointat.js create mode 100644 tests/jerry/es2015/string-prototype-match.js create mode 100644 tests/jerry/es2015/string-prototype-split.js create mode 100644 tests/jerry/es2015/string-raw-crash-escaping-backslash.js create mode 100644 tests/jerry/es2015/string-raw.js create mode 100644 tests/jerry/es2015/super-assignment.js create mode 100644 tests/jerry/es2015/symbol-isconcatspreadable.js create mode 100644 tests/jerry/es2015/symbol-prototype.toprimitive.js create mode 100644 tests/jerry/es2015/symbol-replace.js create mode 100644 tests/jerry/es2015/symbol-search.js create mode 100644 tests/jerry/es2015/symbol-split.js create mode 100644 tests/jerry/es2015/symbol-unscopables.js create mode 100644 tests/jerry/es2015/tagged-template-literal.js create mode 100644 tests/jerry/es2015/to-number-string.js create mode 100644 tests/jerry/es2015/try-catch.js create mode 100644 tests/jerry/es2015/try-pattern.js create mode 100644 tests/jerry/es2015/typedarray-from.js create mode 100644 tests/jerry/es2015/typedarray-of.js create mode 100644 tests/jerry/es2015/weakmap.js create mode 100644 tests/jerry/es2015/weakset.js create mode 100644 tests/jerry/es5.1/array-prototype-push.js create mode 100644 tests/jerry/es5.1/builtin-prototypes.js create mode 100644 tests/jerry/es5.1/func-decl.js rename tests/{jerry-test-suite/15/15.03/15.03.03/15.03.03.02/15.03.03.02-001.js => jerry/es5.1/func-length.js} (95%) create mode 100644 tests/jerry/es5.1/object-methods.js create mode 100644 tests/jerry/es5.1/regexp-construct.js create mode 100644 tests/jerry/es5.1/regexp-routines.js rename tests/jerry/{ => es5.1}/regression-test-issue-1065.js (100%) rename tests/jerry/{ => es5.1}/regression-test-issue-1080.js (100%) rename tests/jerry/{ => es5.1}/regression-test-issue-1546.js (100%) rename tests/jerry/{ => es5.1}/regression-test-issue-1641.js (100%) rename tests/jerry/{ => es5.1}/regression-test-issue-3151-function.js (100%) create mode 100644 tests/jerry/es5.1/regression-test-issue-3637.js rename tests/jerry/{ => es5.1}/regression-test-issue-787.js (100%) create mode 100644 tests/jerry/es5.1/string-prototype-split.js create mode 100644 tests/jerry/es5.1/string-regexp-methods.js create mode 100644 tests/jerry/es5.1/try-catch.js create mode 100644 tests/jerry/eval-with.js create mode 100644 tests/jerry/fail/module-032.js create mode 100644 tests/jerry/fail/module-033.js create mode 100644 tests/jerry/fail/module-034.js create mode 100644 tests/jerry/fail/module-035.js rename tests/jerry/{ => fail}/regression-test-issue-1387.js (100%) rename tests/jerry/{es2015 => fail}/regression-test-issue-2819.js (100%) rename tests/jerry/fail/{regresssion-test-issue-3121.js => regression-test-issue-3121.js} (100%) rename tests/jerry/{es2015 => fail}/regression-test-issue-3123.js (100%) rename tests/jerry/fail/{regresssion-test-issue-3145.js => regression-test-issue-3145.js} (100%) rename tests/jerry/fail/{regresssion-test-issue-3152.js => regression-test-issue-3152.js} (100%) create mode 100644 tests/jerry/fail/regression-test-issue-3253-1.js create mode 100644 tests/jerry/fail/regression-test-issue-3253-2.js create mode 100644 tests/jerry/fail/regression-test-issue-3275.js create mode 100644 tests/jerry/fail/regression-test-issue-3276.js create mode 100644 tests/jerry/fail/regression-test-issue-3297.js create mode 100644 tests/jerry/fail/regression-test-issue-3299.js create mode 100644 tests/jerry/fail/regression-test-issue-3300.js create mode 100644 tests/jerry/fail/regression-test-issue-3394.js create mode 100644 tests/jerry/fail/regression-test-issue-3398.js create mode 100644 tests/jerry/fail/regression-test-issue-3410.js create mode 100644 tests/jerry/fail/regression-test-issue-3554.js create mode 100644 tests/jerry/fail/regression-test-issue-3714.js create mode 100644 tests/jerry/fail/regression-test-issue-3735.js create mode 100644 tests/jerry/fail/regression-test-issue-3882.js create mode 100644 tests/jerry/keyword.js create mode 100644 tests/jerry/large_literal.js create mode 100644 tests/jerry/math-functions-tonumber-rule.js create mode 100644 tests/jerry/regexp-backtrack.js create mode 100644 tests/jerry/regexp-web-compatibility.js create mode 100644 tests/jerry/regression-test-issue-3229.js create mode 100644 tests/jerry/regression-test-issue-3271.js create mode 100644 tests/jerry/regression-test-issue-3313.js create mode 100644 tests/jerry/regression-test-issue-3325.js create mode 100644 tests/jerry/regression-test-issue-3397.js create mode 100644 tests/jerry/regression-test-issue-3467.js create mode 100644 tests/jerry/regression-test-issue-3477.js create mode 100644 tests/jerry/regression-test-issue-3523.js create mode 100644 tests/jerry/regression-test-issue-3532.js create mode 100644 tests/jerry/regression-test-issue-3553.js create mode 100644 tests/jerry/regression-test-issue-3608.js create mode 100644 tests/jerry/regression-test-issue-3648.js create mode 100644 tests/jerry/regression-test-issue-3650.js create mode 100644 tests/jerry/regression-test-issue-3711.js create mode 100644 tests/jerry/regression-test-issue-3748-3749.js create mode 100644 tests/jerry/regression-test-issue-3761.js create mode 100644 tests/jerry/regression-test-issue-3778.js create mode 100644 tests/jerry/regression-test-issue-3779.js create mode 100644 tests/jerry/regression-test-issue-3813.js create mode 100644 tests/jerry/regression-test-issue-3815.js create mode 100644 tests/jerry/regression-test-issue-3821.js create mode 100644 tests/jerry/regression-test-issue-3878.js create mode 100644 tests/jerry/strict2.js create mode 100644 tests/jerry/try-eval.js create mode 100644 tests/jerry/unicode-format-control-characters.js create mode 100644 tests/test262-es6-excludelist.xml create mode 100644 tests/unit-core/test-api-binary-operations-arithmetics.c create mode 100644 tests/unit-core/test-api-promise.c create mode 100644 tests/unit-core/test-container.c create mode 100644 tests/unit-core/test-internal-properties.c create mode 100644 tests/unit-core/test-native-callback-nested.c create mode 100644 tests/unit-core/test-native-instanceof.c create mode 100644 tests/unit-core/test-newtarget.c create mode 100644 tests/unit-core/test-proxy.c create mode 100644 tests/unit-core/test-regression-3588.c create mode 100644 tests/unit-core/test-resource-name.c create mode 100644 tests/unit-core/test-unicode.c create mode 100644 tools/runners/run-test-suite.py delete mode 100755 tools/runners/run-test-suite.sh create mode 100644 tools/runners/util.py create mode 100644 tools/vera++/scripts/rules/jerry_no_consecutive_empty_lines.tcl create mode 100644 tools/vera++/scripts/rules/jerry_no_leading_or_trailing_empty_line.tcl diff --git a/.travis.yml b/.travis.yml index a7674e0d..e40b3c20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: c -# Default environment: Ubuntu Trusty 14.04. +# Default environment: Ubuntu Bionic 18.04. os: linux -dist: trusty +dist: bionic # Default job task: run tests as defined in the $OPT environment variable. # Jobs can redefine the 'script' stage in the matrix below. @@ -12,13 +12,12 @@ script: tools/run-tests.py $OPTS matrix: include: - name: "Checks" - install: pip install --user pylint==1.6.5 script: - tools/run-tests.py --check-signed-off=travis --check-doxygen --check-vera --check-license --check-magic-strings --check-pylint - travis_wait 40 tools/run-tests.py --check-cppcheck addons: apt: - packages: [doxygen, cppcheck, vera++] + packages: [doxygen, cppcheck, vera++, pylint] - name: "Linux/x86-64 Build, Correctness & Debugger Tests" env: @@ -40,10 +39,17 @@ matrix: apt: packages: [gcc-arm-linux-gnueabihf, libc6-dev-armhf-cross, qemu-user-static] + - name: "Linux/AArch64 Native Build & Correctness Tests" + arch: arm64 + env: + - OPTS="--quiet --jerry-tests --jerry-test-suite --buildoptions=--linker-flag=-static" + - TIMEOUT=300 + - name: "OSX/x86-64 Build, Correctness & Unit Tests" env: - OPTS="--quiet --jerry-tests --jerry-test-suite --unittests" os: osx + osx_image: xcode11.4 addons: homebrew: packages: [cmake, cppcheck, vera++] @@ -55,10 +61,14 @@ matrix: apt: packages: [gcc-multilib] - - name: "Conformance Tests" + - name: "Conformance Tests - ES5.1" env: - OPTS="--test262" + - name: "Conformance Tests - ES2015" + env: + - OPTS="--test262-es2015" + - name: "Unit Tests" env: - OPTS="--unittests" @@ -67,25 +77,23 @@ matrix: env: # Skipping maximum stack usage related tests due to 'detect_stack_use_after_return=1' ASAN option. # For more detailed description: https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#compatibility - - OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js --buildoptions=--stack-limit=0,--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold" + - OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js --buildoptions=--stack-limit=0,--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold" - ASAN_OPTIONS=detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true - TIMEOUT=600 - compiler: gcc-5 addons: apt: sources: ubuntu-toolchain-r-test - packages: [gcc-5, gcc-5-multilib] + packages: [gcc-multilib] - name: "UBSAN Tests" env: - OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js,parser-oom2.js --buildoptions=--compile-flag=-fsanitize=undefined,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold" - UBSAN_OPTIONS=print_stacktrace=1 - TIMEOUT=600 - compiler: gcc-5 addons: apt: sources: ubuntu-toolchain-r-test - packages: [gcc-5, gcc-5-multilib] + packages: [gcc-multilib] - name: "Coverity Scan & SonarQube" env: @@ -120,11 +128,13 @@ matrix: script: make -f ./targets/mbedos5/Makefile.travis script - name: "Zephyr/Arduino 101 Build Test" + language: python # NOTE: only way to ensure python>=2.7.10 on Trusty image + python: 3.6 install: make -f ./targets/zephyr/Makefile.travis install-noapt script: make -f ./targets/zephyr/Makefile.travis script addons: apt: - packages: [gperf, dfu-util, device-tree-compiler, python3-ply, python3-pip] + packages: [gperf, dfu-util, device-tree-compiler] - name: "NuttX/STM32F4 Build Test" install: make -f targets/nuttx-stm32f4/Makefile.travis install-noapt diff --git a/BUILD.gn b/BUILD.gn index c94ef00d..d4f04489 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -92,6 +92,7 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/ecma/base/ecma-module.c", "jerry-core/ecma/base/ecma-property-hashmap.c", "jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c", "jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-array.c", "jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c", @@ -108,12 +109,16 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/ecma/builtin-objects/ecma-builtin-evalerror.c", "jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-function.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-generator.c", "jerry-core/ecma/builtin-objects/ecma-builtin-global.c", "jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c", "jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c", "jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c", "jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c", "jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.c", "jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-json.c", "jerry-core/ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c", @@ -126,10 +131,12 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/ecma/builtin-objects/ecma-builtin-object.c", "jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-promise.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c", "jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror.c", "jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c", "jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c", "jerry-core/ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c", @@ -147,6 +154,10 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/ecma/builtin-objects/ecma-builtin-typeerror.c", "jerry-core/ecma/builtin-objects/ecma-builtin-urierror-prototype.c", "jerry-core/ecma/builtin-objects/ecma-builtin-urierror.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c", + "jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c", "jerry-core/ecma/builtin-objects/ecma-builtins.c", "jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-float32array-prototype.c", "jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-float32array.c", @@ -189,6 +200,7 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/ecma/operations/ecma-objects-general.c", "jerry-core/ecma/operations/ecma-objects.c", "jerry-core/ecma/operations/ecma-promise-object.c", + "jerry-core/ecma/operations/ecma-proxy-object.c", "jerry-core/ecma/operations/ecma-reference.c", "jerry-core/ecma/operations/ecma-regexp-object.c", "jerry-core/ecma/operations/ecma-string-object.c", @@ -212,8 +224,10 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-core/parser/js/js-parser-mem.c", "jerry-core/parser/js/js-parser-module.c", "jerry-core/parser/js/js-parser-statm.c", + "jerry-core/parser/js/js-parser-tagged-template-literal.c", "jerry-core/parser/js/js-parser-util.c", "jerry-core/parser/js/js-parser.c", + "jerry-core/parser/js/js-scanner-ops.c", "jerry-core/parser/js/js-scanner-util.c", "jerry-core/parser/js/js-scanner.c", "jerry-core/parser/regexp/re-bytecode.c", @@ -264,6 +278,7 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera "jerry-ext/handler/handler-gc.c", "jerry-ext/handler/handler-print.c", "jerry-ext/handler/handler-register.c", + "jerry-ext/handler/handler-resource-name.c", "jerry-ext/module/module.c", ] jerry_ext_include_dirs = [ @@ -290,22 +305,33 @@ if (defined(ohos_lite)) { # is on lite Os for ipcamera jerry_libm_sources = [ "jerry-libm/acos.c", + "jerry-libm/acosh.c", "jerry-libm/asin.c", + "jerry-libm/asinh.c", "jerry-libm/atan.c", "jerry-libm/atan2.c", + "jerry-libm/atanh.c", + "jerry-libm/cbrt.c", "jerry-libm/ceil.c", "jerry-libm/copysign.c", + "jerry-libm/cosh.c", "jerry-libm/exp.c", + "jerry-libm/expm1.c", "jerry-libm/fabs.c", "jerry-libm/finite.c", "jerry-libm/floor.c", "jerry-libm/fmod.c", "jerry-libm/isnan.c", "jerry-libm/log.c", + "jerry-libm/log10.c", + "jerry-libm/log1p.c", + "jerry-libm/log2.c", "jerry-libm/nextafter.c", "jerry-libm/pow.c", "jerry-libm/scalbn.c", + "jerry-libm/sinh.c", "jerry-libm/sqrt.c", + "jerry-libm/tanh.c", "jerry-libm/trig.c", ] jerry_libm_include_dirs = [ "jerry-libm/include" ] diff --git a/Doxyfile b/Doxyfile index 725b3e33..70f57d95 100644 --- a/Doxyfile +++ b/Doxyfile @@ -798,7 +798,6 @@ RECURSIVE = YES # who are familiar with the undocumented parts. EXCLUDE = \ jerry-core/ecma/base/ecma-globals.h \ - jerry-core/ecma/base/ecma-helpers.h \ jerry-core/ecma/operations/ecma-exceptions.h \ jerry-core/include/jerryscript-debugger-transport.h \ jerry-core/jcontext/jcontext.h \ diff --git a/README.OpenSource b/README.OpenSource index cf976798..4e017443 100755 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name": "jerryscript", "License": "Apache-2.0", "License File": "LICENSE", - "Version Number": "v2.1.0", + "Version Number": "v2.3.0", "Owner": "pengbiao1@huawei.com", "Upstream URL": "https://github.com/jerryscript-project/jerryscript.git", "Description": "JerryScript is the lightweight JavaScript engine intended to run on a very constrained devices such as microcontrollers." diff --git a/README.md b/README.md index 43a59bad..e4530f1a 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,10 @@ Additional information can be found on our [project page](http://jerryscript.net Memory usage and Binary footprint are measured at [here](https://jerryscript-project.github.io/jerryscript-test-results) with real target daily. -The following table shows the latest results on the devices: +The latest results on **Raspberry Pi 2**: -| STM32F4-Discovery | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fjerryscript%2Fstm32f4dis.svg?alt=media&token=1)](https://jerryscript-project.github.io/jerryscript-test-results/?view=stm32f4dis) | -| :---: | :---: | -| **Raspberry Pi 2** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fjerryscript%2Frpi2.svg?alt=media&token=1)](https://jerryscript-project.github.io/jerryscript-test-results/?view=rpi2) | + +[![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fjerryscript%2Frpi2.svg?alt=media&token=1)](https://jerryscript-project.github.io/jerryscript-test-results/?view=rpi2) IRC channel: #jerryscript on [freenode](https://freenode.net) Mailing list: jerryscript-dev@groups.io, you can subscribe [here](https://groups.io/g/jerryscript-dev) and access the mailing list archive [here](https://groups.io/g/jerryscript-dev/topics). diff --git a/appveyor.yml b/appveyor.yml index 5c9d7464..2fb839a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,20 +17,16 @@ platform: environment: matrix: - - FEATURE_DEBUGGER: ON - - FEATURE_DEBUGGER: OFF + - JERRY_DEBUGGER: ON + - JERRY_DEBUGGER: OFF # Steps of a job. init: - cmake -version before_build: - - if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H. -DFEATURE_DEBUGGER=%FEATURE_DEBUGGER% - - if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H. -DFEATURE_DEBUGGER=%FEATURE_DEBUGGER% + - if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H. -DJERRY_DEBUGGER=%JERRY_DEBUGGER% + - if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H. -DJERRY_DEBUGGER=%JERRY_DEBUGGER% build: project: build\Jerry.sln parallel: true verbosity: minimal - -artifacts: - - path: build\bin\$(configuration)\ - name: JerryScriptBinary diff --git a/cmake/toolchain_linux_aarch64.cmake b/cmake/toolchain_linux_aarch64.cmake new file mode 100644 index 00000000..ef0894b0 --- /dev/null +++ b/cmake/toolchain_linux_aarch64.cmake @@ -0,0 +1,18 @@ +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) diff --git a/docs/00.GETTING-STARTED.md b/docs/00.GETTING-STARTED.md index d16d9b89..9ef07a4a 100644 --- a/docs/00.GETTING-STARTED.md +++ b/docs/00.GETTING-STARTED.md @@ -1,6 +1,6 @@ ## Setting up prerequisites -Currently, only Ubuntu 14.04+ is officially supported as primary development environment. +Currently, only Ubuntu 18.04+ is officially supported as primary development environment. There are several dependencies, that should be installed manually. The following list is the absolute minimum for building: diff --git a/docs/01.CONFIGURATION.md b/docs/01.CONFIGURATION.md index fc35e737..cef99932 100644 --- a/docs/01.CONFIGURATION.md +++ b/docs/01.CONFIGURATION.md @@ -211,6 +211,17 @@ A value of 0 will use the default value. | CMake: | `-DJERRY_GC_LIMIT=(int)` | | Python: | `--gc-limit=(int)` | +### GC mark recursion limit + +This option can be used to adjust the maximum recursion depth during the GC mark phase. The provided value should be an integer, which represents the allowed number of recursive calls. Increasing the depth of the recursion reduces the time of GC cycles, however increases stack usage. +A value of 0 will prevent any recursive GC calls. + +| Options | | +|---------|---------------------------------------------------| +| C: | `-DJERRY_GC_MARK_LIMIT=(int)` | +| CMake: | `-DJERRY_GC_MARK_LIMIT=(int)` | +| Python: | `--gc-mark-limit=(int)` | + ### Stack limit This option can be used to cap the stack usage of the engine, and prevent stack overflows due to recursion. The provided value should be an integer, which represents the allowed stack usage in kilobytes. @@ -296,9 +307,27 @@ These files can be directly compiled with an application using the JerryScript A For example with the following command: ```sh -$ gcc -Wall -o demo_app demo_app.c gen_src/jerryscript.c gen_src/jerryscript-port-default.c jerryscript-libm.c -Igen_src/ +$ gcc -Wall -o demo_app demo_app.c gen_src/jerryscript.c gen_src/jerryscript-port-default.c jerryscript-libm.c -Igen_src/ ``` Please note that the headers must be available on the include path. In addition there is a `-DENABLE_ALL_IN_ONE_SOURCE=ON` CMake option to use this kind of sources during the build. + +# Target specific information + +## x86 with GCC + +When building for Intel 32 bit architecture it is possible that GCC uses conservative options, thus assuming the most +basic floating-point support (that is it does not generate SSE or others instructions). +However this could lead to loss off precision and/or different results than what is required by the JavaScript standard +in regards of floating-point values and arithmetic. + +To resolve this precision problem it is advised to use at least SSE2. +To do this with GCC please provide the `-mfpmath=sse -msse2` options during build. + +These options can also be specified via the `build.py` script: + +```sh +$ ./tools/build.py --compile-flag=-mfpmath=sse --compile-flag=-msse2 --compile-flag=-m32 +``` diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 927da660..46d040b7 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -70,8 +70,26 @@ Possible compile time enabled feature types: - JERRY_FEATURE_LOGGING - logging - JERRY_FEATURE_SYMBOL - symbol support - JERRY_FEATURE_DATAVIEW - DataView support + - JERRY_FEATURE_PROXY - Proxy support + - JERRY_FEATURE_MAP - Map support + - JERRY_FEATURE_SET - Set support + - JERRY_FEATURE_WEAKMAP - WeakMap support + - JERRY_FEATURE_WEAKSET - WeakSet support *New in version 2.0*. +*Changed in version 2.3* : Added `JERRY_FEATURE_WEAKMAP`, `JERRY_FEATURE_WEAKSET` values. + +## jerry_container_type_t + +Container object types: + + - JERRY_CONTAINER_TYPE_INVALID - Invalid container + - JERRY_CONTAINER_TYPE_MAP - Map type + - JERRY_CONTAINER_TYPE_SET - Set type + - JERRY_CONTAINER_TYPE_WEAKMAP - WeakMap type + - JERRY_CONTAINER_TYPE_WEAKSET - WeakSet type + + *New in version 2.3*. ## jerry_regexp_flags_t @@ -316,6 +334,11 @@ Enum that contains the supported binary operation types - JERRY_BIN_OP_GREATER - greater relation (>) - JERRY_BIN_OP_GREATER_EQUAL - greater or equal relation (>=) - JERRY_BIN_OP_INSTANCEOF - instanceof operation + - JERRY_BIN_OP_ADD - addition operator (+) + - JERRY_BIN_OP_SUB - subtraction operator (-) + - JERRY_BIN_OP_MUL - multiplication operator (*) + - JERRY_BIN_OP_DIV - division operator (/) + - JERRY_BIN_OP_REM - remainder operator (%) *New in version 2.0*. @@ -442,7 +465,7 @@ typedef jerry_value_t (*jerry_external_handler_t) (const jerry_value_t function_ Native free callback of an object. It is used in `jerry_object_native_info_t` and for external Array buffers. *Note*: - - This callback method **must not** call any JerryScript API methods. + - Referred values by this method must have at least 1 reference. (Correct API usage satisfies this condition) **Prototype** @@ -451,6 +474,7 @@ typedef void (*jerry_object_native_free_callback_t) (void *native_p); ``` *New in version 2.0*: Renamed from `jerry_object_free_callback_t`. +*Changed in version 2.2*: API calls are once again allowed. (See note) **See also** @@ -595,6 +619,22 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p); - [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback) +## jerry_promise_state_t + +Enum which describes the state of a Promise. + +Possible values: + + - JERRY_PROMISE_STATE_NONE - Invalid/Unknown state (possibly called on a non-promise object). + - JERRY_PROMISE_STATE_PENDING - Promise is in "Pending" state. + - JERRY_PROMISE_STATE_FULFILLED - Promise is in "Fulfilled" state. + - JERRY_PROMISE_STATE_REJECTED - Promise is in "Rejected" state. + +*New in version 2.2*. + +**See also** + +- [jerry_get_promise_result](#jerry_get_promise_result) ## jerry_typedarray_type_t @@ -1843,6 +1883,55 @@ jerry_value_is_promise (const jerry_value_t value) - [jerry_create_promise](#jerry_create_promise) +## jerry_value_is_proxy + +**Summary** + +Returns whether the given `jerry_value_t` is a proxy value. + +*Notes*: +- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROXY`) and can be checked + in runtime with the `JERRY_FEATURE_PROXY` feature enum value, + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + + +**Prototype** + +```c +bool +jerry_value_is_proxy (const jerry_value_t value) +``` + +- `value` - api value +- return value + - true, if the given `jerry_value_t` is a proxy object + - false, otherwise + +**Example** + +*New in version 2.3*. + +```c +{ + jerry_value_t value; + ... // create or acquire value + + if (jerry_value_is_proxy (value)) + { + ... + } + + jerry_release_value (value); +} +``` + +**See also** + +- [jerry_release_value](#jerry_release_value) +- [jerry_create_proxy](#jerry_create_proxy) + + ## jerry_value_is_string **Summary** @@ -2000,6 +2089,64 @@ main (void) - [jerry_create_typedarray](#jerry_create_typedarray) +## jerry_get_container_type + +**Summary** + +Checks whether the given `jerry_value_t` is the given `jerry_container_type_t` type container object. + +*Notes* +- This API function depends on a build option (`JERRY_ES2015_BUILTIN_CONTAINER`) and can be checked + runtime with the `JERRY_FEATURE_MAP, JERRY_FEATURE_SET, JERRY_FEATURE_WEAKMAP, JERRY_FEATURE_WEAKSET` + feature enum values. + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + +*New in version 2.3*. + +**Prototype** + +```c +jerry_container_type_t +jerry_get_container_type (const jerry_value_t value) +``` + +- `value` - Container object +- return value + - The corresponding enum value of `jerry_container_type_t`, or `JERRY_CONTAINER_TYPE_INVALID` if the container + was not a valid container object. +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t value = jerry_create_container (JERRY_CONTAINER_TYPE_MAP, NULL, 0); + + if (jerry_get_container_type (value) == JERRY_CONTAINER_TYPE_MAP) + { + /* "value" is a map. */ + } + + jerry_release_value (value); + + jerry_cleanup (); + + return 0; +} +``` + +**See also** + +- [jerry_create_container](#jerry_create_container) +- [jerry_container_type_t](#jerry_container_type_t) + + ## jerry_value_is_undefined **Summary** @@ -3231,6 +3378,144 @@ jerry_value_to_string (const jerry_value_t value); These APIs all depend on the ES2015-subset profile (or on some build options). +## jerry_get_promise_result + +**Summary** + +The function returns the result of a Promise object. + +*Notes*: +- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it + is no longer needed. +- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROMISE`) and can be checked + in runtime with the `JERRY_FEATURE_PROMISE` feature enum value, + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + + +**Prototype** + +```c +jerry_value_t +jerry_get_promise_result (const jerry_value_t promise); +``` + +- `promise` - the input Promise object. +- return + - The result of the Promise. + - If the Promise is not resolved yet the result is the 'undefined' value. + - A TypeError is returned if the input argument was not a Promise object or + the Promise support was not built into the library. + +*New in version 2.2*. + +**Example** + +[doctest]: # (test="compile") + +```c +#include + +static void +example (void) +{ + // acquire/create a promise object. + jerry_value_t promise = jerry_create_promise (); + { + // prepare the argumnent for the resolve or reject. + jerry_value_t argument = jerry_create_number (33); + + jerry_value_t is_ok = jerry_resolve_or_reject_promise (promise, + argument, + true); + // 'is_ok' should be checked if it is an error or not. + // skipped in this example + jerry_release_value (is_ok); + jerry_release_value (argument); + } + + jerry_value_t promise_result = jerry_get_promise_result (promise); + // 'promise_result' is now the number 33. + + jerry_release_value (promise_result); + jerry_release_value (promise); +} +``` + +**See also** + +- [jerry_create_promise](#jerry_create_promise) +- [jerry_promise_state_t](#jerry_promise_state_t) + +## jerry_get_promise_state + +**Summary** + +*Notes*: +- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it + is no longer needed. +- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROMISE`) and can be checked + in runtime with the `JERRY_FEATURE_PROMISE` feature enum value, + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + + +**Prototype** + +```c +jerry_promise_state_t +jerry_get_promise_state (const jerry_value_t promise); +``` + +- `promise` - the input promise object. +- return + - [jerry_promise_state_t](#jerry_promise_state_t) + - `JERRY_PROMISE_STATE_NONE` is returned if the input argument was not a promise object or + the Promise support was not built into the library. + +*New in version 2.2*. + +**Example** + +[doctest]: # (test="compile") + +```c +#include + +static void +example (void) +{ + // acquire/create a promise object. + jerry_value_t promise = jerry_create_promise (); + + jerry_promise_state_t start_state = jerry_get_promise_state (promise); + // a Promise have a default state of JERRY_PROMISE_STATE_PENDING + + { + // prepare the argumnent for the resolve or reject. + jerry_value_t argument = jerry_create_number (33); + + jerry_value_t is_ok = jerry_resolve_or_reject_promise (promise, + argument, + true); + // 'is_ok' should be checked if it is an error or not. + // skipped in this example + jerry_release_value (is_ok); + jerry_release_value (argument); + } + + jerry_promise_state_t current_state = jerry_get_promise_state (promise); + // at this point the Promise should be in the JERRY_PROMISE_STATE_FULFILLED state. + + jerry_release_value (promise); +} +``` + +**See also** + +- [jerry_create_promise](#jerry_create_promise) +- [jerry_promise_state_t](#jerry_promise_state_t) + ## jerry_resolve_or_reject_promise **Summary** @@ -3548,7 +3833,7 @@ jerry_create_arraybuffer_external (const jerry_length_t size - `free_cb` - the callback function called when the object is released - return value - the new ArrayBuffer as a `jerry_value_t` - - if the `size` is zero or `buffer_p` is a null pointer will return RangeError + - if the `size` is zero or `buffer_p` is a null pointer this will return an empty ArrayBuffer. *New in version 2.0*. @@ -4052,6 +4337,65 @@ jerry_create_promise (void) - [jerry_release_value](#jerry_release_value) +## jerry_create_proxy + +**Summary** + +Create a new Proxy object with the given target and handler. + +*Note*: + - This API depends on the ES2015-subset profile. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) + when it is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_create_proxy (const jerry_value_t target, + const jerry_value_t handler) +``` + +- `target` - proxy target +- `handler` - proxy handler +- return thrown error - if the Proxy construction fails + value of the newly created proxy object - otherwise + +**Example** + +*New in version 2.3*. + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + + // usage of the proxy + + jerry_release_value (proxy); + + jerry_cleanup (); +} +``` + +**See also** + +- [jerry_value_is_proxy](#jerry_value_is_proxy) +- [jerry_release_value](#jerry_release_value) + + ## jerry_create_string **Summary** @@ -4068,7 +4412,7 @@ jerry_value_t jerry_create_string (const jerry_char_t *str_p); ``` -- `str_p` - pointer to string +- `str_p` - non-null pointer to string - return value - value of the created string **Example** @@ -4107,7 +4451,7 @@ jerry_create_string_sz (const jerry_char_t *str_p, jerry_size_t str_size) ``` -- `str_p` - pointer to string +- `str_p` - non-null pointer to string - `str_size` - size of the string - return value - value of the created string @@ -4138,8 +4482,9 @@ jerry_create_string_sz (const jerry_char_t *str_p, Create string from a valid UTF8 string. -*Note*: The difference from [jerry_create_string](#jerry_create_string) is that it accepts utf-8 string instead of cesu-8 string. -*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +*Note*: + - The difference from [jerry_create_string](#jerry_create_string) is that it accepts utf-8 string instead of cesu-8 string. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it is no longer needed. **Prototype** @@ -4149,7 +4494,7 @@ jerry_value_t jerry_create_string_from_utf8 (const jerry_char_t *str_p); ``` -- `str_p` - pointer to string +- `str_p` - non-null pointer to string - return value - value of the created string *New in version 2.0*. @@ -4179,19 +4524,20 @@ jerry_create_string_from_utf8 (const jerry_char_t *str_p); Create string from a valid UTF8 string. -*Note*: The difference from [jerry_create_string_sz](#jerry_create_string_sz) is that it accepts utf-8 string instead of cesu-8 string. -*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +*Note*: + - The difference from [jerry_create_string_sz](#jerry_create_string_sz) is that it accepts utf-8 string instead of cesu-8 string. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it is no longer needed. **Prototype** ```c jerry_value_t -jerry_create_string_sz (const jerry_char_t *str_p, - jerry_size_t str_size) +jerry_create_string_sz_from_utf8 (const jerry_char_t *str_p, + jerry_size_t str_size) ``` -- `str_p` - pointer to string +- `str_p` - non-null pointer to string - `str_size` - size of the string - return value - value of the created string @@ -4531,6 +4877,70 @@ jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, - [jerry_release_value](#jerry_release_value) +## jerry_create_container + +**Summary** + +Create a jerry_value_t representing a given type container object. + +*Notes*: +- This method is expected to work the same way as the JavaScript Map constructor. +- Returned value must be freed with [jerry_release_value](#jerry_release_value) + when it is no longer needed. +- This API depends on a build option (`JERRY_ES2015_BUILTIN_CONTAINER`) and can be checked + in runtime with the `JERRY_FEATURE_MAP, JERRY_FEATURE_SET, JERRY_FEATURE_WEAKMAP, JERRY_FEATURE_WEAKSET` + feature enum values. + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + +*New in version 2.3*. + +**Prototype** + +```c +jerry_value_t +jerry_create_container (jerry_container_type_t container_type, + const jerry_value_t *arguments_list_p, + jerry_length_t arguments_list_len); +``` + +- `container_type` - Type of the container to be created, see `jerry_container_type_t`. +- `arguments_list_p` - The arguments passed to the container constructor to be inserted to the container. +- `arguments_list_len` - The length of the above arguments. +- return value - the new container object as a `jerry_value_t` + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + jerry_char_t src[] = "[1,2,3,4].entries()"; + jerry_value_t iterable = jerry_eval (src, sizeof (src) - 1, JERRY_PARSE_NO_OPTS); + + jerry_value_t map = jerry_create_container (JERRY_CONTAINER_TYPE_MAP, &iterable, 1); + jerry_release_value (iterable); + + // use the Map + + jerry_release_value (map); + + jerry_cleanup (); + return 0; +} +``` + +**See also** + +- [jerry_container_type_t](#jerry_container_type_t) +- [jerry_get_container_type](#jerry_get_container_type) + + ## jerry_create_undefined **Summary** @@ -4584,11 +4994,12 @@ jerry_has_property (const jerry_value_t obj_val, - `obj_val` - object value - `prop_name_val` - property name -- return value - JavaScript boolean value that evaluates to - - true, if the property exists - - false, otherwise +- return value - JavaScript value that evaluates to + - raised error - if the operation fail + - true/false API value - depend on whether the property exists *Changed in version 2.0*: The return value type is now a JavaScript value and not a primitive boolean value. +*Changed in version 2.3*: The return value can be an error value. **Example** @@ -4643,11 +5054,12 @@ jerry_has_own_property (const jerry_value_t obj_val, - `obj_val` - object value - `prop_name_val` - property name -- return value - JavaScript boolean value that evaluates to - - true, if the property exists - - false, otherwise +- return value - JavaScript value that evaluates to + - raised error - if the operation fails + - true/false API value - depend on whether the property exists *Changed in version 2.0*: The return value type is now a JavaScript value and not a primitive boolean value. +*Changed in version 2.3*: The return value can be an error value. **Example** @@ -4683,6 +5095,65 @@ main (void) - [jerry_delete_property](#jerry_delete_property) +## jerry_has_internal_property + +**Summary** + +Checks whether the object has the given internal property. + +*Note*: + - Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +is no longer needed. + +**Prototype** + +```c +bool +jerry_has_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - true, if the property exists + - false, otherwise + +*New in version 2.2*. + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + bool has_internal_js_prop = jerry_has_internal_property (global_object, prop_name); + + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + + ## jerry_delete_property **Summary** @@ -4772,6 +5243,52 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, - [jerry_get_property_by_index](#jerry_get_property_by_index) - [jerry_set_property_by_index](#jerry_set_property_by_index) +## jerry_delete_internal_property + +**Summary** + +Delete an internal property from an object. + +*Note*: Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + +**Prototype** + +```c +bool +jerry_delete_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - true, if property was deleted successfully + - false, otherwise + +*New in version 2.2*. + +**Example** + +```c +{ + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + bool delete_result = jerry_delete_internal_property (global_object, prop_name); + /* use "delete_result" */ + + jerry_release_value (prop_name); + jerry_release_value (global_object); +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + ## jerry_get_property @@ -4884,6 +5401,68 @@ jerry_get_property_by_index (const jerry_value_t obj_val, - [jerry_set_property](#jerry_set_property) - [jerry_set_property_by_index](#jerry_set_property_by_index) +## jerry_get_internal_property + +**Summary** + +Get value of an internal property to the specified object with the given name. + +*Note*: + - Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it + is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_get_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - value of property, if the internal property exists + - undefined value, if the, if the internal does not property exists + - thrown error, otherwise + +*New in version 2.2*. + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + jerry_value_t prop_value = jerry_get_internal_property (global_object, prop_name); + + /* use "prop_value" then release it. */ + + jerry_release_value (prop_value); + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + ## jerry_set_property @@ -5001,6 +5580,70 @@ jerry_set_property_by_index (const jerry_value_t obj_val, - [jerry_get_property_by_index](#jerry_get_property_by_index) +## jerry_set_internal_property + +**Summary** + +Set an internal property to the specified object with the given name. + +*Note*: + - The property cannot be accessed from the JavaScript context, only from the public API. + - It is different from [jerry_set_object_native_pointer](#jerry_set_object_native_pointer) in that any jerry API value + can be hidden from the JavaScript context, not only native pointers. + +**Prototype** + +```c +bool +jerry_set_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val, + const jerry_value_t value_to_set) +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- `value_to_set` - value to set +- return value + - true, if success + - thrown error, otherwise + +*New in version 2.2*. + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + jerry_value_t value_to_set = jerry_create_number (5); + + bool set_result = jerry_set_internal_property (global_object, prop_name, value_to_set); + + /* check the result of internal property set call */ + + jerry_release_value (value_to_set); + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) + + ## jerry_init_property_descriptor_fields **Summary** @@ -5761,7 +6404,10 @@ You can get them by calling [jerry_get_object_native_pointer](#jerry_get_object_ it will be called by the garbage collector when the object is freed. - If the object is only referenced via the "global" object (or one of it's "child"), the free callback will be invoked during the execution of `jerry_cleanup`. - - The free callback **must not** invoke API functions. + - The free callback can invoke API functions. + +*Note*: If possible do not store API values in native pointers, rather check + [jerry_set_internal_property](#jerry_set_internal_property). **Prototype** @@ -7169,6 +7815,239 @@ main (void) - [jerry_create_external_function](#jerry_create_external_function) +## jerry_get_resource_name + +**Summary** + +Get the resource name (usually a file name) of the currently executed script or the given function object. + +This function is typically called from native callbacks. + +*Notes*: +- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +is no longer needed. +- This feature depends on build option (`JERRY_LINE_INFO`) and can be checked + in runtime with the `JERRY_FEATURE_LINE_INFO` feature enum value, + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). + +**Prototype** + +```c +jerry_value_t +jerry_get_resource_name (jerry_value_t value); +``` +- `value` - api value to obtain the resource name from +- return string value constructed from + - the currently executed function object's resource name, if the given value is undefined + - resource name of the function object, if the given value is a function object + - "", otherwise + +*New in version 2.2*. + +**Example** + +[doctest]: # (name="02.API-REFERENCE-jsresourcename.c") + +```c +#include +#include +#include "jerryscript.h" + +static jerry_value_t +resource_name_handler (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_count) +{ + jerry_value_t undefined_value = jerry_create_undefined (); + jerry_value_t resource_name = jerry_get_resource_name (args_count > 0 ? args_p[0] : undefined_value); + jerry_release_value (undefined_value); + + return resource_name; +} /* resource_name_handler */ + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global = jerry_get_global_object (); + + /* Register the "resourceName" method. */ + { + jerry_value_t func = jerry_create_external_function (resource_name_handler); + jerry_value_t name = jerry_create_string ((const jerry_char_t *) "resourceName"); + jerry_value_t result = jerry_set_property (global, name, func); + jerry_release_value (result); + jerry_release_value (name); + jerry_release_value (func); + } + + jerry_release_value (global); + + const jerry_char_t source[] = "function myFunction() { return resourceName() }; myFunction()"; + const jerry_char_t resource[] = "demo.js"; + + jerry_value_t program = jerry_parse (resource, + sizeof (resource) - 1, + source, + sizeof (source) - 1, + JERRY_PARSE_NO_OPTS); + + if (!jerry_value_is_error (program)) + { + /* `run_result` contains "demo.js" */ + jerry_value_t run_result = jerry_run (program); + + /* usage of `run_result` */ + + jerry_release_value (run_result); + } + + jerry_release_value (program); + jerry_cleanup (); + + return 0; +} +``` + +**See also** + +- [jerry_create_external_function](#jerry_create_external_function) + +## jerry_get_new_target + +**Summary** + +Returns the current "new.target" JavaScript function at the call site. + +If used outside of a native C function it will return "undefined" value. + +*Notes*: +- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +is no longer needed. +- This feature depends on build option (`JERRY_ES2015`) and can be checked + in runtime with the `JERRY_FEATURE_SYMBOL` feature enum value (as symbols are enabled in case of ES2015), + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- If the ES2015 mode is not enabled this method will always return the "undefined" value. + +**Prototype** + +```c +jerry_value_t +jerry_get_new_target (void); +``` +- return + - "undefined" - if at the call site it was not a constructor call. + - function object - if the current call site is in a constructor call. + +*New in version 2.2*. + +**Example 1** + +[doctest]: # (name="02.API-REFERENCE-jsnewtarget-01.c") + +```c +#include +#include +#include + +static jerry_value_t +demo_handler (const jerry_value_t func_obj_val, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{ + jerry_value_t new_target = jerry_get_new_target (); + + /* new_target is the "demo" JS function object */ + if (jerry_value_get_type (new_target) == JERRY_TYPE_FUNCTION) + { + printf ("This is a construct call\r\n"); + } + + jerry_release_value (new_target); + + return jerry_create_undefined (); +} + +int +main (int argc, char** argv) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t function_val = jerry_create_external_function (demo_handler); + + jerry_value_t ret_val = jerry_construct_object (function_val, NULL, 0); + + jerry_release_value (ret_val); + jerry_release_value (function_val); + + jerry_cleanup (); + return 0; +} +``` + +**Example 2** + +[doctest]: # (name="02.API-REFERENCE-jsnewtarget-02.c") + +```c +#include +#include +#include + +static jerry_value_t +demo_handler (const jerry_value_t func_obj_val, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{ + jerry_value_t new_target = jerry_get_new_target (); + + /* new_target is a JS function object */ + if (jerry_value_get_type (new_target) == JERRY_TYPE_FUNCTION) + { + printf ("This is a construct call\r\n"); + } + + jerry_release_value (new_target); + + return jerry_create_undefined (); +} + +int +main (int argc, char** argv) +{ + jerry_init (JERRY_INIT_EMPTY); + + /* register C method */ + jerry_value_t global_obj_val = jerry_get_global_object (); + jerry_value_t function_val = jerry_create_external_function (demo_handler); + jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) "demo"); + jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val); + jerry_release_value (result_val); + jerry_release_value (function_name_val); + jerry_release_value (function_val); + jerry_release_value (global_obj_val); + + /* Invoke C method via JS */ + const char *src = "new demo ()"; + jerry_value_t ret_val = jerry_eval ((const jerry_char_t *) src, + strlen (src), + JERRY_PARSE_NO_OPTS); + + jerry_release_value (ret_val); + + jerry_cleanup (); + return 0; +} +``` + +**See also** + +- [jerry_construct_object](#jerry_construct_object) + # ArrayBuffer and TypedArray functions These APIs all depend on the ES2015-subset profile. @@ -7397,6 +8276,89 @@ jerry_get_arraybuffer_pointer (const jerry_value_t value); - [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) +## jerry_is_arraybuffer_detachable + +**Summary** + +Get if the ArrayBuffer is detachable. + +**Prototype** + +```c +jerry_value_t +jerry_is_arraybuffer_detachable (const jerry_value_t value); +``` + +- `value` - ArrayBuffer to be detached +- return + - boolean value if success + - Error otherwise + +*New in version 2.2*. + +**Example** + +```c +{ + // create the ArrayBuffer + jerry_value_t buffer = jerry_create_arraybuffer (16); + + jerry_value_t res = jerry_is_arraybuffer_detachable (buffer); + bool is_detachable = jerry_get_boolean_value (res); + + // release buffer as it is not needed after this point + jerry_release_value (res); + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_detach_arraybuffer](#jerry_detach_arraybuffer) + +## jerry_detach_arraybuffer + +**Summary** + +Detach the underlying data block from ArrayBuffer and set its bytelength to 0. + +This operation requires the ArrayBuffer to be external that created by +`jerry_create_arraybuffer_external`. + +**Prototype** + +```c +jerry_value_t +jerry_detach_arraybuffer (const jerry_value_t value); +``` + +- `value` - ArrayBuffer to be detached +- return + - null value if success + - Error otherwise + +*New in version 2.2*. + +**Example** + +```c +{ + uint8_t buf[1]; + jerry_size_t length = 1; + // create the ArrayBuffer + jerry_value_t buffer = jerry_create_arraybuffer (length, buf, NULL); + + jerry_value_t res = jerry_detach_arraybuffer (buffer); + + // release buffer as it is not needed after this point + jerry_release_value (res); + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_is_arraybuffer_detachable](#jerry_is_arraybuffer_detachable) ## jerry_get_dataview_buffer diff --git a/docs/03.API-EXAMPLE.md b/docs/03.API-EXAMPLE.md index 0c6d689b..b6c3c633 100644 --- a/docs/03.API-EXAMPLE.md +++ b/docs/03.API-EXAMPLE.md @@ -1084,7 +1084,8 @@ int main (void) { /* Initialize srand value */ - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); /* Generate a random number, and print it */ const jerry_char_t script[] = "var a = Math.random (); print(a)"; diff --git a/engine.gni b/engine.gni index fb753870..f13ae05d 100644 --- a/engine.gni +++ b/engine.gni @@ -1,24 +1,24 @@ -# Copyright (c) 2020 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -engine_path = "//third_party/jerryscript" - -core_path = "${engine_path}/jerry-core" - -debugger_path = "${engine_path}/jerry-debugger" - -ext_path = "${engine_path}/jerry-ext" - -libm_path = "${engine_path}/jerry-libm" - -port_path = "${engine_path}/jerry-port" +# Copyright (c) 2020 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +engine_path = "//third_party/jerryscript" + +core_path = "${engine_path}/jerry-core" + +debugger_path = "${engine_path}/jerry-debugger" + +ext_path = "${engine_path}/jerry-ext" + +libm_path = "${engine_path}/jerry-libm" + +port_path = "${engine_path}/jerry-port" diff --git a/jerry-core/BUILD.gn b/jerry-core/BUILD.gn index b2aded54..45ff49f2 100755 --- a/jerry-core/BUILD.gn +++ b/jerry-core/BUILD.gn @@ -43,6 +43,7 @@ lite_library("jerry-core_shared") { "ecma/base/ecma-module.c", "ecma/base/ecma-property-hashmap.c", "ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c", + "ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c", "ecma/builtin-objects/ecma-builtin-array-prototype.c", "ecma/builtin-objects/ecma-builtin-array.c", "ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c", @@ -59,12 +60,16 @@ lite_library("jerry-core_shared") { "ecma/builtin-objects/ecma-builtin-evalerror.c", "ecma/builtin-objects/ecma-builtin-function-prototype.c", "ecma/builtin-objects/ecma-builtin-function.c", + "ecma/builtin-objects/ecma-builtin-generator-function.c", + "ecma/builtin-objects/ecma-builtin-generator-prototype.c", + "ecma/builtin-objects/ecma-builtin-generator.c", "ecma/builtin-objects/ecma-builtin-global.c", "ecma/builtin-objects/ecma-builtin-helpers-date.c", "ecma/builtin-objects/ecma-builtin-helpers-error.c", "ecma/builtin-objects/ecma-builtin-helpers-json.c", "ecma/builtin-objects/ecma-builtin-helpers-sort.c", "ecma/builtin-objects/ecma-builtin-helpers.c", + "ecma/builtin-objects/ecma-builtin-intrinsic.c", "ecma/builtin-objects/ecma-builtin-iterator-prototype.c", "ecma/builtin-objects/ecma-builtin-json.c", "ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c", @@ -77,10 +82,12 @@ lite_library("jerry-core_shared") { "ecma/builtin-objects/ecma-builtin-object.c", "ecma/builtin-objects/ecma-builtin-promise-prototype.c", "ecma/builtin-objects/ecma-builtin-promise.c", + "ecma/builtin-objects/ecma-builtin-proxy.c", "ecma/builtin-objects/ecma-builtin-rangeerror-prototype.c", "ecma/builtin-objects/ecma-builtin-rangeerror.c", "ecma/builtin-objects/ecma-builtin-referenceerror-prototype.c", "ecma/builtin-objects/ecma-builtin-referenceerror.c", + "ecma/builtin-objects/ecma-builtin-reflect.c", "ecma/builtin-objects/ecma-builtin-regexp-prototype.c", "ecma/builtin-objects/ecma-builtin-regexp.c", "ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c", @@ -98,6 +105,10 @@ lite_library("jerry-core_shared") { "ecma/builtin-objects/ecma-builtin-typeerror.c", "ecma/builtin-objects/ecma-builtin-urierror-prototype.c", "ecma/builtin-objects/ecma-builtin-urierror.c", + "ecma/builtin-objects/ecma-builtin-weakmap-prototype.c", + "ecma/builtin-objects/ecma-builtin-weakmap.c", + "ecma/builtin-objects/ecma-builtin-weakset-prototype.c", + "ecma/builtin-objects/ecma-builtin-weakset.c", "ecma/builtin-objects/ecma-builtins.c", "ecma/builtin-objects/typedarray/ecma-builtin-float32array-prototype.c", "ecma/builtin-objects/typedarray/ecma-builtin-float32array.c", @@ -140,6 +151,7 @@ lite_library("jerry-core_shared") { "ecma/operations/ecma-objects-general.c", "ecma/operations/ecma-objects.c", "ecma/operations/ecma-promise-object.c", + "ecma/operations/ecma-proxy-object.c", "ecma/operations/ecma-reference.c", "ecma/operations/ecma-regexp-object.c", "ecma/operations/ecma-string-object.c", @@ -163,8 +175,10 @@ lite_library("jerry-core_shared") { "parser/js/js-parser-mem.c", "parser/js/js-parser-module.c", "parser/js/js-parser-statm.c", + "parser/js/js-parser-tagged-template-literal.c", "parser/js/js-parser-util.c", "parser/js/js-parser.c", + "parser/js/js-scanner-ops.c", "parser/js/js-scanner-util.c", "parser/js/js-scanner.c", "parser/regexp/re-bytecode.c", diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index bef35fa1..b47ddbbc 100755 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -41,6 +41,7 @@ set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution st set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes") set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection") set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes") +set(JERRY_GC_MARK_LIMIT "(8)" CACHE STRING "Maximum depth of recursion during GC mark phase") # Option overrides if(USING_MSVC) @@ -104,6 +105,7 @@ message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP}) message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE}) message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT}) message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT}) +message(STATUS "JERRY_GC_MARK_LIMIT " ${JERRY_GC_MARK_LIMIT}) # Include directories set(INCLUDE_CORE_PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") @@ -315,6 +317,9 @@ jerry_add_define01(JERRY_VM_EXEC_STOP) # Maximum size of stack memory usage set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_STACK_LIMIT=${JERRY_STACK_LIMIT}) +# Maximum depth of recursion during GC mark phase +set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GC_MARK_LIMIT=${JERRY_GC_MARK_LIMIT}) + ## This function is to read "config.h" for default values function(read_set_defines FILE PREFIX OUTPUTVAR) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" INPUT_FILE_CONTENTS) @@ -405,6 +410,11 @@ target_include_directories(${JERRY_CORE_NAME} PRIVATE ${INCLUDE_CORE_PRIVATE}) set(JERRY_CORE_PKGCONFIG_REQUIRES) set(JERRY_CORE_PKGCONFIG_LIBS) +set(JERRY_CORE_PKGCONFIG_CFLAGS) + +if(ENABLE_LTO) + set(JERRY_CORE_PKGCONFIG_CFLAGS "${JERRY_CORE_PKGCONFIG_CFLAGS} -flto") +endif() if(JERRY_LIBM) target_link_libraries(${JERRY_CORE_NAME} jerry-libm) diff --git a/jerry-core/api/generate-bytecode.c b/jerry-core/api/generate-bytecode.c index 064e9a72..256f02cb 100755 --- a/jerry-core/api/generate-bytecode.c +++ b/jerry-core/api/generate-bytecode.c @@ -1,528 +1,528 @@ -/* - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. - * Description: Definition of source file for generating bytecode. - * Create: 2020/09/07 - */ - -#ifdef JERRY_FOR_IAR_CONFIG - -#include "generate-bytecode.h" - -#include - -#include "config-gt.h" -#include "config-jupiter.h" - -#define VERSION_LEN 30 -#define ONETIME_MAX_OPTBYTES 4096 // max size for reading and writing at onetime - -// jerry version code -char version_str[VERSION_LEN]; - -// secure functions -extern int memset_s(void *dest, size_t destMax, int c, size_t count); -extern int strcpy_s(char *strDest, size_t destMax, const char *strSrc); -extern int strcat_s(char *strDest, size_t destMax, const char *strSrc); -extern int strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); -extern int sprintf_s(char *strDest, size_t destMax, const char *format, ...); -extern int strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); - -#ifdef JERRY_IAR_JUPITER -extern uint8_t* input_buffer; -extern uint8_t* snapshot_buffer; -#endif // JERRY_IAR_JUPITER - -/** - * jerry snapshot format version - */ -char* get_jerry_version_no() { - if (sprintf_s(version_str, sizeof(version_str), - "JERRY_SNAPSHOT_VERSION_%u", JERRY_SNAPSHOT_VERSION) < 0) { - return NULL; - } - return version_str; -} /* get_jerry_version_no */ - -/** - * splice path and filename - */ -char* splice_path(char* str1, char* str2) { - int len1 = strlen(str1); - int len2 = strlen(str2); - int res_len = len1 + len2 + 1; // str1 + "/" + str2 - - char* res = (char*)OhosMalloc(MEM_TYPE_JERRY, (res_len + 1) * sizeof(char)); - if (res == NULL) { - return NULL; - } - if (memset_s(res, res_len + 1, 0, res_len + 1) != 0) { - OhosFree(res); - res = NULL; - return NULL; - } - if (strcpy_s(res, len1 + 1, str1) != 0) { - OhosFree(res); - res = NULL; - return NULL; - } - if ((strcat_s(res, len1 + strlen("/") + 1, "/") != 0) - || (strcat_s(res, res_len + 1, str2) != 0)) { - OhosFree(res); - res = NULL; - return NULL; - } - return res; -} /* splice_path */ - -/** - * judge if is template(js/bc) file - */ -bool is_template_file(char* filename, char* template) { - const char* pFile; - pFile = strrchr(filename, '.'); - if ((pFile != NULL) && (strcmp(pFile, template) == 0)) { - return true; - } - return false; -} /* is_template_file */ - -/** - * get output snapshot file absolutely path - */ -char* get_output_file_path(char* input_file_path) { - int len = strlen(input_file_path); - char* output_file_path = (char*)OhosMalloc(MEM_TYPE_JERRY, (len + 1) * sizeof(char)); - if (output_file_path == NULL) { - return NULL; - } - if (memset_s(output_file_path, len + 1, 0, len + 1) != 0) { - OhosFree(output_file_path); - output_file_path = NULL; - return NULL; - } - if (strncpy_s(output_file_path, len, input_file_path, len - strlen(".js")) != 0) { - OhosFree(output_file_path); - output_file_path = NULL; - return NULL; - } - output_file_path[len-3] = '.'; - output_file_path[len-2] = 'b'; - output_file_path[len-1] = 'c'; - output_file_path[len] = '\0'; - return output_file_path; -} /* get_output_file_path */ - -/** - * read js bundle file by Fragement - */ -EXECRES read_js_file(char* filename, uint8_t* target_Js, int* file_bytesize) { - int fd = 0; - struct stat file_stat = { 0 }; - int remain_to_read = 0; - int here_to_read = 0; - int tmp_read = 0; - int read_offset = 0; - fd = open(filename, O_RDONLY, S_IREAD); - if (fd < 0) { - // Error: failed to open file - return EXCE_ACE_JERRY_OPEN_FILE_FAILED; - } - if (fstat(fd, &file_stat) < 0) { - close(fd); - return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; - } - *file_bytesize = file_stat.st_size; - if (*file_bytesize > INPUTJS_BUFFER_SIZE) { - close(fd); - return EXCE_ACE_JERRY_JSFILE_TOO_LARGE; - } - remain_to_read = *file_bytesize; - while (remain_to_read > 0) { - here_to_read = (remain_to_read > ONETIME_MAX_OPTBYTES) ? - ONETIME_MAX_OPTBYTES : remain_to_read; - tmp_read = read(fd, target_Js + read_offset, here_to_read); - if (tmp_read < 0 || tmp_read != here_to_read) { - close(fd); - // Error: failed to read file - return EXCE_ACE_JERRY_READ_JSFILE_FAILED; - } - read_offset = read_offset + here_to_read; - remain_to_read = remain_to_read - here_to_read; - } - if (read_offset != *file_bytesize) { - close(fd); - // Error: failed to successfully read file - return EXCE_ACE_JERRY_READ_JSFILE_FAILED; - } - close(fd); - return EXCE_ACE_JERRY_EXEC_OK; -} /* read_js_file */ - -/** - * write snapshot file by Fragment - */ -EXECRES write_snapshot(char* output_file_name_path, size_t snapshot_size) { - int fd = 0; - int res = 0; - int remain_to_write = 0; - int here_to_write = 0; - int write_offset = 0; - - fd = open(output_file_name_path, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); - if (fd < 0) { - // Error: Unable to open snapshot file - return EXCE_ACE_JERRY_OPEN_FILE_FAILED; - } - remain_to_write = snapshot_size; - while (remain_to_write > 0) { - here_to_write = (remain_to_write > ONETIME_MAX_OPTBYTES) ? - ONETIME_MAX_OPTBYTES : remain_to_write; - res = write(fd, snapshot_buffer + write_offset, here_to_write); - if (res <= 0 || res != here_to_write) { - close(fd); - // Error: Unable to write snapshot file - return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; - } - write_offset = write_offset + here_to_write; - remain_to_write = remain_to_write - here_to_write; - } - if (write_offset != snapshot_size) { - close(fd); - // Error: Unable to successfully write snapshot file - return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; - } - close(fd); - return EXCE_ACE_JERRY_EXEC_OK; -} /* write_snapshot */ - -/** - * struct for Directory Node - */ -typedef struct Node { - char* dir_name; - struct Node* next; -} dir_node; - -/** - * free the memory for linkedlist - */ -void free_link(dir_node* head) { - dir_node* tmp = NULL; - while (head != NULL) { - tmp = head; - head = head->next; - if (tmp->dir_name != NULL) { - OhosFree(tmp->dir_name); - tmp->dir_name = NULL; - } - OhosFree(tmp); - tmp = NULL; - } -} /* free_link */ - -/** - * generate snapshot file - */ -EXECRES generate_snapshot_file(char* input_file, char* output_file) { - uint8_t* target_Js = input_buffer; - jerry_value_t generate_result; - size_t snapshot_size = 0; - EXECRES write_res = EXCE_ACE_JERRY_EXEC_OK; - bool convert_state = false; - int file_bytesize = 0; - EXECRES read_res = EXCE_ACE_JERRY_EXEC_OK; - - if (input_file == NULL || output_file == NULL) { - return EXCE_ACE_JERRY_NULL_PATH; - } - read_res = read_js_file(input_file, target_Js, &file_bytesize); - if (read_res != EXCE_ACE_JERRY_EXEC_OK) { - return read_res; - } - - generate_result = jerry_generate_snapshot ( - NULL, - 0, - target_Js, - file_bytesize, - 0, - (uint32_t* )snapshot_buffer, - SNAPSHOT_BUFFER_SIZE); - - convert_state = jerry_value_is_error(generate_result) - || !jerry_value_is_number(generate_result); - if (convert_state) { - // Error: Generating snapshot failed - jerry_release_value(generate_result); - return EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED; - } - snapshot_size = (size_t)jerry_get_number_value(generate_result); - jerry_release_value(generate_result); - - write_res = write_snapshot(output_file, snapshot_size); - if (write_res != EXCE_ACE_JERRY_EXEC_OK) { - // Error: Writing snapshot file failed - return write_res; - } - return EXCE_ACE_JERRY_EXEC_OK; -}/* generate_snapshot_file */ - -/** - * traverse directory and do js to bytecode conversion ON IAR - */ -EXECRES walk_directory(char* filefolder) { - EXECRES generate_val = EXCE_ACE_JERRY_EXEC_OK; - DIR* dir; - struct dirent* direntp; - struct stat file_stat = { 0 }; - char* filename = NULL; - char* current_path = NULL; - char* input_file_path = NULL; - char* output_file_path = NULL; - char* start_folder = NULL; - dir_node *head, *curr, *end, *new_node; - int filefolder_len = strlen(filefolder) + 1; - - if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { - return EXCE_ACE_JERRY_INPUT_PATH_ERROR; - } - if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { - return EXCE_ACE_JERRY_MALLOC_ERROR; - } - if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { - OhosFree(start_folder); - start_folder = NULL; - return EXCE_ACE_JERRY_INPUT_PATH_ERROR; - } - if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - OhosFree(start_folder); - start_folder = NULL; - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - OhosFree(start_folder); - start_folder = NULL; - OhosFree(head); - head = NULL; - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - head->dir_name = NULL; - head->next = end; - end->dir_name = start_folder; - end->next = NULL; - - jerry_init_flag_t flags = JERRY_INIT_EMPTY; - jerry_init (flags); - - while (head->next != NULL) { - curr = head->next; - current_path = curr->dir_name; - if ((dir = (DIR*)opendir(current_path)) == NULL) { - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_OPEN_DIR_FAILED; - } - while ((direntp = (struct dirent*)readdir(dir)) != NULL) { - filename = direntp->d_name; - if (strncmp(filename, ".", 1) == 0) { - continue; - } - if ((input_file_path = splice_path(current_path, filename)) == NULL) { - closedir(dir); - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; - } - if (stat(input_file_path, &file_stat) < 0) { - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; - } - if (file_stat.st_mode & S_IFDIR) { - // file now is file folder - if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - // input_file_path for dir will be freed when that node is freed - new_node->dir_name = input_file_path; - new_node->next = NULL; - end->next = new_node; - end = new_node; - new_node = NULL; - } else if (is_template_file(filename, ".js")) { - //filename now is .js file - if ((output_file_path = get_output_file_path(input_file_path)) == NULL) { - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR; - } - generate_val = generate_snapshot_file(input_file_path, output_file_path); - OhosFree(output_file_path); - output_file_path = NULL; - OhosFree(input_file_path); - input_file_path = NULL; - if (generate_val != EXCE_ACE_JERRY_EXEC_OK) { - closedir(dir); - free_link(head); - curr = NULL; - end = NULL; - jerry_cleanup(); - return generate_val; // return error_code - } - } else { - OhosFree(input_file_path); - input_file_path = NULL; - } - } - closedir(dir); - head->next = curr->next; - OhosFree(curr->dir_name); - curr->dir_name = NULL; - OhosFree(curr); - curr = NULL; - } - OhosFree(head); - head = NULL; - end = NULL; - jerry_cleanup(); - return EXCE_ACE_JERRY_EXEC_OK; -} /* walk_directory */ - -/** - * when convertion failed, traverse directory and delete all created bytecode files - */ -EXECRES walk_del_bytecode(char* filefolder) { - DIR* dir; - struct dirent* direntp; - struct stat file_stat = { 0 }; - char* filename = NULL; - char* current_path = NULL; - char* input_file_path = NULL; - char* start_folder = NULL; - dir_node *head, *curr, *end, *new_node; - int filefolder_len = strlen(filefolder) + 1; - - if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { - return EXCE_ACE_JERRY_INPUT_PATH_ERROR; - } - if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { - return EXCE_ACE_JERRY_MALLOC_ERROR; - } - if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { - OhosFree(start_folder); - start_folder = NULL; - return EXCE_ACE_JERRY_INPUT_PATH_ERROR; - } - if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - OhosFree(start_folder); - start_folder = NULL; - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - OhosFree(start_folder); - start_folder = NULL; - OhosFree(head); - head = NULL; - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - head->dir_name = NULL; - head->next = end; - end->dir_name = start_folder; - end->next = NULL; - - while (head->next != NULL) { - curr = head->next; - current_path = curr->dir_name; - if ((dir = (DIR*)opendir(current_path)) == NULL) { - free_link(head); - curr = NULL; - end = NULL; - return EXCE_ACE_JERRY_OPEN_DIR_FAILED; - } - while ((direntp = (struct dirent*)readdir(dir)) != NULL) { - filename = direntp->d_name; - if (strncmp(filename, ".", 1) == 0) { - continue; - } - if ((input_file_path = splice_path(current_path, filename)) == NULL) { - closedir(dir); - free_link(head); - curr = NULL; - end = NULL; - return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; - } - if (stat(input_file_path, &file_stat) < 0) { - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; - } - if (file_stat.st_mode & S_IFDIR) { - // file now is file folder - if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - return EXCE_ACE_JERRY_LINKLIST_ERROR; - } - // input_file_path for dir will be freed when that node is freed - new_node->dir_name = input_file_path; - new_node->next = NULL; - end->next = new_node; - end = new_node; - new_node = NULL; - } else if ((is_template_file(filename, ".bc")) && (unlink(input_file_path) != F_OK)) { - //file now is .bc file and unlink file failed - closedir(dir); - OhosFree(input_file_path); - input_file_path = NULL; - free_link(head); - curr = NULL; - end = NULL; - return EXCE_ACE_JERRY_UNLINKFILE_ERROR; - } else { - OhosFree(input_file_path); - input_file_path = NULL; - } - } - closedir(dir); - head->next = curr->next; - OhosFree(curr->dir_name); - curr->dir_name = NULL; - OhosFree(curr); - curr = NULL; - } - OhosFree(head); - head = NULL; - end = NULL; - return EXCE_ACE_JERRY_EXEC_OK; -} /* walk_del_bytecode */ - -#endif // end JERRY_FOR_IAR_CONFIG +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: Definition of source file for generating bytecode. + * Create: 2020/09/07 + */ + +#ifdef JERRY_FOR_IAR_CONFIG + +#include "generate-bytecode.h" + +#include + +#include "config-gt.h" +#include "config-jupiter.h" + +#define VERSION_LEN 30 +#define ONETIME_MAX_OPTBYTES 4096 // max size for reading and writing at onetime + +// jerry version code +char version_str[VERSION_LEN]; + +// secure functions +extern int memset_s(void *dest, size_t destMax, int c, size_t count); +extern int strcpy_s(char *strDest, size_t destMax, const char *strSrc); +extern int strcat_s(char *strDest, size_t destMax, const char *strSrc); +extern int strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +extern int sprintf_s(char *strDest, size_t destMax, const char *format, ...); +extern int strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); + +#ifdef JERRY_IAR_JUPITER +extern uint8_t* input_buffer; +extern uint8_t* snapshot_buffer; +#endif // JERRY_IAR_JUPITER + +/** + * jerry snapshot format version + */ +char* get_jerry_version_no() { + if (sprintf_s(version_str, sizeof(version_str), + "JERRY_SNAPSHOT_VERSION_%u", JERRY_SNAPSHOT_VERSION) < 0) { + return NULL; + } + return version_str; +} /* get_jerry_version_no */ + +/** + * splice path and filename + */ +char* splice_path(char* str1, char* str2) { + int len1 = strlen(str1); + int len2 = strlen(str2); + int res_len = len1 + len2 + 1; // str1 + "/" + str2 + + char* res = (char*)OhosMalloc(MEM_TYPE_JERRY, (res_len + 1) * sizeof(char)); + if (res == NULL) { + return NULL; + } + if (memset_s(res, res_len + 1, 0, res_len + 1) != 0) { + OhosFree(res); + res = NULL; + return NULL; + } + if (strcpy_s(res, len1 + 1, str1) != 0) { + OhosFree(res); + res = NULL; + return NULL; + } + if ((strcat_s(res, len1 + strlen("/") + 1, "/") != 0) + || (strcat_s(res, res_len + 1, str2) != 0)) { + OhosFree(res); + res = NULL; + return NULL; + } + return res; +} /* splice_path */ + +/** + * judge if is template(js/bc) file + */ +bool is_template_file(char* filename, char* template) { + const char* pFile; + pFile = strrchr(filename, '.'); + if ((pFile != NULL) && (strcmp(pFile, template) == 0)) { + return true; + } + return false; +} /* is_template_file */ + +/** + * get output snapshot file absolutely path + */ +char* get_output_file_path(char* input_file_path) { + int len = strlen(input_file_path); + char* output_file_path = (char*)OhosMalloc(MEM_TYPE_JERRY, (len + 1) * sizeof(char)); + if (output_file_path == NULL) { + return NULL; + } + if (memset_s(output_file_path, len + 1, 0, len + 1) != 0) { + OhosFree(output_file_path); + output_file_path = NULL; + return NULL; + } + if (strncpy_s(output_file_path, len, input_file_path, len - strlen(".js")) != 0) { + OhosFree(output_file_path); + output_file_path = NULL; + return NULL; + } + output_file_path[len-3] = '.'; + output_file_path[len-2] = 'b'; + output_file_path[len-1] = 'c'; + output_file_path[len] = '\0'; + return output_file_path; +} /* get_output_file_path */ + +/** + * read js bundle file by Fragement + */ +EXECRES read_js_file(char* filename, uint8_t* target_Js, int* file_bytesize) { + int fd = 0; + struct stat file_stat = { 0 }; + int remain_to_read = 0; + int here_to_read = 0; + int tmp_read = 0; + int read_offset = 0; + fd = open(filename, O_RDONLY, S_IREAD); + if (fd < 0) { + // Error: failed to open file + return EXCE_ACE_JERRY_OPEN_FILE_FAILED; + } + if (fstat(fd, &file_stat) < 0) { + close(fd); + return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; + } + *file_bytesize = file_stat.st_size; + if (*file_bytesize > INPUTJS_BUFFER_SIZE) { + close(fd); + return EXCE_ACE_JERRY_JSFILE_TOO_LARGE; + } + remain_to_read = *file_bytesize; + while (remain_to_read > 0) { + here_to_read = (remain_to_read > ONETIME_MAX_OPTBYTES) ? + ONETIME_MAX_OPTBYTES : remain_to_read; + tmp_read = read(fd, target_Js + read_offset, here_to_read); + if (tmp_read < 0 || tmp_read != here_to_read) { + close(fd); + // Error: failed to read file + return EXCE_ACE_JERRY_READ_JSFILE_FAILED; + } + read_offset = read_offset + here_to_read; + remain_to_read = remain_to_read - here_to_read; + } + if (read_offset != *file_bytesize) { + close(fd); + // Error: failed to successfully read file + return EXCE_ACE_JERRY_READ_JSFILE_FAILED; + } + close(fd); + return EXCE_ACE_JERRY_EXEC_OK; +} /* read_js_file */ + +/** + * write snapshot file by Fragment + */ +EXECRES write_snapshot(char* output_file_name_path, size_t snapshot_size) { + int fd = 0; + int res = 0; + int remain_to_write = 0; + int here_to_write = 0; + int write_offset = 0; + + fd = open(output_file_name_path, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); + if (fd < 0) { + // Error: Unable to open snapshot file + return EXCE_ACE_JERRY_OPEN_FILE_FAILED; + } + remain_to_write = snapshot_size; + while (remain_to_write > 0) { + here_to_write = (remain_to_write > ONETIME_MAX_OPTBYTES) ? + ONETIME_MAX_OPTBYTES : remain_to_write; + res = write(fd, snapshot_buffer + write_offset, here_to_write); + if (res <= 0 || res != here_to_write) { + close(fd); + // Error: Unable to write snapshot file + return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; + } + write_offset = write_offset + here_to_write; + remain_to_write = remain_to_write - here_to_write; + } + if (write_offset != snapshot_size) { + close(fd); + // Error: Unable to successfully write snapshot file + return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; + } + close(fd); + return EXCE_ACE_JERRY_EXEC_OK; +} /* write_snapshot */ + +/** + * struct for Directory Node + */ +typedef struct Node { + char* dir_name; + struct Node* next; +} dir_node; + +/** + * free the memory for linkedlist + */ +void free_link(dir_node* head) { + dir_node* tmp = NULL; + while (head != NULL) { + tmp = head; + head = head->next; + if (tmp->dir_name != NULL) { + OhosFree(tmp->dir_name); + tmp->dir_name = NULL; + } + OhosFree(tmp); + tmp = NULL; + } +} /* free_link */ + +/** + * generate snapshot file + */ +EXECRES generate_snapshot_file(char* input_file, char* output_file) { + uint8_t* target_Js = input_buffer; + jerry_value_t generate_result; + size_t snapshot_size = 0; + EXECRES write_res = EXCE_ACE_JERRY_EXEC_OK; + bool convert_state = false; + int file_bytesize = 0; + EXECRES read_res = EXCE_ACE_JERRY_EXEC_OK; + + if (input_file == NULL || output_file == NULL) { + return EXCE_ACE_JERRY_NULL_PATH; + } + read_res = read_js_file(input_file, target_Js, &file_bytesize); + if (read_res != EXCE_ACE_JERRY_EXEC_OK) { + return read_res; + } + + generate_result = jerry_generate_snapshot ( + NULL, + 0, + target_Js, + file_bytesize, + 0, + (uint32_t* )snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + + convert_state = jerry_value_is_error(generate_result) + || !jerry_value_is_number(generate_result); + if (convert_state) { + // Error: Generating snapshot failed + jerry_release_value(generate_result); + return EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED; + } + snapshot_size = (size_t)jerry_get_number_value(generate_result); + jerry_release_value(generate_result); + + write_res = write_snapshot(output_file, snapshot_size); + if (write_res != EXCE_ACE_JERRY_EXEC_OK) { + // Error: Writing snapshot file failed + return write_res; + } + return EXCE_ACE_JERRY_EXEC_OK; +}/* generate_snapshot_file */ + +/** + * traverse directory and do js to bytecode conversion ON IAR + */ +EXECRES walk_directory(char* filefolder) { + EXECRES generate_val = EXCE_ACE_JERRY_EXEC_OK; + DIR* dir; + struct dirent* direntp; + struct stat file_stat = { 0 }; + char* filename = NULL; + char* current_path = NULL; + char* input_file_path = NULL; + char* output_file_path = NULL; + char* start_folder = NULL; + dir_node *head, *curr, *end, *new_node; + int filefolder_len = strlen(filefolder) + 1; + + if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { + return EXCE_ACE_JERRY_INPUT_PATH_ERROR; + } + if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { + return EXCE_ACE_JERRY_MALLOC_ERROR; + } + if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { + OhosFree(start_folder); + start_folder = NULL; + return EXCE_ACE_JERRY_INPUT_PATH_ERROR; + } + if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + OhosFree(start_folder); + start_folder = NULL; + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + OhosFree(start_folder); + start_folder = NULL; + OhosFree(head); + head = NULL; + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + head->dir_name = NULL; + head->next = end; + end->dir_name = start_folder; + end->next = NULL; + + jerry_init_flag_t flags = JERRY_INIT_EMPTY; + jerry_init (flags); + + while (head->next != NULL) { + curr = head->next; + current_path = curr->dir_name; + if ((dir = (DIR*)opendir(current_path)) == NULL) { + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_OPEN_DIR_FAILED; + } + while ((direntp = (struct dirent*)readdir(dir)) != NULL) { + filename = direntp->d_name; + if (strncmp(filename, ".", 1) == 0) { + continue; + } + if ((input_file_path = splice_path(current_path, filename)) == NULL) { + closedir(dir); + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; + } + if (stat(input_file_path, &file_stat) < 0) { + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; + } + if (file_stat.st_mode & S_IFDIR) { + // file now is file folder + if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + // input_file_path for dir will be freed when that node is freed + new_node->dir_name = input_file_path; + new_node->next = NULL; + end->next = new_node; + end = new_node; + new_node = NULL; + } else if (is_template_file(filename, ".js")) { + //filename now is .js file + if ((output_file_path = get_output_file_path(input_file_path)) == NULL) { + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR; + } + generate_val = generate_snapshot_file(input_file_path, output_file_path); + OhosFree(output_file_path); + output_file_path = NULL; + OhosFree(input_file_path); + input_file_path = NULL; + if (generate_val != EXCE_ACE_JERRY_EXEC_OK) { + closedir(dir); + free_link(head); + curr = NULL; + end = NULL; + jerry_cleanup(); + return generate_val; // return error_code + } + } else { + OhosFree(input_file_path); + input_file_path = NULL; + } + } + closedir(dir); + head->next = curr->next; + OhosFree(curr->dir_name); + curr->dir_name = NULL; + OhosFree(curr); + curr = NULL; + } + OhosFree(head); + head = NULL; + end = NULL; + jerry_cleanup(); + return EXCE_ACE_JERRY_EXEC_OK; +} /* walk_directory */ + +/** + * when convertion failed, traverse directory and delete all created bytecode files + */ +EXECRES walk_del_bytecode(char* filefolder) { + DIR* dir; + struct dirent* direntp; + struct stat file_stat = { 0 }; + char* filename = NULL; + char* current_path = NULL; + char* input_file_path = NULL; + char* start_folder = NULL; + dir_node *head, *curr, *end, *new_node; + int filefolder_len = strlen(filefolder) + 1; + + if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { + return EXCE_ACE_JERRY_INPUT_PATH_ERROR; + } + if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { + return EXCE_ACE_JERRY_MALLOC_ERROR; + } + if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { + OhosFree(start_folder); + start_folder = NULL; + return EXCE_ACE_JERRY_INPUT_PATH_ERROR; + } + if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + OhosFree(start_folder); + start_folder = NULL; + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + OhosFree(start_folder); + start_folder = NULL; + OhosFree(head); + head = NULL; + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + head->dir_name = NULL; + head->next = end; + end->dir_name = start_folder; + end->next = NULL; + + while (head->next != NULL) { + curr = head->next; + current_path = curr->dir_name; + if ((dir = (DIR*)opendir(current_path)) == NULL) { + free_link(head); + curr = NULL; + end = NULL; + return EXCE_ACE_JERRY_OPEN_DIR_FAILED; + } + while ((direntp = (struct dirent*)readdir(dir)) != NULL) { + filename = direntp->d_name; + if (strncmp(filename, ".", 1) == 0) { + continue; + } + if ((input_file_path = splice_path(current_path, filename)) == NULL) { + closedir(dir); + free_link(head); + curr = NULL; + end = NULL; + return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; + } + if (stat(input_file_path, &file_stat) < 0) { + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; + } + if (file_stat.st_mode & S_IFDIR) { + // file now is file folder + if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + return EXCE_ACE_JERRY_LINKLIST_ERROR; + } + // input_file_path for dir will be freed when that node is freed + new_node->dir_name = input_file_path; + new_node->next = NULL; + end->next = new_node; + end = new_node; + new_node = NULL; + } else if ((is_template_file(filename, ".bc")) && (unlink(input_file_path) != F_OK)) { + //file now is .bc file and unlink file failed + closedir(dir); + OhosFree(input_file_path); + input_file_path = NULL; + free_link(head); + curr = NULL; + end = NULL; + return EXCE_ACE_JERRY_UNLINKFILE_ERROR; + } else { + OhosFree(input_file_path); + input_file_path = NULL; + } + } + closedir(dir); + head->next = curr->next; + OhosFree(curr->dir_name); + curr->dir_name = NULL; + OhosFree(curr); + curr = NULL; + } + OhosFree(head); + head = NULL; + end = NULL; + return EXCE_ACE_JERRY_EXEC_OK; +} /* walk_del_bytecode */ + +#endif // end JERRY_FOR_IAR_CONFIG diff --git a/jerry-core/api/generate-bytecode.h b/jerry-core/api/generate-bytecode.h index 566ad2bf..d5d370d2 100755 --- a/jerry-core/api/generate-bytecode.h +++ b/jerry-core/api/generate-bytecode.h @@ -1,51 +1,51 @@ -/* - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. - * Description: Definition of header file for generating bytecode. - * Create: 2020/09/07 - */ - -#ifndef GENERATE_BYTECODE_H -#define GENERATE_BYTECODE_H - -#ifdef JERRY_FOR_IAR_CONFIG - -#include "jerryscript.h" - -typedef enum { - EXCE_ACE_JERRY_EXEC_OK = 0, // program function OK - EXCE_ACE_JERRY_NULL_PATH, // null path for generateing snapshot - EXCE_ACE_JERRY_MALLOC_ERROR, // error when malloc - EXCE_ACE_JERRY_INPUT_PATH_ERROR, // passed input path is NULL OR open failed - EXCE_ACE_JERRY_INPUT_PATH_NOT_DIR, // passed input path is not a directory - EXCE_ACE_JERRY_OPEN_DIR_FAILED, // open directory failed - EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED, // jerry_generate_snapshot failed - EXCE_ACE_JERRY_OPEN_FILE_FAILED, // open file failed - EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED, // write into snapshot file failed - EXCE_ACE_JERRY_READ_JSFILE_FAILED, // read .js file process failed - EXCE_ACE_JERRY_JSFILE_TOO_LARGE, // bytes of js file out of psRAM - EXCE_ACE_JERRY_SPLICE_PATH_ERROR, // error when splice path - EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR, // error when splice output file abs name - EXCE_ACE_JERRY_SPRINTFS_VERSION_ERROR, // error when sprintf_s for jerry_version - EXCE_ACE_JERRY_GET_FILE_STAT_ERROR, // error when getting file stat - EXCE_ACE_JERRY_LINKLIST_ERROR, // error when malloc for list node - EXCE_ACE_JERRY_UNLINKFILE_ERROR, // error when unlink bytecode file -} EXECRES; - -typedef struct -{ - jerry_context_t *context_p; -} ContextRecord; - -char* get_jerry_version_no(); -EXECRES walk_directory(char* filefolder); -EXECRES walk_del_bytecode(char* filefolder); - -void bms_task_context_init (void); -void js_task_context_init (void); -void jerry_port_default_remove_current_context_record (); - -void jerry_external_context_init(uint32_t heap_size, jerry_context_alloc_t alloc, void *cb_data_p); - -#endif // JERRY_FOR_IAR_CONFIG - -#endif // GENERATE_BYTECODE_H +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + * Description: Definition of header file for generating bytecode. + * Create: 2020/09/07 + */ + +#ifndef GENERATE_BYTECODE_H +#define GENERATE_BYTECODE_H + +#ifdef JERRY_FOR_IAR_CONFIG + +#include "jerryscript.h" + +typedef enum { + EXCE_ACE_JERRY_EXEC_OK = 0, // program function OK + EXCE_ACE_JERRY_NULL_PATH, // null path for generateing snapshot + EXCE_ACE_JERRY_MALLOC_ERROR, // error when malloc + EXCE_ACE_JERRY_INPUT_PATH_ERROR, // passed input path is NULL OR open failed + EXCE_ACE_JERRY_INPUT_PATH_NOT_DIR, // passed input path is not a directory + EXCE_ACE_JERRY_OPEN_DIR_FAILED, // open directory failed + EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED, // jerry_generate_snapshot failed + EXCE_ACE_JERRY_OPEN_FILE_FAILED, // open file failed + EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED, // write into snapshot file failed + EXCE_ACE_JERRY_READ_JSFILE_FAILED, // read .js file process failed + EXCE_ACE_JERRY_JSFILE_TOO_LARGE, // bytes of js file out of psRAM + EXCE_ACE_JERRY_SPLICE_PATH_ERROR, // error when splice path + EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR, // error when splice output file abs name + EXCE_ACE_JERRY_SPRINTFS_VERSION_ERROR, // error when sprintf_s for jerry_version + EXCE_ACE_JERRY_GET_FILE_STAT_ERROR, // error when getting file stat + EXCE_ACE_JERRY_LINKLIST_ERROR, // error when malloc for list node + EXCE_ACE_JERRY_UNLINKFILE_ERROR, // error when unlink bytecode file +} EXECRES; + +typedef struct +{ + jerry_context_t *context_p; +} ContextRecord; + +char* get_jerry_version_no(); +EXECRES walk_directory(char* filefolder); +EXECRES walk_del_bytecode(char* filefolder); + +void bms_task_context_init (void); +void js_task_context_init (void); +void jerry_port_default_remove_current_context_record (); + +void jerry_external_context_init(uint32_t heap_size, jerry_context_alloc_t alloc, void *cb_data_p); + +#endif // JERRY_FOR_IAR_CONFIG + +#endif // GENERATE_BYTECODE_H diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index a343c66d..e3f77f12 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -45,9 +45,9 @@ snapshot_get_global_flags (bool has_regex, /**< regex literal is present */ #if ENABLED (JERRY_BUILTIN_REGEXP) flags |= (has_regex ? JERRY_SNAPSHOT_HAS_REGEX_LITERAL : 0); #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) flags |= (has_class ? JERRY_SNAPSHOT_HAS_CLASS_LITERAL : 0); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ return flags; } /* snapshot_get_global_flags */ @@ -63,9 +63,9 @@ snapshot_check_global_flags (uint32_t global_flags) /**< global flags */ #if ENABLED (JERRY_BUILTIN_REGEXP) global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_REGEX_LITERAL; #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_CLASS_LITERAL; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ return global_flags == snapshot_get_global_flags (false, false); } /* snapshot_check_global_flags */ @@ -160,12 +160,19 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; -#if ENABLED (JERRY_ES2015_CLASS) - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) +#if ENABLED (JERRY_ES2015) + if (compiled_code_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + { + const char * const error_message_p = "Unsupported feature: tagged template literals."; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + return 0; + } + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) { globals_p->class_found = true; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_REGEXP) if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) @@ -288,19 +295,20 @@ static void static_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< snapshot globals */ ecma_value_t literal) /**< literal form the literal pool */ { - const lit_utf8_byte_t error_prefix[] = "Unsupported static snapshot literal: "; + lit_utf8_byte_t *str_p = (lit_utf8_byte_t *) "Unsupported static snapshot literal: "; + ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw (str_p, 37); - ecma_string_t *error_message_p = ecma_new_ecma_string_from_utf8 (error_prefix, sizeof (error_prefix) - 1); - - literal = ecma_op_to_string (literal); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (literal)); - ecma_string_t *literal_string_p = ecma_get_string_from_value (literal); - error_message_p = ecma_concat_ecma_strings (error_message_p, literal_string_p); + ecma_string_t *literal_string_p = ecma_op_to_string (literal); + JERRY_ASSERT (literal_string_p != NULL); + + ecma_stringbuilder_append (&builder, literal_string_p); + ecma_deref_ecma_string (literal_string_p); - ecma_object_t *error_object_p = ecma_new_standard_error_with_message (ECMA_ERROR_RANGE, error_message_p); - ecma_deref_ecma_string (error_message_p); + ecma_object_t *error_object_p = ecma_new_standard_error_with_message (ECMA_ERROR_RANGE, + ecma_stringbuilder_finalize (&builder)); globals_p->snapshot_error = ecma_create_error_object_reference (error_object_p); } /* static_snapshot_error_unsupported_literal */ @@ -416,7 +424,7 @@ static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< c } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG; literal_start_p = ((ecma_value_t *) buffer_p) - argument_end; @@ -488,7 +496,7 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; @@ -551,7 +559,6 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th #if ENABLED (JERRY_BUILTIN_REGEXP) if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) { - const re_compiled_code_t *re_bytecode_p = NULL; const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (ecma_compiled_code_t); @@ -559,10 +566,8 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th ecma_string_t *pattern_str_p = ecma_new_ecma_string_from_utf8 (regex_start_p, bytecode_p->refs); - re_compile_bytecode (&re_bytecode_p, - pattern_str_p, - bytecode_p->status_flags); - + const re_compiled_code_t *re_bytecode_p = re_compile_bytecode (pattern_str_p, + bytecode_p->status_flags); ecma_deref_ecma_string (pattern_str_p); return (ecma_compiled_code_t *) re_bytecode_p; @@ -581,7 +586,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -595,7 +600,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -738,9 +743,9 @@ jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< scr JERRY_UNUSED (resource_name_p); JERRY_UNUSED (resource_name_length); -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; -#endif /* ENABLED (JERRY_LINE_INFO) */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ snapshot_globals_t globals; ecma_value_t parse_status; @@ -762,7 +767,7 @@ jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< scr if (ECMA_IS_VALUE_ERROR (parse_status)) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value), true); + return ecma_create_error_reference_from_context (); } JERRY_ASSERT (bytecode_data_p != NULL); @@ -981,9 +986,15 @@ jerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */ if (as_function) { - ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_p); +#if ENABLED (JERRY_ES2015) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED) + { + ecma_create_global_lexical_block (); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *lex_env_p = ecma_get_global_scope (); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p); if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { @@ -1091,7 +1102,7 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; @@ -1169,7 +1180,7 @@ update_literal_offsets (uint8_t *buffer_p, /**< [in,out] snapshot buffer start * } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; @@ -1543,42 +1554,6 @@ jerry_append_number_to_buffer (uint8_t *buffer_p, /**< buffer */ utf8_str_size); } /* jerry_append_number_to_buffer */ -/** - * Check whether the passed ecma-string is a valid identifier. - * - * @return true - if the ecma-string is a valid identifier, - * false - otherwise - */ -static bool -ecma_string_is_valid_identifier (const ecma_string_t *string_p) -{ - bool result = false; - - ECMA_STRING_TO_UTF8_STRING (string_p, str_buffer_p, str_buffer_size); - - if (lit_char_is_identifier_start (str_buffer_p)) - { - const uint8_t *str_start_p = str_buffer_p; - const uint8_t *str_end_p = str_buffer_p + str_buffer_size; - - result = true; - - while (str_start_p < str_end_p) - { - if (!lit_char_is_identifier_part (str_start_p)) - { - result = false; - break; - } - lit_utf8_incr (&str_start_p); - } - } - - ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size); - - return result; -} /* ecma_string_is_valid_identifier */ - #endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */ /** @@ -1631,14 +1606,7 @@ jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapsho { ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]); - /* NOTE: - * We don't save a literal (in C format) which isn't a valid - * identifier or it's a magic string. - * TODO: - * Save all of the literals in C format as well. - */ - if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT - && (!is_c_format || ecma_string_is_valid_identifier (literal_p))) + if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT) { literal_count++; } @@ -1666,14 +1634,7 @@ jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapsho { ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]); - /* NOTE: - * We don't save a literal (in C format) which isn't a valid - * identifier or it's a magic string. - * TODO: - * Save all of the literals in C format as well. - */ - if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT - && (!is_c_format || ecma_string_is_valid_identifier (literal_p))) + if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT) { literal_array[literal_idx++] = literal_p; } @@ -1707,7 +1668,29 @@ jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapsho for (lit_utf8_size_t i = 0; i < literal_count; i++) { lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " \"", 0); - lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]); + ECMA_STRING_TO_UTF8_STRING (literal_array[i], str_buffer_p, str_buffer_size); + for (lit_utf8_size_t j = 0; j < str_buffer_size; j++) + { + uint8_t byte = str_buffer_p[j]; + if (byte < 32 || byte > 127) + { + lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\\x", 0); + ecma_char_t hex_digit = (ecma_char_t) (byte >> 4); + *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0')); + hex_digit = (lit_utf8_byte_t) (byte & 0xf); + *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0')); + } + else + { + if (byte == '\\' || byte == '"') + { + *lit_buf_p++ = '\\'; + } + *lit_buf_p++ = byte; + } + } + + ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size); lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\"", 0); if (i < literal_count - 1) @@ -1779,7 +1762,6 @@ jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapsho #endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */ } /* jerry_get_literals_from_snapshot */ - /** * Generate snapshot function from specified source and arguments * diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 629f0c9b..923e0f96 100755 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -22,6 +22,7 @@ #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" #include "ecma-comparison.h" +#include "ecma-container-object.h" #include "ecma-dataview-object.h" #include "ecma-exceptions.h" #include "ecma-eval.h" @@ -30,11 +31,13 @@ #include "ecma-helpers.h" #include "ecma-init-finalize.h" #include "ecma-lex-env.h" +#include "lit-char-helpers.h" #include "ecma-literal-storage.h" #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-regexp-object.h" #include "ecma-promise-object.h" +#include "ecma-proxy-object.h" #include "ecma-symbol-object.h" #include "ecma-typedarray-object.h" #include "opcodes.h" @@ -85,6 +88,24 @@ JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL re_flags_t_must_be_equal_to_jerry_regexp_flags_t); #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) +/* The internal ECMA_PROMISE_STATE_* values are "one byte away" from the API values */ +JERRY_STATIC_ASSERT ((int) ECMA_PROMISE_IS_PENDING == (int) JERRY_PROMISE_STATE_PENDING + && (int) ECMA_PROMISE_IS_FULFILLED == (int) JERRY_PROMISE_STATE_FULFILLED, + promise_internal_state_matches_external); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ + +/** + * Offset between internal and external arithmetic operator types + */ +#define ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET (JERRY_BIN_OP_SUB - NUMBER_ARITHMETIC_SUBTRACTION) + +JERRY_STATIC_ASSERT (((NUMBER_ARITHMETIC_SUBTRACTION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_SUB) + && ((NUMBER_ARITHMETIC_MULTIPLICATION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_MUL) + && ((NUMBER_ARITHMETIC_DIVISION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_DIV) + && ((NUMBER_ARITHMETIC_REMAINDER + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_REM), + number_arithmetics_operation_type_matches_external); + #if !ENABLED (JERRY_PARSER) && !ENABLED (JERRY_SNAPSHOT_EXEC) #error "JERRY_SNAPSHOT_EXEC must be enabled if JERRY_PARSER is disabled!" #endif /* !ENABLED (JERRY_PARSER) && !ENABLED (JERRY_SNAPSHOT_EXEC) */ @@ -207,7 +228,7 @@ jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */ JERRY_ASSERT (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE)); /* Zero out all non-external members. */ - memset (&JERRY_CONTEXT (JERRY_CONTEXT_FIRST_MEMBER), 0, + memset ((char *) &JERRY_CONTEXT_STRUCT + offsetof (jerry_context_t, JERRY_CONTEXT_FIRST_MEMBER), 0, sizeof (jerry_context_t) - offsetof (jerry_context_t, JERRY_CONTEXT_FIRST_MEMBER)); JERRY_CONTEXT (jerry_init_flags) = flags; @@ -475,8 +496,7 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a ecma_free_value (parse_status); ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_data_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); return ecma_make_object_value (func_obj_p); @@ -557,8 +577,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u ecma_free_value (parse_status); ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_data_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); return ecma_make_object_value (func_obj_p); @@ -602,8 +621,8 @@ jerry_run (const jerry_value_t func_val) /**< function to run */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; - ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_func_p->u.function.scope_cp); + ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + ext_func_p->u.function.scope_cp); if (scope_p != ecma_get_global_environment ()) { @@ -823,6 +842,25 @@ jerry_value_is_promise (const jerry_value_t value) /**< api value */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ } /* jerry_value_is_promise */ +/** + * Check if the specified value is a proxy object. + * + * @return true - if the specified value is a proxy object, + * false - otherwise + */ +bool +jerry_value_is_proxy (const jerry_value_t value) /**< api value */ +{ + jerry_assert_api_available (); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + return (ecma_is_value_object (value) + && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value))); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_UNUSED (value); + return false; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +} /* jerry_value_is_proxy */ + /** * Check if the specified value is string. * @@ -848,12 +886,12 @@ jerry_value_is_symbol (const jerry_value_t value) /**< api value */ { jerry_assert_api_available (); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) return ecma_is_value_symbol (value); -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#else /* !ENABLED (JERRY_ES2015) */ JERRY_UNUSED (value); return false; -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ } /* jerry_value_is_symbol */ /** @@ -907,12 +945,12 @@ jerry_value_get_type (const jerry_value_t value) /**< input value to check */ { return JERRY_TYPE_STRING; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case LIT_MAGIC_STRING_SYMBOL: { return JERRY_TYPE_SYMBOL; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ case LIT_MAGIC_STRING_FUNCTION: { return JERRY_TYPE_FUNCTION; @@ -977,15 +1015,18 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check * #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) || feature == JERRY_FEATURE_PROMISE #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) || feature == JERRY_FEATURE_SYMBOL -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) || feature == JERRY_FEATURE_TYPEDARRAY #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) || feature == JERRY_FEATURE_DATAVIEW #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + || feature == JERRY_FEATURE_PROXY +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ #if ENABLED (JERRY_BUILTIN_DATE) || feature == JERRY_FEATURE_DATE #endif /* ENABLED (JERRY_BUILTIN_DATE) */ @@ -998,6 +1039,18 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check * #if ENABLED (JERRY_LOGGING) || feature == JERRY_FEATURE_LOGGING #endif /* ENABLED (JERRY_LOGGING) */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + || feature == JERRY_FEATURE_MAP +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + || feature == JERRY_FEATURE_SET +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + || feature == JERRY_FEATURE_WEAKMAP +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + || feature == JERRY_FEATURE_WEAKSET +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ ); } /* jerry_is_feature_enabled */ @@ -1056,6 +1109,17 @@ jerry_binary_operation (jerry_binary_operation_t op, /**< operation */ ecma_object_t *proto_obj_p = ecma_get_object_from_value (rhs); return jerry_return (ecma_op_object_has_instance (proto_obj_p, lhs)); } + case JERRY_BIN_OP_ADD: + { + return jerry_return (opfunc_addition (lhs, rhs)); + } + case JERRY_BIN_OP_SUB: + case JERRY_BIN_OP_MUL: + case JERRY_BIN_OP_DIV: + case JERRY_BIN_OP_REM: + { + return jerry_return (do_number_arithmetic (op - ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET, lhs, rhs)); + } default: { return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Unsupported binary operation"))); @@ -1325,7 +1389,13 @@ jerry_value_to_string (const jerry_value_t value) /**< input value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); } - return jerry_return (ecma_op_to_string (value)); + ecma_string_t *str_p = ecma_op_to_string (value); + if (JERRY_UNLIKELY (str_p == NULL)) + { + return ecma_create_error_reference_from_context (); + } + + return jerry_return (ecma_make_string_value (str_p)); } /* jerry_value_to_string */ /** @@ -1582,12 +1652,50 @@ jerry_create_promise (void) jerry_assert_api_available (); #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) - return ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY); + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + + if (old_new_target_p == NULL) + { + JERRY_CONTEXT (current_new_target) = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE); + } + + ecma_value_t promise_value = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY); + + JERRY_CONTEXT (current_new_target) = old_new_target_p; + return promise_value; #else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Promise not supported."))); #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ } /* jerry_create_promise */ +/** + * Create a new Proxy object with the given target and handler + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return value of the created Proxy object + */ +jerry_value_t +jerry_create_proxy (const jerry_value_t target, /**< target argument */ + const jerry_value_t handler) /**< handler argument */ +{ + jerry_assert_api_available (); + + if (ecma_is_value_error_reference (target) + || ecma_is_value_error_reference (handler)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + ecma_object_t *proxy_p = ecma_proxy_create (target, handler); + return jerry_return (proxy_p == NULL ? ECMA_VALUE_ERROR : ecma_make_object_value (proxy_p)); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Proxy is not supported."))); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +} /* jerry_create_proxy */ + /** * Create string from a valid UTF-8 string * @@ -1675,11 +1783,11 @@ jerry_create_symbol (const jerry_value_t value) /**< api value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) return jerry_return (ecma_op_create_symbol (&value, 1)); -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#else /* !ENABLED (JERRY_ES2015) */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Symbol is not supported."))); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ } /* jerry_create_symbol */ /** @@ -1712,11 +1820,20 @@ jerry_create_regexp_sz (const jerry_char_t *pattern_p, /**< zero-terminated UTF- return jerry_throw (ecma_raise_common_error (ECMA_ERR_MSG ("Input must be a valid utf8 string"))); } + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + ecma_string_t *ecma_pattern = ecma_new_ecma_string_from_utf8 (pattern_p, pattern_size); - jerry_value_t ret_val = ecma_op_create_regexp_object (ecma_pattern, flags); - + jerry_value_t ret_val = ecma_op_create_regexp_with_flags (regexp_obj_p, + ecma_make_string_value (ecma_pattern), + flags); ecma_deref_ecma_string (ecma_pattern); + return ret_val; #else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ @@ -1741,18 +1858,19 @@ jerry_get_array_length (const jerry_value_t value) /**< api value */ { jerry_assert_api_available (); - if (!jerry_value_is_array (value)) + if (!jerry_value_is_object (value)) { return 0; } - ecma_value_t len_value = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (value), - LIT_MAGIC_STRING_LENGTH); + ecma_object_t *object_p = ecma_get_object_from_value (value); - jerry_length_t length = ecma_number_to_uint32 (ecma_get_number_from_value (len_value)); - ecma_free_value (len_value); + if (JERRY_LIKELY (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY)) + { + return ecma_array_get_length (object_p); + } - return length; + return 0; } /* jerry_get_array_length */ /** @@ -1988,8 +2106,8 @@ jerry_substring_to_utf8_char_buffer (const jerry_value_t value, /**< input strin /** * Checks whether the object or it's prototype objects have the given property. * - * @return true - if the property exists - * false - otherwise + * @return raised error - if the operation fail + * true/false API value - depend on whether the property exists */ jerry_value_t jerry_has_property (const jerry_value_t obj_val, /**< object value */ @@ -2003,17 +2121,15 @@ jerry_has_property (const jerry_value_t obj_val, /**< object value */ return ECMA_VALUE_FALSE; } - bool has_property = ecma_op_object_has_property (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val)); - - return ecma_make_boolean_value (has_property); + return ecma_op_object_has_property (ecma_get_object_from_value (obj_val), + ecma_get_prop_name_from_value (prop_name_val)); } /* jerry_has_property */ /** * Checks whether the object has the given property. * - * @return true - if the property exists - * false - otherwise + * @return ECMA_VALUE_ERROR - if the operation raises error + * ECMA_VALUE_{TRUE, FALSE} - based on whether the property exists */ jerry_value_t jerry_has_own_property (const jerry_value_t obj_val, /**< object value */ @@ -2027,12 +2143,68 @@ jerry_has_own_property (const jerry_value_t obj_val, /**< object value */ return ECMA_VALUE_FALSE; } - bool has_property = ecma_op_object_has_own_property (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val)); + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (prop_name_val); - return ecma_make_boolean_value (has_property); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_property_descriptor_t prop_desc; + + ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + } + + return jerry_return (status); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p)); } /* jerry_has_own_property */ +/** + * Checks whether the object has the given internal property. + * + * @return true - if the internal property exists + * false - otherwise + */ +bool +jerry_has_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_op_object_is_fast_array (obj_p)) + { + return false; + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return false; + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + return property_p != NULL; +} /* jerry_has_internal_property */ + /** * Delete a property from an object. * @@ -2054,6 +2226,15 @@ jerry_delete_property (const jerry_value_t obj_val, /**< object value */ ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_val), ecma_get_prop_name_from_value (prop_name_val), false); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return ecma_is_value_true (ret_value); } /* jerry_delete_property */ @@ -2080,9 +2261,64 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, /**< object value * false); ecma_deref_ecma_string (str_idx_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return ecma_is_value_true (ret_value); } /* jerry_delete_property_by_index */ +/** + * Delete an internal property from an object. + * + * @return true - if property was deleted successfully + * false - otherwise + */ +bool +jerry_delete_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_op_object_is_fast_array (obj_p)) + { + return true; + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return true; + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + if (property_p == NULL) + { + return true; + } + + ecma_delete_property (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p)); + + return true; +} /* jerry_delete_internal_property */ + /** * Get value of a property to the specified object with the given name. * @@ -2129,13 +2365,60 @@ jerry_get_property_by_index (const jerry_value_t obj_val, /**< object value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_val), str_idx_p); - ecma_deref_ecma_string (str_idx_p); + ecma_value_t ret_value = ecma_op_object_get_by_uint32_index (ecma_get_object_from_value (obj_val), index); return jerry_return (ret_value); } /* jerry_get_property_by_index */ +/** + * Get value of an internal property to the specified object with the given name. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return value of the internal property - if the internal property exists + * undefined value - if the internal does not property exists + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_get_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_op_object_is_fast_array (obj_p)) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + if (property_p == NULL) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + return jerry_return (ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); +} /* jerry_get_internal_property */ + /** * Set a property to the specified object with the given name. * @@ -2187,16 +2470,95 @@ jerry_set_property_by_index (const jerry_value_t obj_val, /**< object value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 ((uint32_t) index); - ecma_value_t ret_value = ecma_op_object_put (ecma_get_object_from_value (obj_val), - str_idx_p, - value_to_set, - true); - ecma_deref_ecma_string (str_idx_p); + ecma_value_t ret_value = ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (obj_val), + index, + value_to_set, + true); return jerry_return (ret_value); } /* jerry_set_property_by_index */ +/** + * Set an internal property to the specified object with the given name. + * + * Note: + * - the property cannot be accessed from the JavaScript context, only from the public API + * - returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return true value - if the operation was successful + * value marked with error flag - otherwise + */ +bool +jerry_set_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val, /**< property name value */ + const jerry_value_t value_to_set) /**< value to set */ +{ + jerry_assert_api_available (); + + if (ecma_is_value_error_reference (value_to_set) + || !ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_fast_array_convert_to_normal (obj_p); + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + ecma_object_t *internal_object_p; + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (obj_p, + internal_string_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + internal_object_p = ecma_create_object (NULL, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + { + ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p; + container_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT; + container_p->u.class_prop.extra_info = 0; + container_p->u.class_prop.u.length = 0; + } + + value_p->value = ecma_make_object_value (internal_object_p); + ecma_deref_object (internal_object_p); + } + else + { + internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + } + + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (prop_name_val); + property_p = ecma_find_named_property (internal_object_p, prop_name_p); + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (internal_object_p, + prop_name_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + value_p->value = ecma_copy_value_if_not_object (value_to_set); + } + else + { + ecma_named_data_property_assign_value (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p), value_to_set); + } + + return true; +} /* jerry_set_internal_property */ + /** * Initialize property descriptor. */ @@ -2257,8 +2619,8 @@ jerry_define_own_property (const jerry_value_t obj_val, /**< object value */ if (prop_desc_p->is_configurable_defined) { - flags |= (uint32_t) (ECMA_PROP_IS_CONFIGURABLE_DEFINED | (prop_desc_p->is_enumerable ? ECMA_PROP_IS_CONFIGURABLE - : ECMA_PROP_NO_OPTS)); + flags |= (uint32_t) (ECMA_PROP_IS_CONFIGURABLE_DEFINED | (prop_desc_p->is_configurable ? ECMA_PROP_IS_CONFIGURABLE + : ECMA_PROP_NO_OPTS)); } /* Copy data property info. */ @@ -2349,9 +2711,19 @@ jerry_get_own_property_descriptor (const jerry_value_t obj_val, /**< object val ecma_property_descriptor_t prop_desc; - if (!ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val), - &prop_desc)) + ecma_value_t status = ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_val), + ecma_get_prop_name_from_value (prop_name_val), + &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (!ecma_is_value_true (status)) { return false; } @@ -2466,7 +2838,7 @@ jerry_invoke_function (bool is_invoke_as_constructor, /**< true - invoke functio JERRY_ASSERT (jerry_value_is_constructor (func_obj_val)); return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_obj_val), - ECMA_VALUE_UNDEFINED, + ecma_get_object_from_value (func_obj_val), args_p, args_count)); } @@ -2506,8 +2878,16 @@ jerry_call_function (const jerry_value_t func_obj_val, /**< function object to c } #endif - if (jerry_value_is_function (func_obj_val)) + if (jerry_value_is_function (func_obj_val) && !ecma_is_value_error_reference (this_val)) { + for (jerry_size_t i = 0; i < args_count; i++) + { + if (ecma_is_value_error_reference (args_p[i])) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + } + return jerry_invoke_function (false, func_obj_val, this_val, args_p, args_count); } @@ -2533,6 +2913,14 @@ jerry_construct_object (const jerry_value_t func_obj_val, /**< function object t if (jerry_value_is_constructor (func_obj_val)) { + for (jerry_size_t i = 0; i < args_count; i++) + { + if (ecma_is_value_error_reference (args_p[i])) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + } + ecma_value_t this_val = ECMA_VALUE_UNDEFINED; return jerry_invoke_function (true, func_obj_val, this_val, args_p, args_count); } @@ -2566,6 +2954,9 @@ jerry_get_object_keys (const jerry_value_t obj_val) /**< object value */ /** * Get the prototype of the specified object * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * * @return prototype object or null value - if success * value marked with error flag - otherwise */ @@ -2581,12 +2972,20 @@ jerry_get_prototype (const jerry_value_t obj_val) /**< object value */ ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return jerry_return (ecma_proxy_object_get_prototype_of (obj_p)); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (obj_p->u2.prototype_cp == JMEM_CP_NULL) { return ECMA_VALUE_NULL; } ecma_object_t *proto_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_p->u2.prototype_cp); + ecma_ref_object (proto_obj_p); return ecma_make_object_value (proto_obj_p); } /* jerry_get_prototype */ @@ -2611,17 +3010,47 @@ jerry_set_prototype (const jerry_value_t obj_val, /**< object value */ } ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); - if (ecma_is_value_null (proto_obj_val)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) { - obj_p->u2.prototype_cp = JMEM_CP_NULL; + return jerry_return (ecma_proxy_object_set_prototype_of (obj_p, proto_obj_val)); } - else +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_op_ordinary_object_set_prototype_of (obj_p, proto_obj_val); +} /* jerry_set_prototype */ + +/** + * Utility to check if a given object can be used for the foreach api calls. + * + * Some objects/classes uses extra internal objects to correctly store data. + * These extre object should never be exposed externally to the API user. + * + * @returns true - if the user can access the object in the callback. + * false - if the object is an internal object which should no be accessed by the user. + */ +static +bool jerry_object_is_valid_foreach (ecma_object_t *object_p) /**< object to test */ +{ + if (ecma_is_lexical_environment (object_p)) { - ECMA_SET_NON_NULL_POINTER (obj_p->u2.prototype_cp, ecma_get_object_from_value (proto_obj_val)); + return false; } - return ECMA_VALUE_TRUE; -} /* jerry_set_prototype */ + ecma_object_type_t object_type = ecma_get_object_type (object_p); + + if (object_type == ECMA_OBJECT_TYPE_CLASS) + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + switch (ext_object_p->u.class_prop.class_id) + { + /* An object's internal property object should not be iterable by foreach. */ + case LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT: return false; + } + } + + return true; +} /* jerry_object_is_valid_foreach */ /** * Traverse objects. @@ -2643,7 +3072,7 @@ jerry_objects_foreach (jerry_objects_foreach_t foreach_p, /**< function pointer { ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp); - if (!ecma_is_lexical_environment (iter_p) + if (jerry_object_is_valid_foreach (iter_p) && !foreach_p (ecma_make_object_value (iter_p), user_data_p)) { return true; @@ -2675,14 +3104,13 @@ jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_i ecma_native_pointer_t *native_pointer_p; - jmem_cpointer_t iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp); while (iter_cp != JMEM_CP_NULL) { ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp); - if (!ecma_is_lexical_environment (iter_p)) + if (jerry_object_is_valid_foreach (iter_p)) { native_pointer_p = ecma_get_native_pointer_value (iter_p, (void *) native_info_p); if (native_pointer_p @@ -2746,7 +3174,7 @@ jerry_get_object_native_pointer (const jerry_value_t obj_val, /**< object to get * Note: * If a non-NULL free callback is specified in the native type info, * it will be called by the garbage collector when the object is freed. - * This callback **must not** invoke API functions. + * Referred values by this method must have at least 1 reference. (Correct API usage satisfies this condition) * The type info always overwrites the previous value, so passing * a NULL value deletes the current type info. */ @@ -2817,6 +3245,16 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ ecma_object_t *object_p = ecma_get_object_from_value (obj_val); ecma_collection_t *names_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE_PROTOTYPE); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (names_p == NULL) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + return false; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = names_p->buffer_p; ecma_value_t property_value = ECMA_VALUE_EMPTY; @@ -2845,7 +3283,7 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ return true; } - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return false; } /* jerry_foreach_object_property */ @@ -2868,6 +3306,11 @@ jerry_resolve_or_reject_promise (jerry_value_t promise, /**< the promise value * return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } + if (ecma_is_value_error_reference (argument)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + lit_magic_string_id_t prop_name = (is_resolve ? LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION : LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); @@ -2890,6 +3333,58 @@ jerry_resolve_or_reject_promise (jerry_value_t promise, /**< the promise value * #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ } /* jerry_resolve_or_reject_promise */ +/** + * Get the result of a promise. + * + * @return - Promise result + * - Type error if the promise support was not enabled or the input was not a promise object + */ +jerry_value_t +jerry_get_promise_result (const jerry_value_t promise) /**< promise object to get the result from */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) + if (!jerry_value_is_promise (promise)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + + return ecma_promise_get_result (ecma_get_object_from_value (promise)); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ + JERRY_UNUSED (promise); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Promise not supported."))); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ +} /* jerry_get_promise_result */ + +/** + * Get the state of a promise object. + * + * @return - the state of the promise (one of the jerry_promise_state_t enum values) + * - JERRY_PROMISE_STATE_NONE is only returned if the input is not a promise object + * or the promise support was not enabled. + */ +jerry_promise_state_t +jerry_get_promise_state (const jerry_value_t promise) /**< promise object to get the state from */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) + if (!jerry_value_is_promise (promise)) + { + return JERRY_PROMISE_STATE_NONE; + } + + uint16_t flags = ecma_promise_get_flags (ecma_get_object_from_value (promise)); + flags &= (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED); + + return (flags ? flags : JERRY_PROMISE_STATE_REJECTED); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ + JERRY_UNUSED (promise); + return JERRY_PROMISE_STATE_NONE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ +} /* jerry_get_promise_state */ + /** * Call the SymbolDescriptiveString ecma builtin operation on the symbol value. * @@ -2904,7 +3399,7 @@ jerry_get_symbol_descriptive_string (const jerry_value_t symbol) /**< symbol val { jerry_assert_api_available (); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (!ecma_is_value_symbol (symbol)) { return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); @@ -2912,11 +3407,11 @@ jerry_get_symbol_descriptive_string (const jerry_value_t symbol) /**< symbol val /* Note: This operation cannot throw an error */ return ecma_get_symbol_descriptive_string (symbol); -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#else /* !ENABLED (JERRY_ES2015) */ JERRY_UNUSED (symbol); return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Symbol is not supported."))); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ } /** jerry_get_symbol_descriptive_string */ /** @@ -3083,6 +3578,77 @@ jerry_get_backtrace (uint32_t max_depth) /**< depth limit of the backtrace */ return vm_get_backtrace (max_depth); } /* jerry_get_backtrace */ +/** + * Get the resource name (usually a file name) of the currently executed script or the given function object + * + * Note: returned value must be freed with jerry_release_value, when it is no longer needed + * + * @return JS string constructed from + * - the currently executed function object's resource name, if the given value is undefined + * - resource name of the function object, if the given value is a function object + * - "", otherwise + */ +jerry_value_t +jerry_get_resource_name (const jerry_value_t value) /**< jerry api value */ +{ +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (ecma_is_value_undefined (value)) + { + if (JERRY_CONTEXT (vm_top_context_p) != NULL) + { + return ecma_copy_value (JERRY_CONTEXT (vm_top_context_p)->resource_name); + } + } +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) + else if (ecma_is_value_object (value)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (value); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION + && !ecma_get_object_is_builtin (obj_p)) + { + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) obj_p; + + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); + + return ecma_copy_value (ecma_op_resource_name (bytecode_data_p)); + } + } +#endif /* ENABLED (JERRY_LINE_INFO) */ + + JERRY_UNUSED (value); + return ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); +} /* jerry_get_resource_name */ + +/** + * Access the "new.target" value. + * + * The "new.target" value depends on the current call site. That is + * this method will only have a function object result if, at the call site + * it was called inside a constructor method invoked with "new". + * + * @return "undefined" - if at the call site it was not a constructor call. + * function object - if the current call site is in a constructor call. + */ +jerry_value_t +jerry_get_new_target (void) +{ +#if ENABLED (JERRY_ES2015) + ecma_object_t *current_new_target = JERRY_CONTEXT (current_new_target); + + if (current_new_target == NULL) + { + return jerry_create_undefined (); + } + + ecma_ref_object (current_new_target); + return ecma_make_object_value (current_new_target); +#else /* !ENABLED (JERRY_ES2015) */ + return jerry_create_undefined (); +#endif /* ENABLED (JERRY_ES2015) */ +} /* jerry_get_new_target */ + /** * Check if the given value is an ArrayBuffer object. * @@ -3132,7 +3698,7 @@ jerry_create_arraybuffer (const jerry_length_t size) /**< size of the ArrayBuffe * * the size is specified in bytes. * * the buffer passed should be at least the specified bytes big. * * if the typed arrays are disabled this will return a TypeError. - * * if the size is zero or the buffer_p is a null pointer this will return a RangeError. + * * if the size is zero or buffer_p is a null pointer this will return an empty ArrayBuffer. * * @return value of the construced ArrayBuffer object */ @@ -3144,14 +3710,19 @@ jerry_create_arraybuffer_external (const jerry_length_t size, /**< size of the b jerry_assert_api_available (); #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) - if (size == 0 || buffer_p == NULL) + ecma_object_t *arraybuffer; + + if (JERRY_UNLIKELY (size == 0 || buffer_p == NULL)) { - return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("invalid buffer size or storage reference"))); + arraybuffer = ecma_arraybuffer_new_object_external (0, NULL, (ecma_object_native_free_callback_t) free_cb); + } + else + { + arraybuffer = ecma_arraybuffer_new_object_external (size, + buffer_p, + (ecma_object_native_free_callback_t) free_cb); } - ecma_object_t *arraybuffer = ecma_arraybuffer_new_object_external (size, - buffer_p, - (ecma_object_native_free_callback_t) free_cb); return jerry_return (ecma_make_object_value (arraybuffer)); #else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ JERRY_UNUSED (size); @@ -3316,6 +3887,59 @@ jerry_get_arraybuffer_pointer (const jerry_value_t array_buffer) /**< Array Buff return NULL; } /* jerry_get_arraybuffer_pointer */ +/** + * Get if the ArrayBuffer is detachable. + * + * @return boolean value - if success + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_is_arraybuffer_detachable (const jerry_value_t value) /**< ArrayBuffer */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_arraybuffer (value)) + { + ecma_object_t *buffer_p = ecma_get_object_from_value (value); + return ecma_arraybuffer_is_detachable (buffer_p) ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE; + } +#else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + JERRY_UNUSED (value); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects an ArrayBuffer"))); +} /* jerry_is_arraybuffer_detachable */ + +/** + * Detach the underlying data block from ArrayBuffer and set its bytelength to 0. + * This operation requires the ArrayBuffer to be external that created by + * `jerry_create_arraybuffer_external`. + * + * @return null value - if success + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_detach_arraybuffer (const jerry_value_t value) /**< ArrayBuffer */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_arraybuffer (value)) + { + ecma_object_t *buffer_p = ecma_get_object_from_value (value); + bool detached = ecma_arraybuffer_detach (buffer_p); + if (!detached) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects a detachable ArrayBuffer."))); + } + return ECMA_VALUE_NULL; + } +#else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + JERRY_UNUSED (value); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects an ArrayBuffer"))); +} /* jerry_detach_arraybuffer */ + /** * DataView related functions */ @@ -3371,15 +3995,7 @@ jerry_value_is_dataview (const jerry_value_t value) /**< value to check if it is jerry_assert_api_available (); #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) - if (!ecma_is_value_object (value)) - { - return false; - } - - ecma_dataview_object_t *dataview_object_p = (ecma_dataview_object_t *) ecma_get_object_from_value (value); - - return (ecma_get_object_type (&dataview_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS - && dataview_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_DATAVIEW_UL); + return ecma_is_dataview (value); #else /* !ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ JERRY_UNUSED (value); return false; @@ -3561,6 +4177,7 @@ jerry_create_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedAr ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id); ecma_value_t array_value = ecma_typedarray_create_object_with_length (length, + NULL, prototype_obj_p, element_size_shift, id); @@ -3593,6 +4210,11 @@ jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, / jerry_assert_api_available (); #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_value_error_reference (arraybuffer)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + ecma_builtin_id_t prototype_id = 0; ecma_typedarray_type_t id = 0; uint8_t element_size_shift = 0; @@ -3645,6 +4267,11 @@ jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name, /**< jerry_assert_api_available (); #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_value_error_reference (arraybuffer)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + jerry_length_t byteLength = jerry_get_arraybuffer_byte_length (arraybuffer); return jerry_create_typedarray_for_arraybuffer_sz (type_name, arraybuffer, 0, byteLength); #else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ @@ -3804,6 +4431,11 @@ jerry_json_stringify (const jerry_value_t object_to_stringify) /**< a jerry_obje #if ENABLED (JERRY_BUILTIN_JSON) ecma_value_t ret_value = ecma_builtin_json_string_from_object (object_to_stringify); + if (ecma_is_value_error_reference (object_to_stringify)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + if (ecma_is_value_undefined (ret_value)) { ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON stringify error."))); @@ -3817,6 +4449,158 @@ jerry_json_stringify (const jerry_value_t object_to_stringify) /**< a jerry_obje #endif /* ENABLED (JERRY_BUILTIN_JSON) */ } /* jerry_json_stringify */ +/** + * Create a container type specified in jerry_container_type_t. + * The container can be created with a list of arguments, which will be passed to the container constructor to be + * inserted to the container. + * + * Note: + * The returned value must be freed with jerry_release_value + * @return jerry_value_t representing a container with the given type. + */ +jerry_value_t +jerry_create_container (jerry_container_type_t container_type, /**< Type of the container */ + const jerry_value_t *arguments_list_p, /**< arguments list */ + jerry_length_t arguments_list_len) /**< Length of arguments list */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) + for (jerry_length_t i = 0; i < arguments_list_len; i++) + { + if (ecma_is_value_error_reference (arguments_list_p[i])) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); + } + } + + lit_magic_string_id_t lit_id; + ecma_builtin_id_t proto_id; + ecma_builtin_id_t ctor_id; + + switch (container_type) + { +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case JERRY_CONTAINER_TYPE_MAP: + { + lit_id = LIT_MAGIC_STRING_MAP_UL; + proto_id = ECMA_BUILTIN_ID_MAP_PROTOTYPE; + ctor_id = ECMA_BUILTIN_ID_MAP; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case JERRY_CONTAINER_TYPE_SET: + { + lit_id = LIT_MAGIC_STRING_SET_UL; + proto_id = ECMA_BUILTIN_ID_SET_PROTOTYPE; + ctor_id = ECMA_BUILTIN_ID_SET; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case JERRY_CONTAINER_TYPE_WEAKMAP: + { + lit_id = LIT_MAGIC_STRING_WEAKMAP_UL; + proto_id = ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE; + ctor_id = ECMA_BUILTIN_ID_WEAKMAP; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case JERRY_CONTAINER_TYPE_WEAKSET: + { + lit_id = LIT_MAGIC_STRING_WEAKSET_UL; + proto_id = ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE; + ctor_id = ECMA_BUILTIN_ID_WEAKSET; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + default: + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Invalid container type."))); + } + } + ecma_object_t * old_new_target_p = JERRY_CONTEXT (current_new_target); + + if (old_new_target_p == NULL) + { + JERRY_CONTEXT (current_new_target) = ecma_builtin_get (ctor_id); + } + + ecma_value_t container_value = ecma_op_container_create (arguments_list_p, + arguments_list_len, + lit_id, + proto_id); + + JERRY_CONTEXT (current_new_target) = old_new_target_p; + return container_value; +#else /* !ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ + JERRY_UNUSED (arguments_list_p); + JERRY_UNUSED (arguments_list_len); + JERRY_UNUSED (container_type); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Containers are disabled."))); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ +} /* jerry_create_container */ + +/** + * Get the type of the given container object. + * + * @return Corresponding type to the given container object. + */ +jerry_container_type_t +jerry_get_container_type (const jerry_value_t value) /**< the container object */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) + if (ecma_is_value_object (value)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (value); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_CLASS) + { + uint16_t type = ((ecma_extended_object_t *) obj_p)->u.class_prop.class_id; + + switch (type) + { +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case LIT_MAGIC_STRING_MAP_UL: + { + return JERRY_CONTAINER_TYPE_MAP; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case LIT_MAGIC_STRING_SET_UL: + { + return JERRY_CONTAINER_TYPE_SET; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: + { + return JERRY_CONTAINER_TYPE_WEAKMAP; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: + { + return JERRY_CONTAINER_TYPE_WEAKSET; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + default: + { + return JERRY_CONTAINER_TYPE_INVALID; + } + } + } + } + +#else /* !ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ + JERRY_UNUSED (value); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ + return JERRY_CONTAINER_TYPE_INVALID; +} /* jerry_get_container_type */ #if defined(JERRY_HEAPDUMP) void JerryHeapdumpRun(const char* filepath) diff --git a/jerry-core/api/jerryscript_adapter.c b/jerry-core/api/jerryscript_adapter.c index 24db4294..ab976dc3 100644 --- a/jerry-core/api/jerryscript_adapter.c +++ b/jerry-core/api/jerryscript_adapter.c @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef JERRY_IAR_JUPITER - -#include "jerryscript.h" -#include "jmem.h" -#include "config-jupiter.h" - -uint8_t* input_buffer; -uint8_t* snapshot_buffer; -uint8_t* bms_context_and_heap; -uint8_t* js_context_and_heap; - -void JerryPsRamMemInit() -{ - // memory for js task - js_context_and_heap = OhosMalloc(MEM_TYPE_JERRY_LSRAM, JS_TASK_CONTEXT_AND_HEAP_SIZE_BYTE); -} - -void JerryBmsPsRamMemInit() -{ - // memory for input_js file, snapshot file and bms task - input_buffer = OhosMalloc(MEM_TYPE_JERRY_LSRAM, INPUTJS_BUFFER_SIZE); - snapshot_buffer = OhosMalloc(MEM_TYPE_JERRY_LSRAM, SNAPSHOT_BUFFER_SIZE); - bms_context_and_heap = OhosMalloc(MEM_TYPE_JERRY_LSRAM, BMS_TASK_CONTEXT_AND_HEAP_SIZE * CONVERTION_RATIO); -} - -#endif // JERRY_IAR_JUPITER +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef JERRY_IAR_JUPITER + +#include "jerryscript.h" +#include "jmem.h" +#include "config-jupiter.h" + +uint8_t* input_buffer; +uint8_t* snapshot_buffer; +uint8_t* bms_context_and_heap; +uint8_t* js_context_and_heap; + +void JerryPsRamMemInit() +{ + // memory for js task + js_context_and_heap = OhosMalloc(MEM_TYPE_JERRY_LSRAM, JS_TASK_CONTEXT_AND_HEAP_SIZE_BYTE); +} + +void JerryBmsPsRamMemInit() +{ + // memory for input_js file, snapshot file and bms task + input_buffer = OhosMalloc(MEM_TYPE_JERRY_LSRAM, INPUTJS_BUFFER_SIZE); + snapshot_buffer = OhosMalloc(MEM_TYPE_JERRY_LSRAM, SNAPSHOT_BUFFER_SIZE); + bms_context_and_heap = OhosMalloc(MEM_TYPE_JERRY_LSRAM, BMS_TASK_CONTEXT_AND_HEAP_SIZE * CONVERTION_RATIO); +} + +#endif // JERRY_IAR_JUPITER diff --git a/jerry-core/config.h b/jerry-core/config.h index cf375a7c..43a131d4 100755 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -33,7 +33,7 @@ #ifndef JERRY_FOR_IAR_CONFIG # define JERRY_MEM_STATS 1 # define JERRY_LOGGING 1 -#endif +#endif /* JERRY_FOR_IAR_CONFIG */ #ifndef JERRY_GLOBAL_HEAP_SIZE //Maximum size of heap in kilobytes @@ -44,7 +44,14 @@ // disable builtin eval() function # define JERRY_BUILTIN_EVAL_DISABLED 1 #endif -#endif /* JERRY_FOR_IAR_CONFIG */ + +#if defined (__linux__) +#ifndef JERRY_SNAPSHOT_SAVE +# define JERRY_SNAPSHOT_SAVE 1 +#endif +#endif /* binary tool compiling in linux platform */ + +#endif /* !defined(_WIN32) && !defined(_WIN64) */ /* * Here define the special config for Win simulator build. @@ -64,9 +71,9 @@ # define JERRY_MEM_STATS 1 # define JERRY_SNAPSHOT_EXEC 1 # define JERRY_SNAPSHOT_SAVE 1 -# ifndef JERRY_LOGGING -# define JERRY_LOGGING 1 -# endif +#ifndef JERRY_LOGGING +# define JERRY_LOGGING 1 +#endif // following config controls temp changes in jerry for debugger function with IDE # define ACE_DEBUGGER_CUSTOM @@ -144,18 +151,10 @@ # define JERRY_ES2015 1 #endif /* !defined (JERRY_ES2015) */ -#ifndef JERRY_ES2015_BUILTIN -# define JERRY_ES2015_BUILTIN JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_BUILTIN) */ - #ifndef JERRY_ES2015_BUILTIN_DATAVIEW # define JERRY_ES2015_BUILTIN_DATAVIEW JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_DATAVIEW) */ -#ifndef JERRY_ES2015_BUILTIN_ITERATOR -# define JERRY_ES2015_BUILTIN_ITERATOR JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_BUILTIN_ITERATOR) */ - #ifndef JERRY_ES2015_BUILTIN_MAP # define JERRY_ES2015_BUILTIN_MAP JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_MAP) */ @@ -164,50 +163,34 @@ # define JERRY_ES2015_BUILTIN_SET JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_SET) */ +#ifndef JERRY_ES2015_BUILTIN_WEAKMAP +# define JERRY_ES2015_BUILTIN_WEAKMAP JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#ifndef JERRY_ES2015_BUILTIN_WEAKSET +# define JERRY_ES2015_BUILTIN_WEAKSET JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_WEAKSET) */ + #ifndef JERRY_ES2015_BUILTIN_PROMISE # define JERRY_ES2015_BUILTIN_PROMISE JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_PROMISE) */ -#ifndef JERRY_ES2015_BUILTIN_SYMBOL -# define JERRY_ES2015_BUILTIN_SYMBOL JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_BUILTIN_SYMBOL) */ +#ifndef JERRY_ES2015_BUILTIN_PROXY +# define JERRY_ES2015_BUILTIN_PROXY JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_PROXY) */ + +#ifndef JERRY_ES2015_BUILTIN_REFLECT +# define JERRY_ES2015_BUILTIN_REFLECT JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_REFLECT) */ #ifndef JERRY_ES2015_BUILTIN_TYPEDARRAY # define JERRY_ES2015_BUILTIN_TYPEDARRAY JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ -#ifndef JERRY_ES2015_ARROW_FUNCTION -# define JERRY_ES2015_ARROW_FUNCTION JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_ARROW_FUNCTION) */ - -#ifndef JERRY_ES2015_CLASS -# define JERRY_ES2015_CLASS JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_CLASS) */ - -#ifndef JERRY_ES2015_FOR_OF -# define JERRY_ES2015_FOR_OF JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_FOR_OF) */ - -#ifndef JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER -# define JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - -#ifndef JERRY_ES2015_FUNCTION_REST_PARAMETER -# define JERRY_ES2015_FUNCTION_REST_PARAMETER JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - -#ifndef JERRY_ES2015_OBJECT_INITIALIZER -# define JERRY_ES2015_OBJECT_INITIALIZER JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_OBJECT_INITIALIZER) */ - #ifndef JERRY_ES2015_MODULE_SYSTEM # define JERRY_ES2015_MODULE_SYSTEM JERRY_ES2015 #endif /* !defined (JERRY_ES2015_MODULE_SYSTEM) */ -#ifndef JERRY_ES2015_TEMPLATE_STRINGS -# define JERRY_ES2015_TEMPLATE_STRINGS JERRY_ES2015 -#endif /* !defined (JERRY_ES2015_TEMPLATE_STRINGS) */ - /** * Engine internal and misc configurations. */ @@ -294,6 +277,15 @@ # define JERRY_STACK_LIMIT (0) #endif /* !defined (JERRY_STACK_LIMIT) */ +/** + * Maximum depth of recursion during GC mark phase + * + * Default value: 8 + */ +#ifndef JERRY_GC_MARK_LIMIT +# define JERRY_GC_MARK_LIMIT (8) +#endif /* !defined (JERRY_GC_MARK_LIMIT) */ + /** * Enable/Disable property lookup cache. * @@ -539,7 +531,6 @@ # define JERRY_ATTR_GLOBAL_HEAP #endif /* !defined (JERRY_ATTR_GLOBAL_HEAP) */ - /** * Sanity check for macros to see if the values are 0 or 1 * @@ -600,18 +591,6 @@ || ((JERRY_ES2015 != 0) && (JERRY_ES2015 != 1)) # error "Invalid value for JERRY_ES2015 macro." #endif -#if !defined (JERRY_ES2015_ARROW_FUNCTION) \ -|| ((JERRY_ES2015_ARROW_FUNCTION != 0) && (JERRY_ES2015_ARROW_FUNCTION != 1)) -# error "Invalid value for JERRY_ES2015_ARROW_FUNCTION macro." -#endif -#if !defined (JERRY_ES2015_BUILTIN) \ -|| ((JERRY_ES2015_BUILTIN != 0) && (JERRY_ES2015_BUILTIN != 1)) -# error "Invalid value for JERRY_ES2015_BUILTIN macro." -#endif -#if !defined (JERRY_ES2015_BUILTIN_ITERATOR) \ -|| ((JERRY_ES2015_BUILTIN_ITERATOR != 0) && (JERRY_ES2015_BUILTIN_ITERATOR != 1)) -# error "Invalid value for JERRY_ES2015_BUILTIN_ITERATOR macro." -#endif #if !defined (JERRY_ES2015_BUILTIN_DATAVIEW) \ || ((JERRY_ES2015_BUILTIN_DATAVIEW != 0) && (JERRY_ES2015_BUILTIN_DATAVIEW != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_DATAVIEW macro." @@ -620,50 +599,38 @@ || ((JERRY_ES2015_BUILTIN_MAP != 0) && (JERRY_ES2015_BUILTIN_MAP != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_MAP macro." #endif +#if !defined (JERRY_ES2015_BUILTIN_REFLECT) \ +|| ((JERRY_ES2015_BUILTIN_REFLECT != 0) && (JERRY_ES2015_BUILTIN_REFLECT != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_REFLECT macro." +#endif #if !defined (JERRY_ES2015_BUILTIN_SET) \ || ((JERRY_ES2015_BUILTIN_SET != 0) && (JERRY_ES2015_BUILTIN_SET != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_SET macro." #endif +#if !defined (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ((JERRY_ES2015_BUILTIN_WEAKMAP != 0) && (JERRY_ES2015_BUILTIN_WEAKMAP != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_WEAKMAP macro." +#endif +#if !defined (JERRY_ES2015_BUILTIN_WEAKSET) \ +|| ((JERRY_ES2015_BUILTIN_WEAKSET != 0) && (JERRY_ES2015_BUILTIN_WEAKSET != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_WEAKSET macro." +#endif #if !defined (JERRY_ES2015_BUILTIN_PROMISE) \ || ((JERRY_ES2015_BUILTIN_PROMISE != 0) && (JERRY_ES2015_BUILTIN_PROMISE != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_PROMISE macro." #endif -#if !defined (JERRY_ES2015_BUILTIN_SYMBOL) \ -|| ((JERRY_ES2015_BUILTIN_SYMBOL != 0) && (JERRY_ES2015_BUILTIN_SYMBOL != 1)) -# error "Invalid value for JERRY_ES2015_BUILTIN_SYMBOL macro." +#if !defined (JERRY_ES2015_BUILTIN_PROXY) \ +|| ((JERRY_ES2015_BUILTIN_PROXY != 0) && (JERRY_ES2015_BUILTIN_PROXY != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_PROXY macro." #endif #if !defined (JERRY_ES2015_BUILTIN_TYPEDARRAY) \ || ((JERRY_ES2015_BUILTIN_TYPEDARRAY != 0) && (JERRY_ES2015_BUILTIN_TYPEDARRAY != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_TYPEDARRAY macro." #endif -#if !defined (JERRY_ES2015_CLASS) \ -|| ((JERRY_ES2015_CLASS != 0) && (JERRY_ES2015_CLASS != 1)) -# error "Invalid value for JERRY_ES2015_CLASS macro." -#endif -#if !defined (JERRY_ES2015_FOR_OF) \ -|| ((JERRY_ES2015_FOR_OF != 0) && (JERRY_ES2015_FOR_OF != 1)) -# error "Invalid value for JERRY_ES2015_FOR_OF macro." -#endif -#if !defined (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) \ -|| ((JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER != 0) && (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER != 1)) -# error "Invalid value for JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER macro." -#endif -#if !defined (JERRY_ES2015_FUNCTION_REST_PARAMETER) \ -|| ((JERRY_ES2015_FUNCTION_REST_PARAMETER != 0) && (JERRY_ES2015_FUNCTION_REST_PARAMETER != 1)) -# error "Invalid value for JERRY_ES2015_FUNCTION_REST_PARAMETER macro." -#endif -#if !defined (JERRY_ES2015_OBJECT_INITIALIZER) \ -|| ((JERRY_ES2015_OBJECT_INITIALIZER != 0) && (JERRY_ES2015_OBJECT_INITIALIZER != 1)) -# error "Invalid value for JERRY_ES2015_OBJECT_INITIALIZER macro." -#endif #if !defined (JERRY_ES2015_MODULE_SYSTEM) \ || ((JERRY_ES2015_MODULE_SYSTEM != 0) && (JERRY_ES2015_MODULE_SYSTEM != 1)) # error "Invalid value for JERRY_ES2015_MODULE_SYSTEM macro." #endif -#if !defined (JERRY_ES2015_TEMPLATE_STRINGS) \ -|| ((JERRY_ES2015_TEMPLATE_STRINGS != 0) && (JERRY_ES2015_TEMPLATE_STRINGS != 1)) -# error "Invalid value for JERRY_ES2015_TEMPLATE_STRINGS macro." -#endif /** * Internal options. @@ -693,6 +660,9 @@ #if !defined (JERRY_STACK_LIMIT) || (JERRY_STACK_LIMIT < 0) # error "Invalid value for 'JERRY_STACK_LIMIT' macro." #endif +#if !defined (JERRY_GC_MARK_LIMIT) || (JERRY_GC_MARK_LIMIT < 0) +# error "Invalid value for 'JERRY_GC_MARK_LIMIT' macro." +#endif #if !defined (JERRY_LCACHE) \ || ((JERRY_LCACHE != 0) && (JERRY_LCACHE != 1)) # error "Invalid value for 'JERRY_LCACHE' macro." @@ -762,7 +732,6 @@ # error "Invalid value for 'JERRY_VM_EXEC_STOP' macro." #endif - #define ENABLED(FEATURE) ((FEATURE) == 1) #define DISABLED(FEATURE) ((FEATURE) != 1) @@ -777,4 +746,14 @@ # error "Date does not support float32" #endif +/** + * Wrap container types into a single guard + */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +# define JERRY_ES2015_BUILTIN_CONTAINER 1 +#else +# define JERRY_ES2015_BUILTIN_CONTAINER 0 +#endif + #endif /* !JERRYSCRIPT_CONFIG_H */ diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 44c894e4..fac5eb36 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -244,7 +244,7 @@ jerry_debugger_send_scope_chain (void) if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { - if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_NON_CLOSURE) != 0) + if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) != 0) { message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_NON_CLOSURE; } @@ -313,7 +313,7 @@ jerry_debugger_get_variable_type (ecma_value_t value) /**< input ecma value */ { JERRY_ASSERT (ecma_is_value_object (value)); - if (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL) + if (ecma_get_object_type (ecma_get_object_from_value (value)) == ECMA_OBJECT_TYPE_ARRAY) { ret_value = JERRY_DEBUGGER_VALUE_ARRAY; } @@ -467,14 +467,9 @@ jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (JERRY_UNLIKELY (ecma_get_object_type (binding_obj_p) == ECMA_OBJECT_TYPE_ARRAY)) + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (binding_obj_p))) { - ecma_extended_object_t *ext_binding_obj_p = (ecma_extended_object_t *) binding_obj_p; - - if (ext_binding_obj_p->u.array.is_fast_mode) - { - ecma_fast_array_convert_to_normal (binding_obj_p); - } + ecma_fast_array_convert_to_normal (binding_obj_p); } prop_iter_cp = binding_obj_p->u1.property_list_cp; @@ -517,22 +512,22 @@ jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer ecma_deref_ecma_string (prop_name); ecma_property_value_t prop_value_p = prop_pair_p->values[i]; - ecma_value_t property_value; uint8_t variable_type = jerry_debugger_get_variable_type (prop_value_p.value); - property_value = ecma_op_to_string (prop_value_p.value); + ecma_string_t *str_p = ecma_op_to_string (prop_value_p.value); + JERRY_ASSERT (str_p != NULL); if (!jerry_debugger_copy_variables_to_string_message (variable_type, - ecma_get_string_from_value (property_value), + str_p, message_string_p, &buffer_pos)) { - ecma_free_value (property_value); + ecma_deref_ecma_string (str_p); return; } - ecma_free_value (property_value); + ecma_deref_ecma_string (str_p); } } @@ -568,21 +563,15 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s { if (eval_string_p[4] != JERRY_DEBUGGER_EVAL_EVAL) { + JERRY_ASSERT (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW || eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); - JERRY_CONTEXT (error_value) = result; /* Stop where the error is caught. */ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; - if (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW) - { - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - } - else - { - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; - } + jcontext_raise_exception (result); + jcontext_set_abort_flag (eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); return true; @@ -590,7 +579,8 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s if (!ecma_is_value_string (result)) { - ecma_value_t to_string_value = ecma_op_to_string (result); + ecma_string_t *str_p = ecma_op_to_string (result); + ecma_value_t to_string_value = ecma_make_string_value (str_p); ecma_free_value (result); result = to_string_value; } @@ -628,8 +618,10 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s else { /* Primitive type. */ - message = ecma_op_to_string (result); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (message)); + ecma_string_t *str_p = ecma_op_to_string (result); + JERRY_ASSERT (str_p != NULL); + + message = ecma_make_string_value (str_p); } ecma_free_value (result); @@ -1212,7 +1204,6 @@ jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] } } /* jerry_debugger_receive */ - #undef JERRY_DEBUGGER_CHECK_PACKET_SIZE /** @@ -1276,7 +1267,6 @@ jerry_debugger_send_type (jerry_debugger_header_type_t type) /**< message type * jerry_debugger_send (sizeof (jerry_debugger_send_type_t)); } /* jerry_debugger_send_type */ - /** * Send the type signal to the client. * @@ -1538,11 +1528,9 @@ jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /** } } - lit_utf8_size_t size = lit_get_magic_string_size (string_id); - JERRY_ASSERT (size <= 14); + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); - lit_utf8_byte_t data[16]; - memcpy (data, lit_get_magic_string_utf8 (string_id), size); + ecma_stringbuilder_append_magic (&builder, string_id); ecma_property_t *property_p; property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value), @@ -1551,21 +1539,21 @@ jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /** if (property_p == NULL || ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA) { - return ecma_new_ecma_string_from_utf8 (data, size); + return ecma_stringbuilder_finalize (&builder); } ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); if (!ecma_is_value_string (prop_value_p->value)) { - return ecma_new_ecma_string_from_utf8 (data, size); + return ecma_stringbuilder_finalize (&builder); } - data[size] = LIT_CHAR_COLON; - data[size + 1] = LIT_CHAR_SP; + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COLON); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_SP); + ecma_stringbuilder_append (&builder, ecma_get_string_from_value (prop_value_p->value)); - return ecma_concat_ecma_strings (ecma_new_ecma_string_from_utf8 (data, size + 2), - ecma_get_string_from_value (prop_value_p->value)); + return ecma_stringbuilder_finalize (&builder); } /* jerry_debugger_exception_object_to_string */ /** @@ -1575,12 +1563,11 @@ jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /** * false - otherwise */ bool -jerry_debugger_send_exception_string (void) +jerry_debugger_send_exception_string (ecma_value_t exception_value) { + JERRY_ASSERT (jcontext_has_pending_exception ()); ecma_string_t *string_p = NULL; - ecma_value_t exception_value = JERRY_CONTEXT (error_value); - if (ecma_is_value_object (exception_value)) { string_p = jerry_debugger_exception_object_to_string (exception_value); @@ -1597,8 +1584,7 @@ jerry_debugger_send_exception_string (void) } else { - exception_value = ecma_op_to_string (exception_value); - string_p = ecma_get_string_from_value (exception_value); + string_p = ecma_op_to_string (exception_value); } ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size); diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h index d1882563..adeee53d 100644 --- a/jerry-core/debugger/debugger.h +++ b/jerry-core/debugger/debugger.h @@ -487,7 +487,7 @@ bool jerry_debugger_send_string (uint8_t message_type, uint8_t sub_type, const u bool jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, ecma_compiled_code_t *compiled_code_p); bool jerry_debugger_send_parse_function (uint32_t line, uint32_t column); void jerry_debugger_send_memstats (void); -bool jerry_debugger_send_exception_string (void); +bool jerry_debugger_send_exception_string (ecma_value_t exception_value); #endif /* ENABLED (JERRY_DEBUGGER) */ diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 33c09273..244caa82 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -18,11 +18,15 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-container-object.h" +#include "ecma-function-object.h" #include "ecma-globals.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "ecma-objects.h" #include "ecma-property-hashmap.h" +#include "ecma-proxy-object.h" #include "jcontext.h" #include "jrt.h" #include "jrt-libc-includes.h" @@ -72,37 +76,42 @@ ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); - return (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); + return (object_p->type_flags_refs < ECMA_OBJECT_NON_VISITED); } /* ecma_gc_is_object_visited */ /** - * Set visited flag of the object. - * Note: This macro can be inlined for performance critical code paths + * Mark objects as visited starting from specified object as root */ -#if defined(JERRY_REF_TRACKER) -# define ECMA_REPORT_REF_MARK(x) ReportObjRefManip(x, kRefMark) -#else -# define ECMA_REPORT_REF_MARK(x) do { JERRY_UNUSED(x); } while (0) -#endif - -#define ECMA_GC_SET_OBJECT_VISITED(object_p) \ - do \ - { \ - if ((object_p)->type_flags_refs < ECMA_OBJECT_REF_ONE) \ - { \ - ECMA_REPORT_REF_MARK(object_p); \ - (object_p)->type_flags_refs |= ECMA_OBJECT_REF_ONE; \ - } \ - } while (0) +static void ecma_gc_mark (ecma_object_t *object_p); /** * Set visited flag of the object. */ -static void JERRY_ATTR_NOINLINE +static void ecma_gc_set_object_visited (ecma_object_t *object_p) /**< object */ { - /* Set reference counter to one if it is zero. */ - ECMA_GC_SET_OBJECT_VISITED (object_p); + if (object_p->type_flags_refs >= ECMA_OBJECT_NON_VISITED) + { +#if (JERRY_GC_MARK_LIMIT != 0) + if (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) != 0) + { + JERRY_CONTEXT (ecma_gc_mark_recursion_limit)--; + /* Set the reference count of gray object to 0 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); + ecma_gc_mark (object_p); + JERRY_CONTEXT (ecma_gc_mark_recursion_limit)++; + } + else + { + /* Set the reference count of the non-marked gray object to 1 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ((ECMA_OBJECT_REF_ONE << 1) - 1)); + JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); + } +#else /* (JERRY_GC_MARK_LIMIT == 0) */ + /* Set the reference count of gray object to 0 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + } } /* ecma_gc_set_object_visited */ /** @@ -114,8 +123,6 @@ ecma_init_gc_info (ecma_object_t *object_p) /**< object */ JERRY_CONTEXT (ecma_gc_objects_number)++; JERRY_CONTEXT (ecma_gc_new_objects)++; - JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_new_objects) <= JERRY_CONTEXT (ecma_gc_objects_number)); - JERRY_ASSERT (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_REF_ONE); @@ -191,7 +198,7 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); - ECMA_GC_SET_OBJECT_VISITED (value_obj_p); + ecma_gc_set_object_visited (value_obj_p); } break; } @@ -230,8 +237,49 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa } } /* ecma_gc_mark_properties */ -#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) +/** + * Mark objects referenced by bound function object. + */ +static void JERRY_ATTR_NOINLINE +ecma_gc_mark_bound_function_object (ecma_object_t *object_p) /**< bound function object */ +{ + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; + + ecma_object_t *target_func_p; + target_func_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + bound_func_p->header.u.bound_function.target_function); + + ecma_gc_set_object_visited (target_func_p); + + ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; + + if (!ecma_is_value_integer_number (args_len_or_this)) + { + if (ecma_is_value_object (args_len_or_this)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this)); + } + + return; + } + + ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); + ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1); + + JERRY_ASSERT (args_length > 0); + + for (ecma_integer_value_t i = 0; i < args_length; i++) + { + if (ecma_is_value_object (args_p[i])) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i])); + } + } +} /* ecma_gc_mark_bound_function_object */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) /** * Mark objects referenced by Promise built-in. */ @@ -248,94 +296,229 @@ ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended /* Mark all reactions. */ ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) ext_object_p; - ecma_collection_t *collection_p = promise_object_p->fulfill_reactions; + ecma_collection_t *collection_p = promise_object_p->reactions; if (collection_p != NULL) { ecma_value_t *buffer_p = collection_p->buffer_p; + ecma_value_t *buffer_end_p = buffer_p + collection_p->item_count; - for (uint32_t i = 0; i < collection_p->item_count; i++) + while (buffer_p < buffer_end_p) { - ecma_gc_set_object_visited (ecma_get_object_from_value (buffer_p[i])); - } - } + ecma_value_t value = *buffer_p++; - collection_p = promise_object_p->reject_reactions; + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, value)); - if (collection_p != NULL) - { - ecma_value_t *buffer_p = collection_p->buffer_p; + if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++)); + } - for (uint32_t i = 0; i < collection_p->item_count; i++) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (buffer_p[i])); + if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++)); + } } } } /* ecma_gc_mark_promise_object */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) /** - * Mark objects referenced by Map/Set built-in. + * Mark objects referenced by Map built-in. */ static void -ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */ +ecma_gc_mark_map_object (ecma_object_t *object_p) /**< object */ { - ecma_map_object_t *map_object_p = (ecma_map_object_t *) object_p; - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + JERRY_ASSERT (object_p != NULL); - ecma_gc_set_object_visited (internal_obj_p); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); - jmem_cpointer_t prop_iter_cp = internal_obj_p->u1.property_list_cp; - -#if ENABLED (JERRY_PROPRETY_HASHMAP) - if (prop_iter_cp != JMEM_CP_NULL) + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, - prop_iter_cp); - if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) { - prop_iter_cp = prop_iter_p->next_property_cp; - } - } -#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ - - while (prop_iter_cp != JMEM_CP_NULL) - { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - - ecma_gc_mark_properties ((ecma_property_pair_t *) prop_iter_p); - - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - - for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) - { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) - { - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); - - if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY) - { - ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - - if (ecma_is_value_object (key_arg)) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (key_arg)); - } - } - } + continue; } - prop_iter_cp = prop_iter_p->next_property_cp; - } -} /* ecma_gc_mark_container_object */ + if (ecma_is_value_object (entry_p->key)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->key)); + } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ + if (ecma_is_value_object (entry_p->value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); + } + } +} /* ecma_gc_mark_map_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/** + * Mark objects referenced by WeakMap built-in. + */ +static void +ecma_gc_mark_weakmap_object (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + if (ecma_is_value_object (entry_p->value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); + } + } +} /* ecma_gc_mark_weakmap_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +/** + * Mark objects referenced by Set built-in. + */ +static void +ecma_gc_mark_set_object (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + if (ecma_is_value_object (*entry_p)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*entry_p)); + } + } +} /* ecma_gc_mark_set_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015) +/** + * Mark objects referenced by inactive generator functions, async functions, etc. + */ +static void +ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */ +{ + vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; + + if (!ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info)) + { + /* All objects referenced by running executable objects are strong roots, + * and a finished executable object cannot refer to other values. */ + return; + } + + if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD) + { + ecma_value_t iterator = executable_object_p->extended_object.u.class_prop.u.value; + ecma_gc_set_object_visited (ecma_get_object_from_value (iterator)); + } + + ecma_gc_set_object_visited (executable_object_p->frame_ctx.lex_env_p); + + if (ecma_is_value_object (executable_object_p->frame_ctx.this_binding)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (executable_object_p->frame_ctx.this_binding)); + } + + const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p; + size_t register_end; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + register_end = args_p->register_end; + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + register_end = args_p->register_end; + } + + ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); + ecma_value_t *register_end_p = register_p + register_end; + + while (register_p < register_end_p) + { + if (ecma_is_value_object (*register_p)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p)); + } + + register_p++; + } + + register_p += executable_object_p->frame_ctx.context_depth; + register_end_p = executable_object_p->frame_ctx.stack_top_p; + + while (register_p < register_end_p) + { + if (ecma_is_value_object (*register_p)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p)); + } + + register_p++; + } +} /* ecma_gc_mark_executable_object */ + +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Mark the objects referenced by a proxy object + */ +static void +ecma_gc_mark_proxy_object (ecma_object_t *object_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (object_p)); + + ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) object_p; + + if (!ecma_is_value_null (proxy_p->target)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->target)); + } + + if (!ecma_is_value_null (proxy_p->handler)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->handler)); + } +} /* ecma_gc_mark_proxy_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /** * Mark objects as visited starting from specified object as root @@ -352,7 +535,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (outer_lex_env_cp != JMEM_CP_NULL) { - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) @@ -369,7 +552,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (proto_cp != JMEM_CP_NULL) { - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); } switch (ecma_get_object_type (object_p)) @@ -395,20 +578,42 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - case LIT_MAGIC_STRING_MAP_UL: +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: { - ecma_gc_mark_container_object (object_p); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ #if ENABLED (JERRY_ES2015_BUILTIN_SET) case LIT_MAGIC_STRING_SET_UL: { - ecma_gc_mark_container_object (object_p); + ecma_gc_mark_set_object (object_p); break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: + { + ecma_gc_mark_weakmap_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case LIT_MAGIC_STRING_MAP_UL: + { + ecma_gc_mark_map_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ +#if ENABLED (JERRY_ES2015) + case LIT_MAGIC_STRING_GENERATOR_UL: + { + ecma_gc_mark_executable_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ default: { break; @@ -431,7 +636,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) case ECMA_PSEUDO_ARRAY_ITERATOR: case ECMA_PSEUDO_SET_ITERATOR: case ECMA_PSEUDO_MAP_ITERATOR: @@ -447,7 +652,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); @@ -466,20 +671,18 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_array_is_fast_array (ext_object_p)) { - if (object_p->u1.property_list_cp == JMEM_CP_NULL) + if (object_p->u1.property_list_cp != JMEM_CP_NULL) { - return; - } + ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - - for (uint32_t i = 0; i < ext_object_p->u.array.length; i++) - { - if (ecma_is_value_object (values_p[i])) + for (uint32_t i = 0; i < ext_object_p->u.array.length; i++) { - ECMA_GC_SET_OBJECT_VISITED (ecma_get_object_from_value (values_p[i])); + if (ecma_is_value_object (values_p[i])) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (values_p[i])); + } } } @@ -487,39 +690,16 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } break; } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_OBJECT_TYPE_PROXY: + { + ecma_gc_mark_proxy_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; - - ecma_object_t *target_func_obj_p; - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - ecma_gc_set_object_visited (target_func_obj_p); - - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - if (!ecma_is_value_integer_number (args_len_or_this)) - { - if (ecma_is_value_object (args_len_or_this)) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this)); - } - break; - } - - ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - - JERRY_ASSERT (args_length > 0); - - for (ecma_integer_value_t i = 0; i < args_length; i++) - { - if (ecma_is_value_object (args_p[i])) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i])); - } - } + ecma_gc_mark_bound_function_object (object_p); break; } case ECMA_OBJECT_TYPE_FUNCTION: @@ -527,27 +707,47 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (!ecma_get_object_is_builtin (object_p)) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + ext_func_p->u.function.scope_cp)); - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_func_p->u.function.scope_cp)); +#if ENABLED (JERRY_ES2015) + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p); + + if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + + if (ecma_is_value_object (arrow_func_p->this_binding)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding)); + } + + if (ecma_is_value_object (arrow_func_p->new_target)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->new_target)); + } + } +#endif /* ENABLED (JERRY_ES2015) */ } break; } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: +#if ENABLED (JERRY_ES2015) + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, - arrow_func_p->scope_cp)); - - if (ecma_is_value_object (arrow_func_p->this_binding)) + if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) { - ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding)); + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) object_p; + + if (!ecma_is_value_null (rev_proxy_p->proxy)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy)); + } } break; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { break; @@ -593,10 +793,6 @@ ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value); -#ifndef JERRY_NDEBUG - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_AVAILABLE; -#endif /* !JERRY_NDEBUG */ - while (native_pointer_p != NULL) { if (native_pointer_p->info_p != NULL) @@ -615,10 +811,6 @@ ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ native_pointer_p = next_p; } - -#ifndef JERRY_NDEBUG - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_AVAILABLE; -#endif /* !JERRY_NDEBUG */ } /* ecma_gc_free_native_pointer */ /** @@ -627,11 +819,9 @@ ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ static void ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode array object to free */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - JERRY_ASSERT (ext_object_p->u.array.is_fast_mode); - const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_object_p->u.array.length); if (object_p->u1.property_list_cp != JMEM_CP_NULL) @@ -646,12 +836,181 @@ ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode arra jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); } - JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); - JERRY_CONTEXT (ecma_gc_objects_number)--; - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); } /* ecma_free_fast_access_array */ +#if ENABLED (JERRY_ES2015) + +/** + * Free non-objects referenced by inactive generator functions, async functions, etc. + * + * @return total object size + */ +static size_t +ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */ +{ + vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; + + const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p; + size_t size, register_end; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + + register_end = args_p->register_end; + size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + + register_end = args_p->register_end; + size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); + } + + size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t)); + + JERRY_ASSERT (!(executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING)); + + ecma_bytecode_deref ((ecma_compiled_code_t *) bytecode_header_p); + + if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED) + { + return size; + } + + ecma_free_value_if_not_object (executable_object_p->frame_ctx.this_binding); + + ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); + ecma_value_t *register_end_p = register_p + register_end; + + while (register_p < register_end_p) + { + ecma_free_value_if_not_object (*register_p++); + } + + if (executable_object_p->frame_ctx.context_depth > 0) + { + ecma_value_t *context_end_p = register_p; + + register_p += executable_object_p->frame_ctx.context_depth; + + ecma_value_t *context_top_p = register_p; + + do + { + context_top_p[-1] &= (uint32_t) ~(VM_CONTEXT_HAS_LEX_ENV | VM_CONTEXT_CLOSE_ITERATOR); + + uint32_t offsets = vm_get_context_value_offsets (context_top_p); + + while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets)) + { + int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets); + + if (ecma_is_value_object (context_top_p[offset])) + { + context_top_p[offset] = ECMA_VALUE_UNDEFINED; + } + + offsets >>= VM_CONTEXT_OFFSET_SHIFT; + } + + context_top_p = vm_stack_context_abort (&executable_object_p->frame_ctx, context_top_p); + } + while (context_top_p > context_end_p); + } + + register_end_p = executable_object_p->frame_ctx.stack_top_p; + + while (register_p < register_end_p) + { + ecma_free_value_if_not_object (*register_p++); + } + + return size; +} /* ecma_gc_free_executable_object */ + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Free properties of an object + */ +void +ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ +{ + jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; + +#if ENABLED (JERRY_PROPRETY_HASHMAP) + if (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, + prop_iter_cp); + if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + { + ecma_property_hashmap_free (object_p); + prop_iter_cp = object_p->u1.property_list_cp; + } + } +#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ + + while (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + /* Both cannot be deleted. */ + JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED + || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); + + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; + + for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + { + ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); + jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; + + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC) + { + /* Call the native's free callback. */ + if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)) + { + ecma_gc_free_native_pointer (property_p); + } +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + else if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_WEAK_REFS)) + { + ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + ECMA_PROPERTY_VALUE_PTR (property_p)->value); + for (uint32_t j = 0; j < refs_p->item_count; j++) + { + const ecma_value_t value = refs_p->buffer_p[j]; + if (!ecma_is_value_empty (value)) + { + ecma_object_t *container_p = ecma_get_object_from_value (value); + + ecma_op_container_remove_weak_entry (container_p, + ecma_make_object_value (object_p)); + } + } + + ecma_collection_destroy (refs_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + } + + if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) + { + ecma_free_property (object_p, name_cp, property_p); + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + + ecma_dealloc_property_pair (prop_pair_p); + } +} /* ecma_gc_free_properties */ + /** * Free specified object. */ @@ -660,114 +1019,86 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) - && object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); - -#if defined(JERRY_REF_TRACKER) - ReportObjDelete(object_p); -#endif - - bool obj_is_not_lex_env = !ecma_is_lexical_environment (object_p); - - if (obj_is_not_lex_env - || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) - { - if (obj_is_not_lex_env && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY) - { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - if (ext_object_p->u.array.is_fast_mode) - { - ecma_free_fast_access_array (object_p); - return; - } - } - - jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; - -#if ENABLED (JERRY_PROPRETY_HASHMAP) - if (prop_iter_cp != JMEM_CP_NULL) - { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, - prop_iter_cp); - if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) - { - ecma_property_hashmap_free (object_p); - prop_iter_cp = object_p->u1.property_list_cp; - } - } -#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ - - while (prop_iter_cp != JMEM_CP_NULL) - { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - - /* Both cannot be deleted. */ - JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED - || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); - - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) - { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - - /* Call the native's free callback. */ - if (JERRY_UNLIKELY (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC - && (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER))) - { - ecma_gc_free_native_pointer (property_p); - } - - if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) - { - ecma_free_property (object_p, name_cp, property_p); - } - } - - prop_iter_cp = prop_iter_p->next_property_cp; - - ecma_dealloc_property_pair (prop_pair_p); - } - } + && ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED)); JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); JERRY_CONTEXT (ecma_gc_objects_number)--; - if (obj_is_not_lex_env) + if (ecma_is_lexical_environment (object_p)) { - ecma_object_type_t object_type = ecma_get_object_type (object_p); - - size_t ext_object_size = sizeof (ecma_extended_object_t); - - if (ecma_get_object_is_builtin (object_p)) + if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { - uint8_t length_and_bitset_size; - - if (object_type == ECMA_OBJECT_TYPE_CLASS - || object_type == ECMA_OBJECT_TYPE_ARRAY) - { - ext_object_size = sizeof (ecma_extended_built_in_object_t); - length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size; - } - else - { - length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size; - } - - ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); + ecma_gc_free_properties (object_p); } - if (object_type == ECMA_OBJECT_TYPE_CLASS) + ecma_dealloc_object (object_p); + return; + } + + ecma_object_type_t object_type = ecma_get_object_type (object_p); + + size_t ext_object_size = sizeof (ecma_extended_object_t); + + if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p))) + { + uint8_t length_and_bitset_size; + + if (object_type == ECMA_OBJECT_TYPE_CLASS + || object_type == ECMA_OBJECT_TYPE_ARRAY) + { + ext_object_size = sizeof (ecma_extended_built_in_object_t); + length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size; + ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); + } + else + { + length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size; + ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); + + ecma_gc_free_properties (object_p); + ecma_dealloc_extended_object (object_p, ext_object_size); + return; + } + } + + switch (object_type) + { + case ECMA_OBJECT_TYPE_GENERAL: + { + ecma_gc_free_properties (object_p); + ecma_dealloc_object (object_p); + return; + } + case ECMA_OBJECT_TYPE_ARRAY: + { + if (ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p)) + { + ecma_free_fast_access_array (object_p); + return; + } + break; + } + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: + { +#if ENABLED (JERRY_ES2015) + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + + if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) + { + ext_object_size = sizeof (ecma_revocable_proxy_object_t); + } +#endif /* ENABLED (JERRY_ES2015) */ + break; + } + case ECMA_OBJECT_TYPE_CLASS: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; switch (ext_object_p->u.class_prop.class_id) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case LIT_MAGIC_STRING_SYMBOL_UL: -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ case LIT_MAGIC_STRING_STRING_UL: case LIT_MAGIC_STRING_NUMBER_UL: { @@ -782,28 +1113,23 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ecma_dealloc_number (num_p); break; } - case LIT_MAGIC_STRING_REGEXP_UL: { - ecma_compiled_code_t *bytecode_p; - bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, - ext_object_p->u.class_prop.u.value); + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, + ext_object_p->u.class_prop.u.value); + + ecma_bytecode_deref (bytecode_p); - if (bytecode_p != NULL) - { - ecma_bytecode_deref (bytecode_p); - } break; } #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) case LIT_MAGIC_STRING_ARRAY_BUFFER_UL: { ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length; - size_t size; if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) { - size = sizeof (ecma_arraybuffer_external_info); + ext_object_size = sizeof (ecma_arraybuffer_external_info); /* Call external free callback if any. */ ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; @@ -816,68 +1142,83 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } else { - size = sizeof (ecma_extended_object_t) + arraybuffer_length; + ext_object_size += arraybuffer_length; } - ecma_dealloc_extended_object (object_p, size); - return; + break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) case LIT_MAGIC_STRING_PROMISE_UL: { ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); - ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->fulfill_reactions); - ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->reject_reactions); - ecma_dealloc_extended_object (object_p, sizeof (ecma_promise_object_t)); - return; + + /* Reactions only contains objects. */ + ecma_collection_destroy (((ecma_promise_object_t *) object_p)->reactions); + + ext_object_size = sizeof (ecma_promise_object_t); + break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_SET) - case LIT_MAGIC_STRING_SET_UL: - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t)); - return; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) #if ENABLED (JERRY_ES2015_BUILTIN_MAP) case LIT_MAGIC_STRING_MAP_UL: - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t)); - return; - } #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case LIT_MAGIC_STRING_SET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + { + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_op_container_free_entries (object_p); + ecma_collection_destroy (container_p); + + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) case LIT_MAGIC_STRING_DATAVIEW_UL: { - ecma_dealloc_extended_object (object_p, sizeof (ecma_dataview_object_t)); - return; + ext_object_size = sizeof (ecma_dataview_object_t); + break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ +#if ENABLED (JERRY_ES2015) + case LIT_MAGIC_STRING_GENERATOR_UL: + { + ext_object_size = ecma_gc_free_executable_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ default: { /* The undefined id represents an uninitialized class. */ JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_UNDEFINED || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ARGUMENTS_UL || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL - || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ERROR_UL); + || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ERROR_UL + || ext_object_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT); break; } } - ecma_dealloc_extended_object (object_p, ext_object_size); - return; + break; } - - if (ecma_get_object_is_builtin (object_p) - || object_type == ECMA_OBJECT_TYPE_ARRAY - || object_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_OBJECT_TYPE_PROXY: { - ecma_dealloc_extended_object (object_p, ext_object_size); - return; + ext_object_size = sizeof (ecma_proxy_object_t); + break; } - - if (object_type == ECMA_OBJECT_TYPE_FUNCTION) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + case ECMA_OBJECT_TYPE_FUNCTION: { /* Function with byte-code (not a built-in function). */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; @@ -885,88 +1226,36 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ #if ENABLED (JERRY_SNAPSHOT_EXEC) if (ext_func_p->u.function.bytecode_cp != ECMA_NULL_POINTER) { - ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); - } - else - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_static_function_t)); - } -#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ - ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ - return; - } + ecma_compiled_code_t *byte_code_p = (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + ext_func_p->u.function.bytecode_cp)); -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (object_type == ECMA_OBJECT_TYPE_ARROW_FUNCTION) - { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - - ecma_free_value_if_not_object (arrow_func_p->this_binding); +#if ENABLED (JERRY_ES2015) + if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + { + ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->this_binding); + ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->new_target); + ext_object_size = sizeof (ecma_arrow_function_t); + } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_bytecode_deref (byte_code_p); #if ENABLED (JERRY_SNAPSHOT_EXEC) - if (arrow_func_p->bytecode_cp != ECMA_NULL_POINTER) - { - ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - arrow_func_p->bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); } else { - ecma_dealloc_extended_object (object_p, sizeof (ecma_static_arrow_function_t)); + ext_object_size = sizeof (ecma_static_function_t); } -#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ - ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - arrow_func_p->bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ - return; + break; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - - if (object_type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY) + case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; switch (ext_object_p->u.pseudo_array.type) { -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) - case ECMA_PSEUDO_ARRAY_TYPEDARRAY: - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); - return; - } - case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_typedarray_object_t)); - return; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) - case ECMA_PSEUDO_ARRAY_ITERATOR: - case ECMA_PSEUDO_SET_ITERATOR: - case ECMA_PSEUDO_MAP_ITERATOR: - { - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); - return; - } - case ECMA_PSEUDO_STRING_ITERATOR: - { - ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value; - - if (!ecma_is_value_empty (iterated_value)) - { - ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value)); - } - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); - return; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ - default: + case ECMA_PSEUDO_ARRAY_ARGUMENTS: { JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); @@ -983,27 +1272,56 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + formal_params_size); - return; + ext_object_size += formal_params_size; + break; + } +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: + { + ext_object_size = sizeof (ecma_extended_typedarray_object_t); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ +#if ENABLED (JERRY_ES2015) + case ECMA_PSEUDO_STRING_ITERATOR: + { + ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value; + + if (!ecma_is_value_empty (iterated_value)) + { + ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value)); + } + + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + default: + { + JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY + || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ITERATOR + || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_SET_ITERATOR + || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_MAP_ITERATOR); + break; } } + + break; } - - if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION) + case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; + ext_object_size = sizeof (ecma_bound_function_t); + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; + ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; if (!ecma_is_value_integer_number (args_len_or_this)) { ecma_free_value_if_not_object (args_len_or_this); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); - return; + break; } ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); + ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1); for (ecma_integer_value_t i = 0; i < args_length; i++) { @@ -1011,12 +1329,17 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + args_size); - return; + ext_object_size += args_size; + break; + } + default: + { + JERRY_UNREACHABLE (); } } - ecma_dealloc_object (object_p); + ecma_gc_free_properties (object_p); + ecma_dealloc_extended_object (object_p, ext_object_size); } /* ecma_gc_free_object */ /** @@ -1025,6 +1348,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ void ecma_gc_run (void) { +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + JERRY_CONTEXT (ecma_gc_new_objects) = 0; ecma_object_t black_list_head; @@ -1047,7 +1374,7 @@ ecma_gc_run (void) JERRY_ASSERT (obj_prev_p == NULL || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p); - if (ecma_gc_is_object_visited (obj_iter_p)) + if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) { /* Moving the object to list of marked objects. */ obj_prev_p->gc_next_cp = obj_next_cp; @@ -1057,6 +1384,7 @@ ecma_gc_run (void) } else { + obj_iter_p->type_flags_refs |= ECMA_OBJECT_NON_VISITED; obj_prev_p = obj_iter_p; } @@ -1064,7 +1392,6 @@ ecma_gc_run (void) } black_end_p->gc_next_cp = JMEM_CP_NULL; - ecma_object_t *const last_root_object_p = black_end_p; /* Mark root objects. */ obj_iter_cp = black_list_head.gc_next_cp; @@ -1085,6 +1412,10 @@ ecma_gc_run (void) do { +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + marked_anything_during_current_iteration = false; obj_prev_p = &white_gray_list_head; @@ -1106,13 +1437,22 @@ ecma_gc_run (void) black_end_p->gc_next_cp = obj_iter_cp; black_end_p = obj_iter_p; - ecma_gc_mark (obj_iter_p); +#if (JERRY_GC_MARK_LIMIT != 0) + if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) + { + /* Set the reference count of non-marked gray object to 0 */ + obj_iter_p->type_flags_refs = (uint16_t) (obj_iter_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); + ecma_gc_mark (obj_iter_p); #if defined(JERRY_HEAPDUMP) if (GetHeapdumpTracing()) { DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_SIMPLE); } #endif + marked_anything_during_current_iteration = true; + } +#else /* (JERRY_GC_MARK_LIMIT == 0) */ marked_anything_during_current_iteration = true; +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ } else { @@ -1125,6 +1465,7 @@ ecma_gc_run (void) while (marked_anything_during_current_iteration); black_end_p->gc_next_cp = JMEM_CP_NULL; + JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp; /* Sweep objects that are currently unmarked. */ obj_iter_cp = white_gray_list_head.gc_next_cp; @@ -1140,24 +1481,9 @@ ecma_gc_run (void) obj_iter_cp = obj_next_cp; } - /* Reset the reference counter of non-root black objects. */ - obj_iter_cp = last_root_object_p->gc_next_cp; - - while (obj_iter_cp != JMEM_CP_NULL) - { - /* The reference counter must be 1. */ - obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); - ecma_unmark_deref_object (obj_iter_p); - JERRY_ASSERT (obj_iter_p->type_flags_refs < ECMA_OBJECT_REF_ONE); - - obj_iter_cp = obj_iter_p->gc_next_cp; - } - - JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp; - #if ENABLED (JERRY_BUILTIN_REGEXP) /* Free RegExp bytecodes stored in cache */ - re_cache_gc_run (); + re_cache_gc (); #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ } /* ecma_gc_run */ @@ -1231,8 +1557,7 @@ ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */ || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { if (!ecma_is_lexical_environment (obj_iter_p) - && ecma_get_object_type (obj_iter_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_iter_p)->u.array.is_fast_mode) + && ecma_op_object_is_fast_array (obj_iter_p)) { obj_iter_cp = obj_iter_p->gc_next_cp; continue; diff --git a/jerry-core/ecma/base/ecma-gc.h b/jerry-core/ecma/base/ecma-gc.h index 6a4166ad..a10e023f 100644 --- a/jerry-core/ecma/base/ecma-gc.h +++ b/jerry-core/ecma/base/ecma-gc.h @@ -29,6 +29,7 @@ void ecma_init_gc_info (ecma_object_t *object_p); void ecma_ref_object (ecma_object_t *object_p); void ecma_deref_object (ecma_object_t *object_p); +void ecma_gc_free_properties (ecma_object_t *object_p); void ecma_gc_run (void); void ecma_free_unused_memory (jmem_pressure_t pressure); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 9ab92e11..d5a117ae 100755 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -36,6 +36,15 @@ */ #define ECMA_NULL_POINTER JMEM_CP_NULL +#if defined (JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY) + +/** + * JMEM_ALIGNMENT_LOG aligned pointers can be stored directly in ecma_value_t + */ +#define ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + +#endif /* JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY */ + /** * @} */ @@ -62,6 +71,7 @@ typedef enum ECMA_STATUS_HIGH_PRESSURE_GC = (1u << 2), /**< last gc was under high pressure */ #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */ + ECMA_STATUS_ABORT = (1u << 4), /**< last exception is an abort */ } ecma_status_flag_t; /** @@ -88,23 +98,37 @@ typedef enum #endif /* ENABLED (JERRY_DEBUGGER) */ /** - * Option flags for script parsing. + * Option flags for parser_parse_script and internal flags for global_status_flags in parser context. * Note: - * The enum members must be kept in sync with parser_general_flags_t - * The last 16 bits are reserved for scope chain index + * the last 16 bits is reserved for internal parser flags, because the debugger uses these + * 16 bits to encode the scope chain skip index as well (see ECMA_PARSE_CHAIN_INDEX_SHIFT) */ typedef enum { ECMA_PARSE_NO_OPTS = 0, /**< no options passed */ - ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */ - ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */ - /* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ - ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed (this value must be kept in - * in sync with PARSER_CLASS_CONSTRUCTOR) */ - ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */ - ECMA_PARSE_HAS_IMPL_SUPER = (1u << 4), /**< the current context has implicit parent class */ - ECMA_PARSE_HAS_STATIC_SUPER = (1u << 5), /**< the current context is a static class method */ - ECMA_PARSE_EVAL = (1u << 6), /**< eval is called */ + ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode, must be same as PARSER_IS_STRICT */ + ECMA_PARSE_MODULE = (1u << 1), /**< module is parsed */ + ECMA_PARSE_EVAL = (1u << 2), /**< eval is called */ + ECMA_PARSE_DIRECT_EVAL = (1u << 3), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */ + ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 4), /**< a class constructor is being parsed */ + + /* These four status flags must be in this order. The first three are also parser status flags. + * See PARSER_SAVE_STATUS_FLAGS / PARSER_RESTORE_STATUS_FLAGS. */ + ECMA_PARSE_ALLOW_SUPER = (1u << 5), /**< allow super property access */ + ECMA_PARSE_ALLOW_SUPER_CALL = (1u << 6), /**< allow super constructor call */ + ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 7), /**< allow new.target access */ + ECMA_PARSE_FUNCTION_CONTEXT = (1u << 8), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */ + + ECMA_PARSE_GENERATOR_FUNCTION = (1u << 9), /**< generator function is parsed */ + + /* These flags are internally used by the parser. */ +#ifndef JERRY_NDEBUG + /** + * This flag represents an error in for in/of statements, which cannot be set + * if the parsing is completed successfully. + */ + ECMA_PARSE_INTERNAL_FOR_IN_OFF_CONTEXT_ERROR = (1u << 30), +#endif /* !JERRY_NDEBUG */ } ecma_parse_opts_t; /** @@ -119,15 +143,6 @@ typedef uint32_t ecma_value_t; */ typedef int32_t ecma_integer_value_t; -#if UINTPTR_MAX <= UINT32_MAX - -/** - * JMEM_ALIGNMENT_LOG aligned pointers can be stored directly in ecma_value_t - */ -#define ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - -#endif /* UINTPTR_MAX <= UINT32_MAX */ - /** * Mask for ecma types in ecma_value_t */ @@ -187,7 +202,11 @@ enum * ecma_op_object_find */ ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference, * a special "base" value for vm */ - ECMA_VALUE_IMPLICIT_CONSTRUCTOR = ECMA_MAKE_VALUE (9), /**< special value for bound class constructors */ + ECMA_VALUE_RELEASE_LEX_ENV = ECMA_MAKE_VALUE (9), /**< if this error remains on the stack when an exception occours + the top lexical environment of the VM frame should be popped */ + ECMA_VALUE_UNINITIALIZED = ECMA_MAKE_VALUE (10), /**< a special value for uninitialized let/const declarations */ + ECMA_VALUE_SPREAD_ELEMENT = ECMA_MAKE_VALUE (11), /**< a special value for spread elements in array initialization + * or function call argument list */ }; #if !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) @@ -327,10 +346,11 @@ typedef enum * that are not indices */ ECMA_LIST_ENUMERABLE = (1 << 1), /**< exclude non-enumerable properties */ ECMA_LIST_PROTOTYPE = (1 << 2), /**< list properties from prototype chain */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - ECMA_LIST_SYMBOLS = (1 << 3), /**< list symbol properties only */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - ECMA_LIST_CONVERT_FAST_ARRAYS = (1 << 4), /**< after listing the properties convert +#if ENABLED (JERRY_ES2015) + ECMA_LIST_SYMBOLS = (1 << 3), /**< list symbol properties */ + ECMA_LIST_SYMBOLS_ONLY = (1 << 4), /**< list symbol properties only */ +#endif /* ENABLED (JERRY_ES2015) */ + ECMA_LIST_CONVERT_FAST_ARRAYS = (1 << 5), /**< after listing the properties convert * the fast access mode array back to normal array */ } ecma_list_properties_options_t; @@ -390,6 +410,15 @@ typedef enum */ #define ECMA_PROPERTY_FIXED 0 +/** + * Default flag of length property. + */ +#if ENABLED (JERRY_ES2015) +#define ECMA_PROPERTY_FLAG_DEFAULT_LENGTH ECMA_PROPERTY_FLAG_CONFIGURABLE +#else /* !ENABLED (JERRY_ES2015) */ +#define ECMA_PROPERTY_FLAG_DEFAULT_LENGTH ECMA_PROPERTY_FIXED +#endif /* ENABLED (JERRY_ES2015) */ + /** * Shift for property name part. */ @@ -593,6 +622,7 @@ typedef enum ECMA_PROPERTY_GET_NO_OPTIONS = 0, /**< no option flags for ecma_op_object_get_property */ ECMA_PROPERTY_GET_VALUE = 1u << 0, /**< fill virtual_value field for virtual properties */ ECMA_PROPERTY_GET_EXT_REFERENCE = 1u << 1, /**< get extended reference to the property */ + ECMA_PROPERTY_GET_HAS_OWN_PROP = 1u << 2, /**< internal [[HasOwnProperty]] method */ } ecma_property_get_option_bits_t; /** @@ -602,15 +632,13 @@ typedef enum { ECMA_OBJECT_TYPE_GENERAL = 0, /**< all objects that are not belongs to the sub-types below. */ ECMA_OBJECT_TYPE_CLASS = 1, /**< Objects with class property */ - ECMA_OBJECT_TYPE_FUNCTION = 2, /**< Function objects (15.3), created through 13.2 routine */ - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION = 3, /**< External (host) function object */ - ECMA_OBJECT_TYPE_ARRAY = 4, /**< Array object (15.4) */ - ECMA_OBJECT_TYPE_BOUND_FUNCTION = 5, /**< Function objects (15.3), created through 15.3.4.5 routine */ - ECMA_OBJECT_TYPE_PSEUDO_ARRAY = 6, /**< Array-like object, such as Arguments object (10.6) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - ECMA_OBJECT_TYPE_ARROW_FUNCTION = 7, /**< arrow function objects */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - + ECMA_OBJECT_TYPE_ARRAY = 2, /**< Array object (15.4) */ + ECMA_OBJECT_TYPE_PSEUDO_ARRAY = 3, /**< Array-like object, such as Arguments object (10.6) */ + ECMA_OBJECT_TYPE_PROXY = 4, /**< Proxy object ECMAScript v6 26.2 */ + /* Note: these 4 types must be in this order. See IsCallable operation. */ + ECMA_OBJECT_TYPE_FUNCTION = 5, /**< Function objects (15.3), created through 13.2 routine */ + ECMA_OBJECT_TYPE_BOUND_FUNCTION = 6, /**< Function objects (15.3), created through 15.3.4.5 routine */ + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION = 7, /**< External (host) function object */ /* Types between 13-15 cannot have a built-in flag. See ecma_lexical_environment_type_t. */ ECMA_OBJECT_TYPE__MAX /**< maximum value */ @@ -641,15 +669,16 @@ typedef enum ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 13, /**< declarative lexical environment */ ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 14, /**< object-bound lexical environment * with provideThis flag */ - ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND = 15, /**< object-bound lexical environment - * with provided super reference */ + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND = 15, /**< object-bound lexical environment + * with provided home object reference */ ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical * environment type */ - ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND /**< maximum value */ + ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND /**< maximum value */ } ecma_lexical_environment_type_t; -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * Types of array iterators. */ @@ -658,35 +687,37 @@ typedef enum ECMA_ITERATOR_KEYS, /**< List only key indices */ ECMA_ITERATOR_VALUES, /**< List only key values */ ECMA_ITERATOR_KEYS_VALUES, /**< List key indices and values */ -} ecma_iterator_type_t; -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +} ecma_array_iterator_type_t; + +#endif /* ENABLED (JERRY_ES2015) */ /** * Offset for JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_SUPER_EVAL_OPTS_OFFSET (32 - 8) +#define ECMA_LOCAL_PARSE_OPTS_OFFSET ((sizeof (uint32_t) - sizeof (uint8_t)) * JERRY_BITSINBYTE) /** * Set JERRY_CONTEXT (status_flags) top 8 bits to the specified 'opts'. */ -#define ECMA_SET_SUPER_EVAL_PARSER_OPTS(opts) \ +#define ECMA_SET_LOCAL_PARSE_OPTS(opts) \ do \ { \ - JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_SUPER_EVAL_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \ + JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_LOCAL_PARSE_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \ } while (0) /** * Get JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_GET_SUPER_EVAL_PARSER_OPTS() (JERRY_CONTEXT (status_flags) >> ECMA_SUPER_EVAL_OPTS_OFFSET) +#define ECMA_GET_LOCAL_PARSE_OPTS() \ + (JERRY_CONTEXT (status_flags) >> (ECMA_LOCAL_PARSE_OPTS_OFFSET - JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER))) /** * Clear JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS() \ +#define ECMA_CLEAR_LOCAL_PARSE_OPTS() \ do \ { \ - JERRY_CONTEXT (status_flags) &= ((1 << ECMA_SUPER_EVAL_OPTS_OFFSET) - 1); \ + JERRY_CONTEXT (status_flags) &= ((1 << ECMA_LOCAL_PARSE_OPTS_OFFSET) - 1); \ } while (0) /** @@ -709,19 +740,32 @@ typedef enum /** * Non closure flag for debugger. */ -#if ENABLED (JERRY_DEBUGGER) -#define ECMA_OBJECT_FLAG_NON_CLOSURE 0x20 -#endif /* ENABLED (JERRY_DEBUGGER) */ +#define ECMA_OBJECT_FLAG_BLOCK ECMA_OBJECT_FLAG_EXTENSIBLE + +/** + * Bitshift index for an ecma-object reference count field + */ +#define ECMA_OBJECT_REF_SHIFT 6 + +/** + * Bitmask for an ecma-object reference count field + */ +#define ECMA_OBJECT_REF_MASK (((1u << 10) - 1) << ECMA_OBJECT_REF_SHIFT) /** * Value for increasing or decreasing the object reference counter. */ -#define ECMA_OBJECT_REF_ONE (1u << 6) +#define ECMA_OBJECT_REF_ONE (1u << ECMA_OBJECT_REF_SHIFT) /** - * Maximum value of the object reference counter (1023). + * Represents non-visited white object */ -#define ECMA_OBJECT_MAX_REF (0x3ffu << 6) +#define ECMA_OBJECT_NON_VISITED (0x3ffu << ECMA_OBJECT_REF_SHIFT) + +/** + * Maximum value of the object reference counter (1022). + */ +#define ECMA_OBJECT_MAX_REF (ECMA_OBJECT_NON_VISITED - ECMA_OBJECT_REF_ONE) /** * Description of ECMA-object or lexical environment @@ -732,8 +776,8 @@ typedef struct /** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV, - ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_NON_CLOSURE - refs : 10 bit (max 1023) */ + ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_BLOCK + refs : 10 bit (max 1022) */ uint16_t type_flags_refs; /** next in the object chain maintained by the garbage collector */ @@ -743,8 +787,9 @@ typedef struct union { jmem_cpointer_t property_list_cp; /**< compressed pointer to object's - * or declerative lexical environments's property list */ + * or declerative lexical environments's property list */ jmem_cpointer_t bound_object_cp; /**< compressed pointer to lexical environments's the bound object */ + jmem_cpointer_t home_object_cp; /**< compressed pointer to lexical environments's the home object */ } u1; /** object prototype or outer reference */ @@ -764,7 +809,15 @@ typedef struct uint8_t length_and_bitset_size; /**< length for built-in functions and * bit set size for all built-ins */ uint16_t routine_id; /**< routine id for built-in functions */ - uint32_t instantiated_bitset[1]; /**< bit set for instantiated properties */ + union + { + uint32_t instantiated_bitset[1]; /**< bit set for instantiated properties */ + struct + { + uint16_t name; /**< name of the built-in functions */ + uint16_t bitset; /**< bit set for instantiated properties of builtin functions */ + } builtin_routine; + } u; } ecma_built_in_props_t; /** @@ -804,6 +857,7 @@ typedef struct { ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */ uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */ + ecma_value_t target; /**< [[ProxyTarget]] internal property */ } u; } class_prop; @@ -812,7 +866,7 @@ typedef struct */ struct { - ecma_value_t scope_cp; /**< function scope */ + jmem_cpointer_tag_t scope_cp; /**< function scope */ ecma_value_t bytecode_cp; /**< function byte code */ } function; @@ -822,10 +876,13 @@ typedef struct struct { uint32_t length; /**< length property value */ - ecma_property_t length_prop; /**< length property */ - bool is_fast_mode; /**< true - if the array is a fast access mode array - * false - otherwise */ - uint8_t hole_count; /**< Number of array holes in a fast access mode array */ + union + { + ecma_property_t length_prop; /**< length property */ + uint32_t hole_count; /**< number of array holes in a fast access mode array + * multiplied ECMA_FAST_ACCESS_HOLE_ONE */ + } u; + } array; /** @@ -848,6 +905,7 @@ typedef struct ecma_value_t lex_env_cp; /**< for arguments: lexical environment */ ecma_value_t arraybuffer; /**< for typedarray: internal arraybuffer */ ecma_value_t iterated_value; /**< for %Iterator%: [[IteratedObject]] property */ + ecma_value_t spread_value; /**< for spread object: spreaded element */ } u2; } pseudo_array; @@ -856,7 +914,7 @@ typedef struct */ struct { - ecma_value_t target_function; /**< target function */ + jmem_cpointer_tag_t target_function; /**< target function */ ecma_value_t args_len_or_this; /**< length of arguments or this value */ } bound_function; @@ -885,7 +943,6 @@ typedef struct #define ECMA_FAST_ARRAY_ALIGN_LENGTH(length) \ (uint32_t) ((((length)) + ECMA_FAST_ARRAY_ALIGNMENT - 1) / ECMA_FAST_ARRAY_ALIGNMENT * ECMA_FAST_ARRAY_ALIGNMENT) - /** * Compiled byte code data. */ @@ -900,6 +957,17 @@ typedef struct * If regexp, the other flags must be RE_FLAG... */ } ecma_compiled_code_t; +/** + * Description of bound function objects. + */ +typedef struct +{ + ecma_extended_object_t header; /**< extended object header */ +#if ENABLED (JERRY_ES2015) + ecma_integer_value_t target_length; /**< length of target function */ +#endif /* ENABLED (JERRY_ES2015) */ +} ecma_bound_function_t; + #if ENABLED (JERRY_SNAPSHOT_EXEC) /** @@ -913,17 +981,16 @@ typedef struct #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) /** * Description of arrow function objects. */ typedef struct { - ecma_object_t object; /**< object header */ + ecma_extended_object_t header; /**< extended object header */ ecma_value_t this_binding; /**< value of 'this' binding */ - jmem_cpointer_t scope_cp; /**< function scope */ - jmem_cpointer_t bytecode_cp; /**< function byte code */ + ecma_value_t new_target; /**< value of new.target */ } ecma_arrow_function_t; #if ENABLED (JERRY_SNAPSHOT_EXEC) @@ -939,18 +1006,62 @@ typedef struct #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** - * Description of Map/Set objects. + * Flags for container objects + */ +typedef enum +{ + ECMA_CONTAINER_FLAGS_EMPTY = (0), /** empty flags */ + ECMA_CONTAINER_FLAGS_WEAK = (1 << 0) /** container object is weak */ +} ecma_container_flags_t; + +/** + * Description of map collection. */ typedef struct { - ecma_extended_object_t header; /**< header part */ - uint32_t size; /**< size of the map object */ -} ecma_map_object_t; -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ + ecma_value_t key; /**< key value */ + ecma_value_t value; /**< value of the key */ +} ecma_container_pair_t; + +/** + * Size of a single element (in ecma_value_t unit). + */ +#define ECMA_CONTAINER_VALUE_SIZE 1 + +/** + * Size of a key - value pair (in ecma_value_t unit). + */ +#define ECMA_CONTAINER_PAIR_SIZE 2 + +/** + * Size of the internal buffer. + */ +#define ECMA_CONTAINER_GET_SIZE(container_p) \ + (container_p->buffer_p[0]) + +/** + * Remove the size field of the internal buffer. + */ +#define ECMA_CONTAINER_SET_SIZE(container_p, size) \ + (container_p->buffer_p[0] = (ecma_value_t) (size)) + +/** + * Number of entries of the internal buffer. + */ +#define ECMA_CONTAINER_ENTRY_COUNT(collection_p) \ + (collection_p->item_count - 1) + +/** + * Pointer to the first entry of the internal buffer. + */ +#define ECMA_CONTAINER_START(collection_p) \ + (collection_p->buffer_p + 1) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ typedef enum { @@ -1148,6 +1259,26 @@ typedef union * See also: ECMA_262 v5, 15.7.3.2 */ # define ECMA_NUMBER_MAX_VALUE (FLT_MAX) +/** + * Number.EPSILON + * + * See also: ECMA_262 v6, 20.1.2.1 + */ +# define ECMA_NUMBER_EPSILON ((ecma_number_t) 1.1920928955078125e-7) + +/** + * Number.MAX_SAFE_INTEGER + * + * See also: ECMA_262 v6, 20.1.2.6 + */ +# define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0xFFFFFF) + +/** + * Number.MIN_SAFE_INTEGER + * + * See also: ECMA_262 v6, 20.1.2.8 + */ +# define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0xFFFFFF) #elif ENABLED (JERRY_NUMBER_TYPE_FLOAT64) /** * Number.MAX_VALUE (i.e., the maximum value of ecma-number) @@ -1155,29 +1286,36 @@ typedef union * See also: ECMA_262 v5, 15.7.3.2 */ # define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308) + /** * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number) * * See also: ECMA_262 v5, 15.7.3.3 */ # define ECMA_NUMBER_MIN_VALUE ((ecma_number_t) 5e-324) -#endif /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */ -#if ENABLED (JERRY_ES2015_BUILTIN) + /** * Number.EPSILON * * See also: ECMA_262 v6, 20.1.2.1 */ # define ECMA_NUMBER_EPSILON ((ecma_number_t) 2.2204460492503130808472633361816e-16) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ -#if ENABLED (JERRY_ES2015_BUILTIN) + /** * Number.MAX_SAFE_INTEGER * - * See also: ECMA_262 v6, 20.1.2.1 + * See also: ECMA_262 v6, 20.1.2.6 */ # define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0x1FFFFFFFFFFFFF) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + +/** + * Number.MIN_SAFE_INTEGER + * + * See also: ECMA_262 v6, 20.1.2.8 + */ +# define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0x1FFFFFFFFFFFFF) +#endif /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */ + /** * Euler number */ @@ -1363,9 +1501,7 @@ typedef enum ECMA_STRING_CONTAINER_SYMBOL, /**< the ecma-string is a symbol */ - ECMA_STRING_CONTAINER_MAP_KEY, /**< the ecma-string is a map key string */ - - ECMA_STRING_CONTAINER__MAX = ECMA_STRING_CONTAINER_MAP_KEY /**< maximum value */ + ECMA_STRING_CONTAINER__MAX = ECMA_STRING_CONTAINER_SYMBOL /**< maximum value */ } ecma_string_container_t; /** @@ -1622,12 +1758,12 @@ typedef struct /** * Function callback descriptor of a %TypedArray% object getter */ -typedef ecma_number_t (*ecma_typedarray_getter_fn_t)(lit_utf8_byte_t *src); +typedef ecma_number_t (*ecma_typedarray_getter_fn_t) (lit_utf8_byte_t *src); /** * Function callback descriptor of a %TypedArray% object setter */ -typedef void (*ecma_typedarray_setter_fn_t)(lit_utf8_byte_t *src, ecma_number_t value); +typedef void (*ecma_typedarray_setter_fn_t) (lit_utf8_byte_t *src, ecma_number_t value); /** * Builtin id for the different types of TypedArray's @@ -1703,6 +1839,27 @@ typedef struct #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ +#if ENABLED (JERRY_ES2015) + +/** + * Executable (e.g. generator, async) object flags. + */ +typedef enum +{ + ECMA_EXECUTABLE_OBJECT_COMPLETED = (1u << 0), /**< executable object is completed and cannot be resumed */ + ECMA_EXECUTABLE_OBJECT_RUNNING = (1u << 1), /**< executable object is currently running */ + /* Generator specific flags. */ + ECMA_GENERATOR_ITERATE_AND_YIELD = (1u << 2), /**< the generator performs a yield* operation */ +} ecma_executable_object_flags_t; + +/** + * Checks whether the executable object is waiting for resuming. + */ +#define ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED(extra_info) \ + (!((extra_info) & (ECMA_EXECUTABLE_OBJECT_COMPLETED | ECMA_EXECUTABLE_OBJECT_RUNNING))) + +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) /** * Description of DataView objects. @@ -1771,6 +1928,32 @@ do \ #define CHECK_JERRY_STACK_USAGE(context_p) #endif /* (JERRY_STACK_LIMIT != 0) */ +/** + * Invalid object pointer which represents abrupt completion + */ +#define ECMA_OBJECT_POINTER_ERROR ((ecma_object_t *) 0x01) + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Description of Proxy objects. + */ +typedef struct +{ + ecma_object_t header; /**< header part */ + ecma_value_t target; /**< [[ProxyTarget]] internal slot */ + ecma_value_t handler; /**< [[ProxyHandler]] internal slot */ +} ecma_proxy_object_t; + +/** + * Description of Proxy objects. + */ +typedef struct +{ + ecma_extended_object_t header; /**< header part */ + ecma_value_t proxy; /**< [[RevocableProxy]] internal slot */ +} ecma_revocable_proxy_object_t; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers-collection.c b/jerry-core/ecma/base/ecma-helpers-collection.c index 56850cb2..0b4ba486 100644 --- a/jerry-core/ecma/base/ecma-helpers-collection.c +++ b/jerry-core/ecma/base/ecma-helpers-collection.c @@ -144,6 +144,49 @@ ecma_collection_push_back (ecma_collection_t *collection_p, /**< value collectio collection_p->buffer_p = buffer_p; } /* ecma_collection_push_back */ +/** + * Reserve space for the given amount of ecma_values in the collection + */ +void +ecma_collection_reserve (ecma_collection_t *collection_p, /**< value collection */ + uint32_t count) /**< number of ecma values to reserve */ +{ + JERRY_ASSERT (collection_p != NULL); + JERRY_ASSERT (UINT32_MAX - count > collection_p->capacity); + + const uint32_t new_capacity = collection_p->capacity + count; + const uint32_t old_size = ECMA_COLLECTION_ALLOCATED_SIZE (collection_p->capacity); + const uint32_t new_size = ECMA_COLLECTION_ALLOCATED_SIZE (new_capacity); + + ecma_value_t *buffer_p = collection_p->buffer_p; + buffer_p = jmem_heap_realloc_block (buffer_p, old_size, new_size); + + collection_p->capacity = new_capacity; + collection_p->buffer_p = buffer_p; +} /* ecma_collection_reserve */ + +/** + * Append a list of values to the end of the collection + */ +void +ecma_collection_append (ecma_collection_t *collection_p, /**< value collection */ + const ecma_value_t *buffer_p, /**< values to append */ + uint32_t count) /**< number of ecma values to append */ +{ + JERRY_ASSERT (collection_p != NULL); + JERRY_ASSERT (collection_p->capacity >= collection_p->item_count); + + uint32_t free_count = collection_p->capacity - collection_p->item_count; + + if (free_count < count) + { + ecma_collection_reserve (collection_p, count - free_count); + } + + memcpy (collection_p->buffer_p + collection_p->item_count, buffer_p, count * sizeof (ecma_value_t)); + collection_p->item_count += count; +} /* ecma_collection_append */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers-conversion.c b/jerry-core/ecma/base/ecma-helpers-conversion.c index c97d621c..aa037133 100644 --- a/jerry-core/ecma/base/ecma-helpers-conversion.c +++ b/jerry-core/ecma/base/ecma-helpers-conversion.c @@ -280,13 +280,87 @@ static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, */ #define EPSILON 0.0000001 +/** + * ECMA-defined conversion from string to number for different radixes (2, 8, 16). + * + * See also: + * ECMA-262 v5 9.3.1 + * ECMA-262 v6 7.1.3.1 + * + * @return NaN - if the conversion fails + * converted number - otherwise + */ +static ecma_number_t +ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p, /**< utf-8 string */ + const lit_utf8_byte_t *end_p, /**< end of utf-8 string */ + uint32_t radix) /**< radix */ +{ + JERRY_ASSERT (radix == 2 || radix == 8 || radix == 16); + ecma_number_t num = ECMA_NUMBER_ZERO; + +#if ENABLED (JERRY_ES2015) + if (radix <= 8) + { + lit_code_point_t upper_limit = LIT_CHAR_0 + radix; + + for (const lit_utf8_byte_t * iter_p = str_p; iter_p <= end_p; iter_p++) + { + int32_t digit_value; + + if (*iter_p >= LIT_CHAR_0 && *iter_p < upper_limit) + { + digit_value = (*iter_p - LIT_CHAR_0); + } + else + { + return ecma_number_make_nan (); + } + + num = num * radix + (ecma_number_t) digit_value; + } + + return num; + } +#endif /* ENABLED (JERRY_ES2015) */ + + for (const lit_utf8_byte_t * iter_p = str_p; iter_p <= end_p; iter_p++) + { + int32_t digit_value; + + if (*iter_p >= LIT_CHAR_0 + && *iter_p <= LIT_CHAR_9) + { + digit_value = (*iter_p - LIT_CHAR_0); + } + else if (*iter_p >= LIT_CHAR_LOWERCASE_A + && *iter_p <= LIT_CHAR_LOWERCASE_F) + { + digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A); + } + else if (*iter_p >= LIT_CHAR_UPPERCASE_A + && *iter_p <= LIT_CHAR_UPPERCASE_F) + { + digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A); + } + else + { + return ecma_number_make_nan (); + } + + num = num * radix + (ecma_number_t) digit_value; + } + + return num; +} /* ecma_utf8_string_to_number_by_radix */ + /** * ECMA-defined conversion of string to Number. * * See also: * ECMA-262 v5, 9.3.1 * - * @return ecma-number + * @return NaN - if the conversion fails + * converted number - otherwise */ ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ @@ -307,46 +381,28 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ return ECMA_NUMBER_ZERO; } - if ((end_p >= str_p + 2) - && str_p[0] == LIT_CHAR_0 - && (str_p[1] == LIT_CHAR_LOWERCASE_X - || str_p[1] == LIT_CHAR_UPPERCASE_X)) + if (end_p >= str_p + 2 + && str_p[0] == LIT_CHAR_0) { - /* Hex literal handling */ - str_p += 2; - - ecma_number_t num = ECMA_NUMBER_ZERO; - - for (const lit_utf8_byte_t * iter_p = str_p; - iter_p <= end_p; - iter_p++) + switch (LEXER_TO_ASCII_LOWERCASE (str_p[1])) { - int32_t digit_value; - - if (*iter_p >= LIT_CHAR_0 - && *iter_p <= LIT_CHAR_9) + case LIT_CHAR_LOWERCASE_X : { - digit_value = (*iter_p - LIT_CHAR_0); + return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 16); } - else if (*iter_p >= LIT_CHAR_LOWERCASE_A - && *iter_p <= LIT_CHAR_LOWERCASE_F) + case LIT_CHAR_LOWERCASE_O : { - digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A); + return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 8); } - else if (*iter_p >= LIT_CHAR_UPPERCASE_A - && *iter_p <= LIT_CHAR_UPPERCASE_F) + case LIT_CHAR_LOWERCASE_B : { - digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A); + return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 2); } - else + default: { - return ecma_number_make_nan (); + break; } - - num = num * 16 + (ecma_number_t) digit_value; } - - return num; } bool sign = false; /* positive */ @@ -703,9 +759,7 @@ ecma_uint32_to_utf8_string (uint32_t value, /**< value to convert */ uint32_t ecma_number_to_uint32 (ecma_number_t num) /**< ecma-number */ { - if (ecma_number_is_nan (num) - || ecma_number_is_zero (num) - || ecma_number_is_infinity (num)) + if (JERRY_UNLIKELY (ecma_number_is_zero (num) || !ecma_number_is_finite (num))) { return 0; } diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.c b/jerry-core/ecma/base/ecma-helpers-external-pointers.c index b9a20d6b..b79bf1f0 100644 --- a/jerry-core/ecma/base/ecma-helpers-external-pointers.c +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.c @@ -17,6 +17,7 @@ #include "ecma-array-object.h" #include "ecma-globals.h" #include "ecma-objects.h" +#include "ecma-objects-general.h" #include "ecma-helpers.h" /** \addtogroup ecma ECMA @@ -39,8 +40,7 @@ ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create { ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { ecma_fast_array_convert_to_normal (obj_p); } @@ -115,8 +115,7 @@ ecma_native_pointer_t * ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */ void *info_p) /**< native pointer's type info */ { - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { /* Fast access mode array can not have native pointer properties */ return NULL; @@ -164,8 +163,7 @@ bool ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete property from */ void *info_p) /**< native pointer's type info */ { - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { /* Fast access mode array can not have native pointer properties */ return false; @@ -196,7 +194,8 @@ ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete if (native_pointer_p->next_p == NULL) { /* Only one native pointer property exists, so the property can be deleted as well. */ - ecma_op_object_delete (obj_p, name_p, false); + ecma_op_general_object_delete (obj_p, name_p, false); + jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t)); return true; } diff --git a/jerry-core/ecma/base/ecma-helpers-number.c b/jerry-core/ecma/base/ecma-helpers-number.c index ca0d5d52..cd1d2361 100644 --- a/jerry-core/ecma/base/ecma-helpers-number.c +++ b/jerry-core/ecma/base/ecma-helpers-number.c @@ -13,8 +13,10 @@ * limitations under the License. */ -#include "ecma-globals.h" -#include "ecma-helpers.h" +#include + +#include "ecma-conversion.h" +#include "lit-char-helpers.h" /** \addtogroup ecma ECMA * @{ @@ -298,8 +300,6 @@ ecma_number_is_negative (ecma_number_t num) /**< ecma-number */ bool ecma_number_is_zero (ecma_number_t num) /**< ecma-number */ { - JERRY_ASSERT (!ecma_number_is_nan (num)); - bool is_zero = (num == ECMA_NUMBER_ZERO); #ifndef JERRY_NDEBUG @@ -323,8 +323,6 @@ ecma_number_is_zero (ecma_number_t num) /**< ecma-number */ bool ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */ { - JERRY_ASSERT (!ecma_number_is_nan (num)); - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); uint64_t fraction = ecma_number_get_fraction_field (num); @@ -333,6 +331,24 @@ ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */ && (fraction == 0)); } /* ecma_number_is_infinity */ +/** + * Check if number is finite + * + * @return true - if number is finite + * false - if number is NaN or infinity + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_number_is_finite (ecma_number_t num) /**< ecma-number */ +{ +#if defined (__GNUC__) || defined (__clang__) + return __builtin_isfinite (num); +#elif defined (WIN32) + return isfinite (num); +#else + return !ecma_number_is_nan (num) && !ecma_number_is_infinity (num); +#endif /* defined (__GNUC__) || defined (__clang__) */ +} /* ecma_number_is_finite */ + /** * Get fraction and exponent of the number * @@ -642,6 +658,31 @@ ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */ return r; } /* ecma_number_calc_remainder */ +/** + * Compute power operation according to the ES standard. + * + * @return x ** y + */ +ecma_number_t +ecma_number_pow (ecma_number_t x, /**< left operand */ + ecma_number_t y) /**< right operand */ +{ + if (ecma_number_is_nan (y) || + (ecma_number_is_infinity (y) && (x == 1.0 || x == -1.0))) + { + /* Handle differences between ES5.1 and ISO C standards for pow. */ + return ecma_number_make_nan (); + } + + if (ecma_number_is_zero (y)) + { + /* Handle differences between ES5.1 and ISO C standards for pow. */ + return (ecma_number_t) 1.0; + } + + return DOUBLE_TO_ECMA_NUMBER_T (pow (x, y)); +} /* ecma_number_pow */ + /** * ECMA-integer number multiplication. * @@ -667,6 +708,371 @@ ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */ return ecma_make_integer_value (left_integer * right_integer); } /* ecma_integer_multiply */ +/** + * The Number object's 'parseInt' routine + * + * See also: + * ECMA-262 v5, 15.1.2.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first argument's + * string buffer */ + lit_utf8_size_t string_buff_size, /**< routine's first argument's + * string buffer's size */ + ecma_value_t radix) /**< routine's second argument */ +{ + if (string_buff_size == 0) + { + return ecma_make_nan_value (); + } + + const lit_utf8_byte_t *string_curr_p = string_buff; + + /* 2. Remove leading whitespace. */ + ecma_string_trim_helper (&string_curr_p, &string_buff_size); + + const lit_utf8_byte_t *string_end_p = string_curr_p + string_buff_size; + const lit_utf8_byte_t *start_p = string_curr_p; + const lit_utf8_byte_t *end_p = string_end_p; + + if (string_curr_p >= string_end_p) + { + return ecma_make_nan_value (); + } + + /* 3. */ + int sign = 1; + + /* 4. */ + ecma_char_t current = lit_cesu8_read_next (&string_curr_p); + if (current == LIT_CHAR_MINUS) + { + sign = -1; + } + + /* 5. */ + if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) + { + start_p = string_curr_p; + if (string_curr_p < string_end_p) + { + current = lit_cesu8_read_next (&string_curr_p); + } + } + + /* 6. */ + ecma_number_t radix_num; + radix = ecma_get_number (radix, &radix_num); + + if (!ecma_is_value_empty (radix)) + { + return radix; + } + + int32_t rad = ecma_number_to_int32 (radix_num); + + /* 7.*/ + bool strip_prefix = true; + + /* 8. */ + if (rad != 0) + { + /* 8.a */ + if (rad < 2 || rad > 36) + { + return ecma_make_nan_value (); + } + /* 8.b */ + else if (rad != 16) + { + strip_prefix = false; + } + } + /* 9. */ + else + { + rad = 10; + } + + /* 10. */ + if (strip_prefix + && ((end_p - start_p) >= 2) + && (current == LIT_CHAR_0)) + { + ecma_char_t next = *string_curr_p; + if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X) + { + /* Skip the 'x' or 'X' characters. */ + start_p = ++string_curr_p; + rad = 16; + } + } + + /* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */ + string_curr_p = start_p; + while (string_curr_p < string_end_p) + { + ecma_char_t current_char = *string_curr_p++; + int32_t current_number; + + if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) + { + current_number = current_char - LIT_CHAR_LOWERCASE_A + 10; + } + else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) + { + current_number = current_char - LIT_CHAR_UPPERCASE_A + 10; + } + else if (lit_char_is_decimal_digit (current_char)) + { + current_number = current_char - LIT_CHAR_0; + } + else + { + /* Not a valid number char, set value to radix so it fails to pass as a valid character. */ + current_number = rad; + } + + if (!(current_number < rad)) + { + end_p = --string_curr_p; + break; + } + } + + /* 12. */ + if (end_p == start_p) + { + return ecma_make_nan_value (); + } + + ecma_number_t value = ECMA_NUMBER_ZERO; + ecma_number_t multiplier = 1.0f; + + /* 13. and 14. */ + string_curr_p = end_p; + + while (string_curr_p > start_p) + { + ecma_char_t current_char = *(--string_curr_p); + ecma_number_t current_number = ECMA_NUMBER_MINUS_ONE; + + if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) + { + current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10; + } + else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) + { + current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10; + } + else + { + JERRY_ASSERT (lit_char_is_decimal_digit (current_char)); + current_number = (ecma_number_t) current_char - LIT_CHAR_0; + } + + value += current_number * multiplier; + multiplier *= (ecma_number_t) rad; + } + + /* 15. */ + if (sign < 0) + { + value *= (ecma_number_t) sign; + } + return ecma_make_number_value (value); +} /* ecma_number_parse_int */ + +/** + * The Number object's 'parseFloat' routine + * + * See also: + * ECMA-262 v5, 15.1.2.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_number_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's first argument's + * string buffer */ + lit_utf8_size_t string_buff_size) /**< routine's first argument's + * string buffer's size */ +{ + if (string_buff_size == 0) + { + return ecma_make_nan_value (); + } + + const lit_utf8_byte_t *str_curr_p = string_buff; + + /* 2. Remove leading whitespace. */ + ecma_string_trim_helper (&str_curr_p, &string_buff_size); + + const lit_utf8_byte_t *str_end_p = str_curr_p + string_buff_size; + const lit_utf8_byte_t *start_p = str_curr_p; + const lit_utf8_byte_t *end_p = str_end_p; + + bool sign = false; + ecma_char_t current; + + if (str_curr_p < str_end_p) + { + /* Check if sign is present. */ + current = *str_curr_p; + if (current == LIT_CHAR_MINUS) + { + sign = true; + } + + if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) + { + /* Set starting position to be after the sign character. */ + start_p = ++str_curr_p; + } + } + + /* Check if string is equal to "Infinity". */ + const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL); + const lit_utf8_size_t infinity_length = lit_get_magic_string_size (LIT_MAGIC_STRING_INFINITY_UL); + + /* The input string should be at least the length of "Infinity" to be correctly processed as + * the infinity value. + */ + if ((str_end_p - str_curr_p) >= (int) infinity_length + && memcmp (infinity_str_p, str_curr_p, infinity_length) == 0) + { + /* String matched Infinity. */ + return ecma_make_number_value (ecma_number_make_infinity (sign)); + } + + /* Reset to starting position. */ + str_curr_p = start_p; + + /* String ended after sign character, or was empty after removing leading whitespace. */ + if (str_curr_p >= str_end_p) + { + return ecma_make_nan_value (); + } + + /* Reset to starting position. */ + str_curr_p = start_p; + + current = *str_curr_p; + + bool has_whole_part = false; + bool has_fraction_part = false; + + /* Check digits of whole part. */ + if (lit_char_is_decimal_digit (current)) + { + has_whole_part = true; + str_curr_p++; + + while (str_curr_p < str_end_p) + { + current = *str_curr_p++; + if (!lit_char_is_decimal_digit (current)) + { + str_curr_p--; + break; + } + } + } + + /* Set end position to the end of whole part. */ + end_p = str_curr_p; + if (str_curr_p < str_end_p) + { + current = *str_curr_p; + + /* Check decimal point. */ + if (current == LIT_CHAR_DOT) + { + str_curr_p++; + + if (str_curr_p < str_end_p) + { + current = *str_curr_p; + + if (lit_char_is_decimal_digit (current)) + { + has_fraction_part = true; + + /* Check digits of fractional part. */ + while (str_curr_p < str_end_p) + { + current = *str_curr_p++; + if (!lit_char_is_decimal_digit (current)) + { + str_curr_p--; + break; + } + } + + /* Set end position to end of fraction part. */ + end_p = str_curr_p; + } + } + } + } + + if (str_curr_p < str_end_p) + { + current = *str_curr_p++; + } + + /* Check exponent. */ + if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E) + && (has_whole_part || has_fraction_part) + && str_curr_p < str_end_p) + { + current = *str_curr_p++; + + /* Check sign of exponent. */ + if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS) + && str_curr_p < str_end_p) + { + current = *str_curr_p++; + } + + if (lit_char_is_decimal_digit (current)) + { + /* Check digits of exponent part. */ + while (str_curr_p < str_end_p) + { + current = *str_curr_p++; + if (!lit_char_is_decimal_digit (current)) + { + str_curr_p--; + break; + } + } + + /* Set end position to end of exponent part. */ + end_p = str_curr_p; + } + } + + /* String did not contain a valid number. */ + if (start_p == end_p) + { + return ecma_make_nan_value (); + } + + /* 5. */ + ecma_number_t ret_num = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (end_p - start_p)); + + if (sign) + { + ret_num *= ECMA_NUMBER_MINUS_ONE; + } + + return ecma_make_number_value (ret_num); +} /* ecma_number_parse_float */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c index 9a3c7a1a..4c94038d 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.c +++ b/jerry-core/ecma/base/ecma-helpers-string.c @@ -204,7 +204,7 @@ ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id) /**< return string_desc_p; } /* ecma_new_ecma_string_from_magic_string_ex_id */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Allocate new ecma-string and fill it with reference to the symbol descriptor * @@ -238,42 +238,7 @@ ecma_prop_name_is_symbol (ecma_string_t *string_p) /**< ecma-string */ return (!ECMA_IS_DIRECT_STRING (string_p) && ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_SYMBOL); } /* ecma_prop_name_is_symbol */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) -/** - * Allocate new ecma-string and fill it with reference to the map key descriptor - * - * @return pointer to ecma-string descriptor - */ -ecma_string_t * -ecma_new_map_key_string (ecma_value_t value) /**< non prop-name ecma-value */ -{ - JERRY_ASSERT (!ecma_is_value_prop_name (value)); - - ecma_extended_string_t *string_p = ecma_alloc_extended_string (); - string_p->header.refs_and_container = ECMA_STRING_REF_ONE | ECMA_STRING_CONTAINER_MAP_KEY; - string_p->u.value = ecma_copy_value_if_not_object (value); - string_p->header.u.hash = (lit_string_hash_t) (ecma_is_value_simple (value) ? value : 0); - - return (ecma_string_t *) string_p; -} /* ecma_new_map_key_string */ - -/** - * Check whether an ecma-string contains a map key string - * - * @return true - if the ecma-string contains a map key string - * false - otherwise - */ -bool -ecma_prop_name_is_map_key (ecma_string_t *string_p) /**< ecma-string */ -{ - JERRY_ASSERT (string_p != NULL); - - return (!ECMA_IS_DIRECT_STRING (string_p) - && ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAP_KEY); -} /* ecma_prop_name_is_map_key */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Allocate new UTF8 ecma-string and fill it with characters from the given utf8 buffer @@ -461,16 +426,9 @@ ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string if ((string_p[pos] & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER) { /* Processing 4 byte unicode sequence. Always converted to two 3 byte long sequence. */ - uint32_t character = ((((uint32_t) string_p[pos++]) & 0x7) << 18); - character |= ((((uint32_t) string_p[pos++]) & LIT_UTF8_LAST_6_BITS_MASK) << 12); - character |= ((((uint32_t) string_p[pos++]) & LIT_UTF8_LAST_6_BITS_MASK) << 6); - character |= (((uint32_t) string_p[pos++]) & LIT_UTF8_LAST_6_BITS_MASK); - - JERRY_ASSERT (character >= 0x10000); - character -= 0x10000; - - data_p += lit_char_to_utf8_bytes (data_p, (ecma_char_t) (0xd800 | (character >> 10))); - data_p += lit_char_to_utf8_bytes (data_p, (ecma_char_t) (0xdc00 | (character & LIT_UTF16_LAST_10_BITS_MASK))); + lit_four_byte_utf8_char_to_cesu8 (data_p, string_p + pos); + data_p += 3 * 2; + pos += 4; } else { @@ -499,7 +457,8 @@ ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit) /**< code unit */ return ecma_new_ecma_string_from_utf8 (lit_utf8_bytes, bytes_size); } /* ecma_new_ecma_string_from_code_unit */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * Allocate new ecma-string and fill it with cesu-8 character which represents specified code units * @@ -515,7 +474,8 @@ ecma_new_ecma_string_from_code_units (ecma_char_t first_code_unit, /**< code uni return ecma_new_ecma_string_from_utf8 (lit_utf8_bytes, bytes_size); } /* ecma_new_ecma_string_from_code_units */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Allocate new ecma-string and fill it with ecma-number @@ -681,7 +641,6 @@ ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */ cesu8_string2_p, cesu8_string2_size); - if (magic_string_id != LIT_MAGIC_STRING__COUNT) { ecma_deref_ecma_string (string1_p); @@ -790,30 +749,6 @@ ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */ return result_p; } /* ecma_concat_ecma_strings */ -/** - * Append a magic string after an ecma-string - * - * Note: - * The string1_p argument is freed. If it needs to be preserved, - * call ecma_ref_ecma_string with string1_p before the call. - * - * @return concatenation of an ecma-string and a magic string - */ -ecma_string_t * -ecma_append_magic_string_to_string (ecma_string_t *string1_p, /**< string descriptor */ - lit_magic_string_id_t string2_id) /**< magic string ID */ -{ - if (JERRY_UNLIKELY (ecma_string_is_empty (string1_p))) - { - return ecma_get_magic_string (string2_id); - } - - const lit_utf8_byte_t *cesu8_string2_p = lit_get_magic_string_utf8 (string2_id); - lit_utf8_size_t cesu8_string2_size = lit_get_magic_string_size (string2_id); - - return ecma_append_chars_to_string (string1_p, cesu8_string2_p, cesu8_string2_size, cesu8_string2_size); -} /* ecma_append_magic_string_to_string */ - /** * Increase reference counter of ecma-string. */ @@ -910,7 +845,7 @@ ecma_destroy_ecma_string (ecma_string_t *string_p) /**< ecma-string */ ((ecma_ascii_string_t *) string_p)->size + sizeof (ecma_ascii_string_t)); return; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case ECMA_STRING_CONTAINER_SYMBOL: { ecma_extended_string_t * symbol_p = (ecma_extended_string_t *) string_p; @@ -918,16 +853,7 @@ ecma_destroy_ecma_string (ecma_string_t *string_p) /**< ecma-string */ ecma_dealloc_extended_string (symbol_p); return; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) - case ECMA_STRING_CONTAINER_MAP_KEY: - { - ecma_extended_string_t *key_p = (ecma_extended_string_t *) string_p; - ecma_free_value_if_not_object (key_p->u.value); - ecma_dealloc_extended_string (key_p); - return; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC @@ -1809,20 +1735,12 @@ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /**< ecma-string */ return true; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (string1_container == ECMA_STRING_CONTAINER_SYMBOL) { return false; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - if (string1_container == ECMA_STRING_CONTAINER_MAP_KEY) - { - return ecma_op_same_value_zero (((ecma_extended_string_t *) string1_p)->u.value, - ((ecma_extended_string_t *) string2_p)->u.value); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#endif /* ENABLED (JERRY_ES2015) */ return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_strings */ @@ -1863,20 +1781,12 @@ ecma_compare_ecma_non_direct_strings (const ecma_string_t *string1_p, /**< ecma- return true; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (string1_container == ECMA_STRING_CONTAINER_SYMBOL) { return false; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - if (string1_container == ECMA_STRING_CONTAINER_MAP_KEY) - { - return ecma_op_same_value_zero (((ecma_extended_string_t *) string1_p)->u.value, - ((ecma_extended_string_t *) string2_p)->u.value); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#endif /* ENABLED (JERRY_ES2015) */ return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_non_direct_strings */ @@ -2452,8 +2362,7 @@ ecma_string_trim_helper (const lit_utf8_byte_t **utf8_str_p, /**< [in, out] curr { read_size = lit_read_code_unit_from_utf8 (current_p, &ch); - if (!lit_char_is_white_space (ch) - && !lit_char_is_line_terminator (ch)) + if (!lit_char_is_white_space (ch)) { nonws_start_p = current_p; break; @@ -2468,8 +2377,7 @@ ecma_string_trim_helper (const lit_utf8_byte_t **utf8_str_p, /**< [in, out] curr { read_size = lit_read_prev_code_unit_from_utf8 (current_p, &ch); - if (!lit_char_is_white_space (ch) - && !lit_char_is_line_terminator (ch)) + if (!lit_char_is_white_space (ch)) { break; } @@ -2558,6 +2466,29 @@ ecma_stringbuilder_create_from (ecma_string_t *string_p) /**< ecma string */ return ret; } /* ecma_stringbuilder_create_from */ +/** + * Create a string builder from a raw string + * + * @return new string builder + */ +ecma_stringbuilder_t +ecma_stringbuilder_create_raw (const lit_utf8_byte_t *data_p, /**< pointer to data */ + const lit_utf8_size_t data_size) /**< size of the data */ +{ + const lit_utf8_size_t initial_size = data_size + (lit_utf8_size_t) sizeof (ecma_ascii_string_t); + + ecma_stringbuilder_header_t *header_p = (ecma_stringbuilder_header_t *) jmem_heap_alloc_block (initial_size); + header_p->current_size = initial_size; +#if ENABLED (JERRY_MEM_STATS) + jmem_stats_allocate_string_bytes (initial_size); +#endif /* ENABLED (JERRY_MEM_STATS) */ + + memcpy (ECMA_STRINGBUILDER_STRING_PTR (header_p), data_p, data_size); + + ecma_stringbuilder_t ret = {.header_p = header_p}; + return ret; +} /* ecma_stringbuilder_create_raw */ + /** * Grow the underlying buffer of a string builder * @@ -2681,10 +2612,10 @@ void ecma_stringbuilder_append_char (ecma_stringbuilder_t *builder_p, /**< string builder */ const ecma_char_t c) /**< ecma char */ { - const lit_utf8_size_t size = (lit_utf8_size_t) lit_char_get_utf8_length (c); + const lit_utf8_size_t size = (lit_utf8_size_t) lit_code_point_get_cesu8_length (c); lit_utf8_byte_t *dest_p = ecma_stringbuilder_grow (builder_p, size); - lit_char_to_utf8_bytes (dest_p, c); + lit_code_point_to_cesu8_bytes (dest_p, c); } /* ecma_stringbuilder_append_char */ /** @@ -2799,6 +2730,58 @@ ecma_stringbuilder_destroy (ecma_stringbuilder_t *builder_p) /**< string builder #endif /* ENABLED (JERRY_MEM_STATS) */ } /* ecma_stringbuilder_destroy */ +#if ENABLED (JERRY_ES2015) +/** + * AdvanceStringIndex operation + * + * See also: + * ECMA-262 v6.0, 21.2.5.2.3 + * + * @return uint32_t - the proper character index based on the operation + */ +uint32_t +ecma_op_advance_string_index (ecma_string_t *str_p, /**< input string */ + uint32_t index, /**< given character index */ + bool is_unicode) /**< true - if regexp object's "unicode" flag is set + false - otherwise */ +{ + if (index >= UINT32_MAX - 1) + { + return UINT32_MAX; + } + + uint32_t next_index = index + 1; + + if (!is_unicode) + { + return next_index; + } + + ecma_length_t str_len = ecma_string_get_length (str_p); + + if (next_index >= str_len) + { + return next_index; + } + + ecma_char_t first = ecma_string_get_char_at_pos (str_p, index); + + if (first < LIT_UTF16_HIGH_SURROGATE_MIN || first > LIT_UTF16_HIGH_SURROGATE_MAX) + { + return next_index; + } + + ecma_char_t second = ecma_string_get_char_at_pos (str_p, next_index); + + if (second < LIT_UTF16_LOW_SURROGATE_MIN || second > LIT_UTF16_LOW_SURROGATE_MAX) + { + return next_index; + } + + return next_index + 1; +} /* ecma_op_advance_string_index */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 90373327..25babda2 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -14,6 +14,7 @@ */ #include "ecma-alloc.h" +#include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" @@ -35,8 +36,12 @@ JERRY_STATIC_ASSERT (ECMA_VALUE_SHIFT <= JMEM_ALIGNMENT_LOG, JERRY_STATIC_ASSERT (sizeof (jmem_cpointer_t) <= sizeof (ecma_value_t), size_of_jmem_cpointer_t_must_be_less_or_equal_to_the_size_of_ecma_value_t); +JERRY_STATIC_ASSERT (sizeof (jmem_cpointer_t) <= sizeof (jmem_cpointer_tag_t), + size_of_jmem_cpointer_t_must_be_less_or_equal_to_the_size_of_jmem_cpointer_tag_t); + #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY +/* cppcheck-suppress zerodiv */ JERRY_STATIC_ASSERT (sizeof (uintptr_t) <= sizeof (ecma_value_t), uintptr_t_must_fit_in_ecma_value_t); @@ -63,7 +68,7 @@ JERRY_STATIC_ASSERT ((ECMA_VALUE_FALSE | (1 << ECMA_DIRECT_SHIFT)) == ECMA_VALUE * * @return type field */ -static inline ecma_type_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE +extern inline ecma_type_t JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE ecma_get_value_type_field (ecma_value_t value) /**< ecma value */ { return value & ECMA_VALUE_TYPE_MASK; @@ -311,7 +316,7 @@ ecma_is_value_string (ecma_value_t value) /**< ecma value */ return ((value & (ECMA_VALUE_TYPE_MASK - 0x4)) == ECMA_TYPE_STRING); } /* ecma_is_value_string */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Check if the value is symbol. * @@ -323,7 +328,7 @@ ecma_is_value_symbol (ecma_value_t value) /**< ecma value */ { return (ecma_get_value_type_field (value) == ECMA_TYPE_SYMBOL); } /* ecma_is_value_symbol */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Check if the value can be property name. @@ -334,11 +339,11 @@ ecma_is_value_symbol (ecma_value_t value) /**< ecma value */ inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE ecma_is_value_prop_name (ecma_value_t value) /**< ecma value */ { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) return ecma_is_value_string (value) || ecma_is_value_symbol (value); -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#else /* !ENABLED (JERRY_ES2015) */ return ecma_is_value_string (value); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_is_value_prop_name */ /** @@ -405,6 +410,45 @@ ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */ || ecma_is_value_object (value)); } /* ecma_check_value_type_is_spec_defined */ +/** + * Checks if the given argument is an array or not. + * + * @return ECMA_VALUE_ERROR- if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether 'arg' is an array object + */ +ecma_value_t +ecma_is_value_array (ecma_value_t arg) /**< argument */ +{ + if (!ecma_is_value_object (arg)) + { + return ECMA_VALUE_FALSE; + } + + ecma_object_t *arg_obj_p = ecma_get_object_from_value (arg); + + if (ecma_get_object_type (arg_obj_p) == ECMA_OBJECT_TYPE_ARRAY) + { + return ECMA_VALUE_TRUE; + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (arg_obj_p)) + { + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) arg_obj_p; + + if (proxy_obj_p->handler == ECMA_VALUE_NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot perform 'IsArray' on the given proxy " + "because handler is null")); + } + + return ecma_is_value_array (proxy_obj_p->target); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ECMA_VALUE_FALSE; +} /* ecma_is_value_array */ + /** * Creates an ecma value from the given raw boolean. * @@ -547,9 +591,9 @@ inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to reference in value */ { JERRY_ASSERT (ecma_string_p != NULL); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) JERRY_ASSERT (!ecma_prop_name_is_symbol ((ecma_string_t *) ecma_string_p)); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if ((((uintptr_t) ecma_string_p) & ECMA_VALUE_TYPE_MASK) != 0) { @@ -559,7 +603,7 @@ ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to refer return ecma_pointer_to_ecma_value (ecma_string_p) | ECMA_TYPE_STRING; } /* ecma_make_string_value */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Symbol value constructor * @@ -573,7 +617,7 @@ ecma_make_symbol_value (const ecma_string_t *ecma_symbol_p) /**< symbol to refer return ecma_pointer_to_ecma_value (ecma_symbol_p) | ECMA_TYPE_SYMBOL; } /* ecma_make_symbol_value */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Property-name value constructor @@ -585,12 +629,12 @@ ecma_make_prop_name_value (const ecma_string_t *ecma_prop_name_p) /**< property { JERRY_ASSERT (ecma_prop_name_p != NULL); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_prop_name_is_symbol ((ecma_string_t *) ecma_prop_name_p)) { return ecma_make_symbol_value (ecma_prop_name_p); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ return ecma_make_string_value (ecma_prop_name_p); } /* ecma_make_prop_name_value */ @@ -705,7 +749,7 @@ ecma_get_string_from_value (ecma_value_t value) /**< ecma value */ return (ecma_string_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_string_from_value */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Get pointer to ecma-string from ecma value * @@ -718,7 +762,7 @@ ecma_get_symbol_from_value (ecma_value_t value) /**< ecma value */ return (ecma_string_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_symbol_from_value */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Get pointer to a property name from ecma value @@ -798,13 +842,13 @@ ecma_copy_value (ecma_value_t value) /**< value description */ ecma_ref_ecma_string (ecma_get_string_from_value (value)); return value; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case ECMA_TYPE_SYMBOL: { ecma_ref_ecma_string (ecma_get_symbol_from_value (value)); return value; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ case ECMA_TYPE_OBJECT: { ecma_ref_object (ecma_get_object_from_value (value)); @@ -842,10 +886,10 @@ ecma_fast_copy_value (ecma_value_t value) /**< value description */ * * @return copy of the given value */ -ecma_value_t +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */ { - if (ecma_get_value_type_field (value) != ECMA_TYPE_OBJECT) + if (!ecma_is_value_object (value)) { return ecma_copy_value (value); } @@ -853,6 +897,30 @@ ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */ return value; } /* ecma_copy_value_if_not_object */ +/** + * Increase reference counter of a value if it is an object. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +ecma_ref_if_object (ecma_value_t value) /**< value description */ +{ + if (ecma_is_value_object (value)) + { + ecma_ref_object (ecma_get_object_from_value (value)); + } +} /* ecma_ref_if_object */ + +/** + * Decrease reference counter of a value if it is an object. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +ecma_deref_if_object (ecma_value_t value) /**< value description */ +{ + if (ecma_is_value_object (value)) + { + ecma_deref_object (ecma_get_object_from_value (value)); + } +} /* ecma_deref_if_object */ + /** * Assign a new value to an ecma-value * @@ -995,13 +1063,13 @@ ecma_free_value (ecma_value_t value) /**< value description */ ecma_deref_ecma_string (string_p); break; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case ECMA_TYPE_SYMBOL: { ecma_deref_ecma_string (ecma_get_symbol_from_value (value)); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ case ECMA_TYPE_OBJECT: { ecma_deref_object (ecma_get_object_from_value (value)); @@ -1101,12 +1169,12 @@ ecma_get_typeof_lit_id (ecma_value_t value) /**< input ecma value */ { ret_value = LIT_MAGIC_STRING_STRING; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) else if (ecma_is_value_symbol (value)) { ret_value = LIT_MAGIC_STRING_SYMBOL; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ else { JERRY_ASSERT (ecma_is_value_object (value)); diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 2d547073..e7288f59 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -14,6 +14,7 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" @@ -54,8 +55,8 @@ JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_BUILT_IN_O JERRY_STATIC_ASSERT (ECMA_OBJECT_REF_ONE == (ECMA_OBJECT_FLAG_EXTENSIBLE << 1), ecma_object_ref_one_must_follow_the_extensible_flag); -JERRY_STATIC_ASSERT ((ECMA_OBJECT_MAX_REF | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX, - ecma_object_max_ref_does_not_fill_the_remaining_bits); +JERRY_STATIC_ASSERT (((ECMA_OBJECT_MAX_REF + ECMA_OBJECT_REF_ONE) | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX, + ecma_object_max_ref_does_not_fill_the_remaining_bits); JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_DELETED == (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT), ecma_property_type_deleted_must_have_magic_string_name_type); @@ -138,12 +139,12 @@ ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< out ecma_object_t *binding_obj_p, /**< binding object */ ecma_lexical_environment_type_t type) /**< type of the new lexical environment */ { -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND - || type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ + || type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (binding_obj_p != NULL && !ecma_is_lexical_environment (binding_obj_p)); @@ -178,40 +179,17 @@ ecma_is_lexical_environment (const ecma_object_t *object_p) /**< object or lexic return full_type >= (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_TYPE_START); } /* ecma_is_lexical_environment */ -/** - * Get value of [[Extensible]] object's internal property. - * - * @return true - if object is extensible - * false - otherwise - */ -inline bool JERRY_ATTR_PURE -ecma_get_object_extensible (const ecma_object_t *object_p) /**< object */ -{ - JERRY_ASSERT (object_p != NULL); - JERRY_ASSERT (!ecma_is_lexical_environment (object_p)); - - return (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0; -} /* ecma_get_object_extensible */ - /** * Set value of [[Extensible]] object's internal property. */ inline void -ecma_set_object_extensible (ecma_object_t *object_p, /**< object */ - bool is_extensible) /**< value of [[Extensible]] */ +ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (object_p)); - if (is_extensible) - { - object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_EXTENSIBLE); - } - else - { - object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_EXTENSIBLE); - } -} /* ecma_set_object_extensible */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_EXTENSIBLE); +} /* ecma_op_ordinary_object_set_extensible */ /** * Get object's internal implementation-defined type. @@ -308,16 +286,86 @@ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-boun { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p)); -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND - || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ + || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ return ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u1.bound_object_cp); } /* ecma_get_lex_env_binding_object */ +/** + * Create a new lexical environment with the same property list as the passed lexical environment + * + * @return pointer to the newly created lexical environment + */ +ecma_object_t * +ecma_clone_decl_lexical_environment (ecma_object_t *lex_env_p, /**< declarative lexical environment */ + bool copy_values) /**< copy property values as well */ +{ + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + + ecma_object_t *outer_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + ecma_object_t *new_lex_env_p = ecma_create_decl_lex_env (outer_lex_env_p); + + jmem_cpointer_t prop_iter_cp = lex_env_p->u1.property_list_cp; + JERRY_ASSERT (prop_iter_cp != JMEM_CP_NULL); + + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, + prop_iter_cp); + if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + { + prop_iter_cp = prop_iter_p->next_property_cp; + } + + JERRY_ASSERT (prop_iter_cp != JMEM_CP_NULL); + + do + { + prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; + + for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + { + if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) + { + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]) == ECMA_PROPERTY_TYPE_NAMEDDATA); + + uint8_t prop_attributes = (uint8_t) (prop_iter_p->types[i] & ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + ecma_string_t *name_p = ecma_string_from_property_name (prop_iter_p->types[i], prop_pair_p->names_cp[i]); + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (new_lex_env_p, name_p, prop_attributes, NULL); + + ecma_deref_ecma_string (name_p); + + JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); + + if (copy_values) + { + property_value_p->value = ecma_copy_value_if_not_object (prop_pair_p->values[i].value); + } + else + { + property_value_p->value = ECMA_VALUE_UNINITIALIZED; + } + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + } + while (prop_iter_cp != JMEM_CP_NULL); + + ecma_deref_object (lex_env_p); + return new_lex_env_p; +} /* ecma_clone_decl_lexical_environment */ + /** * Create a property in an object and link it into * the object's properties' linked-list (at start of the list). @@ -473,8 +521,7 @@ ecma_create_named_data_property (ecma_object_t *object_p, /**< object */ { JERRY_ASSERT (object_p != NULL && name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL); JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) == 0); @@ -502,8 +549,7 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */ { JERRY_ASSERT (object_p != NULL && name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL); JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE) == 0); @@ -537,8 +583,7 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (obj_p) - || ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (obj_p)); ecma_property_t *property_p = NULL; @@ -696,8 +741,7 @@ ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (obj_p) - || ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (obj_p)); ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p); @@ -1202,8 +1246,13 @@ ecma_create_error_reference (ecma_value_t value, /**< referenced value */ ecma_value_t ecma_create_error_reference_from_context (void) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value), - (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) != 0); + bool is_abort = jcontext_has_pending_abort (); + + if (is_abort) + { + jcontext_set_abort_flag (false); + } + return ecma_create_error_reference (jcontext_take_exception (), !is_abort); } /* ecma_create_error_reference_from_context */ /** @@ -1254,40 +1303,35 @@ ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refe } /* ecma_deref_error_reference */ /** - * Clears error reference, and returns with the value. + * Raise error from the given error reference. * - * @return value referenced by the error + * Note: the error reference's ref count is also decreased */ -ecma_value_t -ecma_clear_error_reference (ecma_value_t value, /**< error reference */ - bool set_abort_flag) /**< set abort flag */ +void +ecma_raise_error_from_error_reference (ecma_value_t value) /**< error reference */ { + JERRY_ASSERT (!jcontext_has_pending_exception () && !jcontext_has_pending_abort ()); ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value); - if (set_abort_flag) - { - if (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) - { - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; - } - else - { - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - } - } - JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE); + ecma_value_t referenced_value = error_ref_p->value; + + jcontext_set_exception_flag (true); + jcontext_set_abort_flag (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT); + if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE) { error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE; - return ecma_copy_value (error_ref_p->value); + referenced_value = ecma_copy_value (referenced_value); + } + else + { + jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t)); } - ecma_value_t referenced_value = error_ref_p->value; - jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t)); - return referenced_value; -} /* ecma_clear_error_reference */ + JERRY_CONTEXT (error_value) = referenced_value; +} /* ecma_raise_error_from_error_reference */ /** * Increase reference counter of Compact @@ -1394,6 +1438,18 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ } #endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015) + if (bytecode_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + { + ecma_collection_t *collection_p = ecma_compiled_code_get_tagged_template_collection (bytecode_p); + + /* Since the objects in the tagged template collection are not strong referenced anymore by the compiled code + we can treat them as 'new' objects. */ + JERRY_CONTEXT (ecma_gc_new_objects) += collection_p->item_count; + ecma_collection_free (collection_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_MEM_STATS) jmem_stats_free_byte_code_bytes (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG); #endif /* ENABLED (JERRY_MEM_STATS) */ @@ -1411,6 +1467,51 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG); } /* ecma_bytecode_deref */ +#if ENABLED (JERRY_ES2015) +/** + * Get the tagged template collection of the compiled code + * + * @return pointer to the tagged template collection + */ +ecma_collection_t * +ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */ +{ + JERRY_ASSERT (bytecode_header_p != NULL); + JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS); + + uint8_t *byte_p = (uint8_t *) bytecode_header_p; + byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; + + ecma_value_t *tagged_base_p = (ecma_value_t *) byte_p; + tagged_base_p -= ecma_compiled_code_get_formal_params (bytecode_header_p); + + return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, tagged_base_p[-1]); +} /* ecma_compiled_code_get_tagged_template_collection */ +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) +/** + * Get the number of formal parameters of the compiled code + * + * @return number of formal parameters + */ +ecma_length_t +ecma_compiled_code_get_formal_params (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */ +{ + if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)) + { + return 0; + } + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + return ((cbc_uint16_arguments_t *) bytecode_header_p)->argument_end; + } + + return ((cbc_uint8_arguments_t *) bytecode_header_p)->argument_end; +} /* ecma_compiled_code_get_formal_params */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) */ + #if (JERRY_STACK_LIMIT != 0) /** * Check the current stack usage by calculating the difference from the initial stack base. @@ -1421,7 +1522,7 @@ uintptr_t JERRY_ATTR_NOINLINE ecma_get_current_stack_usage (void) { volatile int __sp; - return (uintptr_t) (JERRY_CONTEXT (stack_base) - (uintptr_t)&__sp); + return (uintptr_t) (JERRY_CONTEXT (stack_base) - (uintptr_t) &__sp); } /* ecma_get_current_stack_usage */ #endif /* (JERRY_STACK_LIMIT != 0) */ diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index a4fbde47..83acd6fb 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -32,6 +32,12 @@ */ #define ECMA_GET_NON_NULL_POINTER(type, field) JMEM_CP_GET_NON_NULL_POINTER (type, field) +/** + * Extract value of pointer from specified pointer-tag value + */ +#define ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG(type, field) \ + JMEM_CP_GET_NON_NULL_POINTER_FROM_POINTER_TAG (type, field) + /** * Get value of pointer from specified compressed pointer. */ @@ -44,12 +50,39 @@ #define ECMA_SET_NON_NULL_POINTER(field, non_compressed_pointer) JMEM_CP_SET_NON_NULL_POINTER (field, \ non_compressed_pointer) +/** + * Set value of pointer-tag value so that it will correspond + * to specified non_compressed_pointer along with tag + */ +#define ECMA_SET_NON_NULL_POINTER_TAG(field, non_compressed_pointer, tag) \ + JMEM_CP_SET_NON_NULL_POINTER_TAG (field, non_compressed_pointer, tag) + /** * Set value of compressed pointer so that it will correspond * to specified non_compressed_pointer. */ #define ECMA_SET_POINTER(field, non_compressed_pointer) JMEM_CP_SET_POINTER (field, non_compressed_pointer) +/** + * Get value of each tag bit from specified pointer-tag value + */ +#define ECMA_GET_FIRST_BIT_FROM_POINTER_TAG(field) \ + JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (field) /**< get first tag bit from jmem_cpointer_tag_t **/ +#define ECMA_GET_SECOND_BIT_FROM_POINTER_TAG(field) \ + JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (field) /**< get second tag bit from jmem_cpointer_tag_t **/ +#define ECMA_GET_THIRD_BIT_FROM_POINTER_TAG(field) \ + JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG (field) /**< get third tag bit from jmem_cpointer_tag_t **/ + +/** + * Set value of each tag bit to specified pointer-tag value + */ +#define ECMA_SET_FIRST_BIT_TO_POINTER_TAG(field) \ + JMEM_CP_SET_FIRST_BIT_TO_POINTER_TAG (field) /**< set first tag bit to jmem_cpointer_tag_t **/ +#define ECMA_SET_SECOND_BIT_TO_POINTER_TAG(field) \ + JMEM_CP_SET_SECOND_BIT_TO_POINTER_TAG (field) /**< set second tag bit to jmem_cpointer_tag_t **/ +#define ECMA_SET_THIRD_BIT_TO_POINTER_TAG(field) \ + JMEM_CP_SET_THIRD_BIT_TO_POINTER_TAG (field) /**< set third tag bit to jmem_cpointer_tag_t **/ + /** * Status flags for ecma_string_get_chars function */ @@ -147,19 +180,38 @@ typedef enum */ #define ECMA_BOOL_TO_BITFIELD(x) ((x) ? 1 : 0) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * JERRY_ASSERT compatible macro for checking whether the given ecma-value is symbol */ #define ECMA_ASSERT_VALUE_IS_SYMBOL(value) (ecma_is_value_symbol ((value))) -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#else /* !ENABLED (JERRY_ES2015) */ /** * JERRY_ASSERT compatible macro for checking whether the given ecma-value is symbol */ #define ECMA_ASSERT_VALUE_IS_SYMBOL(value) (false) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Check whether the given type is ECMA_OBJECT_TYPE_PROXY + * + * @param type object type + */ +#define ECMA_OBJECT_TYPE_IS_PROXY(type) (JERRY_UNLIKELY ((type) == ECMA_OBJECT_TYPE_PROXY)) + +/** + * Check whether the given object has [[ProxyHandler]] and [[ProxyTarger]] internal slots + * + * @param obj_p ecma-object + */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +#define ECMA_OBJECT_IS_PROXY(obj_p) (ECMA_OBJECT_TYPE_IS_PROXY (ecma_get_object_type ((obj_p)))) +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +#define ECMA_OBJECT_IS_PROXY(obj_p) (false) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /* ecma-helpers-value.c */ +ecma_type_t JERRY_ATTR_CONST ecma_get_value_type_field (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_direct (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_simple (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_empty (ecma_value_t value); @@ -176,14 +228,15 @@ bool JERRY_ATTR_CONST ecma_are_values_integer_numbers (ecma_value_t first_value, bool JERRY_ATTR_CONST ecma_is_value_float_number (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_number (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_string (ecma_value_t value); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) bool JERRY_ATTR_CONST ecma_is_value_symbol (ecma_value_t value); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ bool JERRY_ATTR_CONST ecma_is_value_prop_name (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_direct_string (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_non_direct_string (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_object (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_error_reference (ecma_value_t value); +ecma_value_t ecma_is_value_array (ecma_value_t arg); void ecma_check_value_type_is_spec_defined (ecma_value_t value); @@ -195,9 +248,9 @@ ecma_value_t ecma_make_number_value (ecma_number_t ecma_number); ecma_value_t ecma_make_int32_value (int32_t int32_number); ecma_value_t ecma_make_uint32_value (uint32_t uint32_number); ecma_value_t JERRY_ATTR_PURE ecma_make_string_value (const ecma_string_t *ecma_string_p); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ecma_value_t JERRY_ATTR_PURE ecma_make_symbol_value (const ecma_string_t *ecma_symbol_p); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_value_t JERRY_ATTR_PURE ecma_make_prop_name_value (const ecma_string_t *ecma_prop_name_p); ecma_value_t JERRY_ATTR_PURE ecma_make_magic_string_value (lit_magic_string_id_t id); ecma_value_t JERRY_ATTR_PURE ecma_make_object_value (const ecma_object_t *object_p); @@ -207,9 +260,9 @@ ecma_number_t JERRY_ATTR_PURE ecma_get_float_from_value (ecma_value_t value); ecma_number_t * ecma_get_pointer_from_float_value (ecma_value_t value); ecma_number_t JERRY_ATTR_PURE ecma_get_number_from_value (ecma_value_t value); ecma_string_t JERRY_ATTR_PURE *ecma_get_string_from_value (ecma_value_t value); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ecma_string_t JERRY_ATTR_PURE *ecma_get_symbol_from_value (ecma_value_t value); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_string_t JERRY_ATTR_PURE *ecma_get_prop_name_from_value (ecma_value_t value); ecma_object_t JERRY_ATTR_PURE *ecma_get_object_from_value (ecma_value_t value); ecma_error_reference_t JERRY_ATTR_PURE *ecma_get_error_reference_from_value (ecma_value_t value); @@ -217,6 +270,8 @@ ecma_value_t JERRY_ATTR_CONST ecma_invert_boolean_value (ecma_value_t value); ecma_value_t ecma_copy_value (ecma_value_t value); ecma_value_t ecma_fast_copy_value (ecma_value_t value); ecma_value_t ecma_copy_value_if_not_object (ecma_value_t value); +void ecma_ref_if_object (ecma_value_t value); +void ecma_deref_if_object (ecma_value_t value); ecma_value_t ecma_update_float_number (ecma_value_t float_value, ecma_number_t new_number); void ecma_value_assign_value (ecma_value_t *value_p, ecma_value_t ecma_value); void ecma_value_assign_number (ecma_value_t *value_p, ecma_number_t ecma_number); @@ -227,10 +282,11 @@ void ecma_free_number (ecma_value_t value); lit_magic_string_id_t ecma_get_typeof_lit_id (ecma_value_t value); /* ecma-helpers-string.c */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ecma_string_t *ecma_new_symbol_from_descriptor_string (ecma_value_t string_desc); bool ecma_prop_name_is_symbol (ecma_string_t *string_p); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +uint32_t ecma_op_advance_string_index (ecma_string_t *str_p, uint32_t index, bool is_unicode); +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) ecma_string_t *ecma_new_map_key_string (ecma_value_t value); bool ecma_prop_name_is_map_key (ecma_string_t *string_p); @@ -239,9 +295,9 @@ ecma_string_t *ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p, ecma_string_t *ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string_p, lit_utf8_size_t string_size); ecma_string_t *ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit); -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) ecma_string_t *ecma_new_ecma_string_from_code_units (ecma_char_t first_code_unit, ecma_char_t second_code_unit); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_string_t *ecma_new_ecma_string_from_uint32 (uint32_t uint32_number); ecma_string_t *ecma_new_non_direct_string_from_uint32 (uint32_t uint32_number); ecma_string_t *ecma_get_ecma_string_from_uint32 (uint32_t uint32_number); @@ -252,7 +308,6 @@ ecma_string_t *ecma_append_chars_to_string (ecma_string_t *string1_p, lit_utf8_size_t cesu8_string2_size, lit_utf8_size_t cesu8_string2_length); ecma_string_t *ecma_concat_ecma_strings (ecma_string_t *string1_p, ecma_string_t *string2_p); -ecma_string_t *ecma_append_magic_string_to_string (ecma_string_t *string1_p, lit_magic_string_id_t string2_id); void ecma_ref_ecma_string (ecma_string_t *string_p); void ecma_deref_ecma_string (ecma_string_t *string_p); void ecma_destroy_ecma_string (ecma_string_t *string_p); @@ -316,6 +371,8 @@ ecma_string_t *ecma_string_trim (const ecma_string_t *string_p); ecma_stringbuilder_t ecma_stringbuilder_create (void); ecma_stringbuilder_t ecma_stringbuilder_create_from (ecma_string_t *string_p); +ecma_stringbuilder_t ecma_stringbuilder_create_raw (const lit_utf8_byte_t *data_p, + const lit_utf8_size_t data_size); lit_utf8_size_t ecma_stringbuilder_get_size (ecma_stringbuilder_t *builder_p); lit_utf8_byte_t *ecma_stringbuilder_get_data (ecma_stringbuilder_t *builder_p); void ecma_stringbuilder_revert (ecma_stringbuilder_t *builder_p, const lit_utf8_size_t size); @@ -336,12 +393,19 @@ bool ecma_number_is_nan (ecma_number_t num); bool ecma_number_is_negative (ecma_number_t num); bool ecma_number_is_zero (ecma_number_t num); bool ecma_number_is_infinity (ecma_number_t num); +bool ecma_number_is_finite (ecma_number_t num); ecma_number_t ecma_number_make_from_sign_mantissa_and_exponent (bool sign, uint64_t mantissa, int32_t exponent); ecma_number_t ecma_number_get_prev (ecma_number_t num); ecma_number_t ecma_number_get_next (ecma_number_t num); ecma_number_t ecma_number_trunc (ecma_number_t num); ecma_number_t ecma_number_calc_remainder (ecma_number_t left_num, ecma_number_t right_num); +ecma_number_t ecma_number_pow (ecma_number_t x, ecma_number_t y); +ecma_value_t ecma_number_parse_int (const lit_utf8_byte_t *string_buff, + lit_utf8_size_t string_buff_size, + ecma_value_t radix); +ecma_value_t ecma_number_parse_float (const lit_utf8_byte_t *string_buff, + lit_utf8_size_t string_buff_size); ecma_value_t ecma_integer_multiply (ecma_integer_value_t left_integer, ecma_integer_value_t right_integer); lit_utf8_size_t ecma_number_to_decimal (ecma_number_t num, lit_utf8_byte_t *out_digits_p, int32_t *out_decimal_exp_p); lit_utf8_size_t ecma_number_to_binary_floating_point_number (ecma_number_t num, @@ -351,6 +415,8 @@ lit_utf8_size_t ecma_number_to_binary_floating_point_number (ecma_number_t num, /* ecma-helpers-collection.c */ ecma_collection_t *ecma_new_collection (void); void ecma_collection_push_back (ecma_collection_t *collection_p, ecma_value_t value); +void ecma_collection_reserve (ecma_collection_t *collection_p, uint32_t count); +void ecma_collection_append (ecma_collection_t *collection_p, const ecma_value_t *buffer_p, uint32_t count); void ecma_collection_destroy (ecma_collection_t *collection_p); void ecma_collection_free (ecma_collection_t *collection_p); void ecma_collection_free_if_not_object (ecma_collection_t *collection_p); @@ -362,15 +428,14 @@ ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environmen ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p, ecma_lexical_environment_type_t type); bool JERRY_ATTR_PURE ecma_is_lexical_environment (const ecma_object_t *object_p); -bool JERRY_ATTR_PURE ecma_get_object_extensible (const ecma_object_t *object_p); -void ecma_set_object_extensible (ecma_object_t *object_p, bool is_extensible); +void ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p); ecma_object_type_t JERRY_ATTR_PURE ecma_get_object_type (const ecma_object_t *object_p); bool JERRY_ATTR_PURE ecma_get_object_is_builtin (const ecma_object_t *object_p); void ecma_set_object_is_builtin (ecma_object_t *object_p); uint8_t ecma_get_object_builtin_id (ecma_object_t *object_p); ecma_lexical_environment_type_t JERRY_ATTR_PURE ecma_get_lex_env_type (const ecma_object_t *object_p); -ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_outer_reference (const ecma_object_t *object_p); ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_binding_object (const ecma_object_t *object_p); +ecma_object_t *ecma_clone_decl_lexical_environment (ecma_object_t *lex_env_p, bool copy_values); ecma_property_value_t * ecma_create_named_data_property (ecma_object_t *object_p, ecma_string_t *name_p, uint8_t prop_attributes, @@ -416,10 +481,16 @@ ecma_value_t ecma_create_error_reference_from_context (void); ecma_value_t ecma_create_error_object_reference (ecma_object_t *object_p); void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p); void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p); -ecma_value_t ecma_clear_error_reference (ecma_value_t value, bool set_abort_flag); +void ecma_raise_error_from_error_reference (ecma_value_t value); void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p); void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p); +#if ENABLED (JERRY_ES2015) +ecma_collection_t *ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p); +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) +ecma_length_t ecma_compiled_code_get_formal_params (const ecma_compiled_code_t *bytecode_p); +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) */ #if (JERRY_STACK_LIMIT != 0) uintptr_t ecma_get_current_stack_usage (void); #endif /* (JERRY_STACK_LIMIT != 0) */ diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 383c2f39..7717bb91 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -29,13 +29,22 @@ * @{ */ +/** + * Maximum number of GC loops on cleanup. + */ +#define JERRY_GC_LOOP_LIMIT 100 + /** * Initialize ECMA components */ void ecma_init (void) { - ecma_init_global_lex_env (); +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT; +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + + ecma_init_global_environment (); #if ENABLED (JERRY_PROPRETY_HASHMAP) JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON; @@ -44,12 +53,17 @@ ecma_init (void) #if (JERRY_STACK_LIMIT != 0) volatile int sp; - JERRY_CONTEXT (stack_base) = (uintptr_t)&sp; + JERRY_CONTEXT (stack_base) = (uintptr_t) &sp; #endif /* (JERRY_STACK_LIMIT != 0) */ #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) ecma_job_queue_init (); #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = NULL; + JERRY_CONTEXT (current_function_obj_p) = NULL; +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_init */ /** @@ -58,9 +72,23 @@ ecma_init (void) void ecma_finalize (void) { - ecma_finalize_global_lex_env (); - ecma_finalize_builtins (); - ecma_gc_run (); +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) == NULL); + JERRY_ASSERT (JERRY_CONTEXT (current_function_obj_p) == NULL); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_finalize_global_environment (); + uint8_t runs = 0; + do + { + ecma_finalize_builtins (); + ecma_gc_run (); + if (++runs >= JERRY_GC_LOOP_LIMIT) + { + jerry_fatal (ERR_UNTERMINATED_GC_LOOPS); + } + } + while (JERRY_CONTEXT (ecma_gc_new_objects) != 0); ecma_finalize_lit_storage (); } /* ecma_finalize */ diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 83ac43b2..e4dc58ce 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -25,7 +25,7 @@ * @{ */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Free symbol list */ @@ -53,7 +53,7 @@ ecma_free_symbol_list (jmem_cpointer_t symbol_list_cp) /**< symbol list */ symbol_list_cp = next_item_cp; } } /* ecma_free_symbol_list */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Free string list @@ -115,9 +115,9 @@ ecma_free_number_list (jmem_cpointer_t number_list_cp) /**< string list */ void ecma_finalize_lit_storage (void) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ecma_free_symbol_list (JERRY_CONTEXT (symbol_list_first_cp)); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_free_string_list (JERRY_CONTEXT (string_list_first_cp)); ecma_free_number_list (JERRY_CONTEXT (number_list_first_cp)); } /* ecma_finalize_lit_storage */ @@ -346,7 +346,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ const_literal_end = args_p->const_literal_end - register_end; literal_end = args_p->literal_end - register_end; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -361,7 +361,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ const_literal_end = args_p->const_literal_end - register_end; literal_end = args_p->literal_end - register_end; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } diff --git a/jerry-core/ecma/base/ecma-module.c b/jerry-core/ecma/base/ecma-module.c index bd597543..424f8c8a 100644 --- a/jerry-core/ecma/base/ecma-module.c +++ b/jerry-core/ecma/base/ecma-module.c @@ -79,7 +79,6 @@ ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier ECMA_MODULE_MAX_PATH, (char *) module_path_p); - if (normalized_size > 0) { /* Convert the normalized path to cesu8. */ @@ -661,7 +660,7 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */ * @return ECMA_VALUE_ERROR - if an error occured * ECMA_VALUE_EMPTY - otherwise */ -ecma_value_t +static ecma_value_t ecma_module_connect_imports (void) { ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p); @@ -670,6 +669,53 @@ ecma_module_connect_imports (void) JERRY_ASSERT (ecma_is_lexical_environment (local_env_p)); ecma_module_node_t *import_node_p = current_context_p->imports_p; + + /* Check that the imported bindings don't exist yet. */ + while (import_node_p != NULL) + { + ecma_module_names_t *import_names_p = import_node_p->module_names_p; + + while (import_names_p != NULL) + { + ecma_object_t *lex_env_p = local_env_p; + ecma_property_t *binding_p = NULL; + + if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { + binding_p = ecma_find_named_property (lex_env_p, import_names_p->local_name_p); + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + + if (binding_p != NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable.")); + } + + ecma_value_t status = ecma_op_has_binding (lex_env_p, import_names_p->local_name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (status)) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable.")); + } + + import_names_p = import_names_p->next_p; + } + + import_node_p = import_node_p->next_p; + } + + import_node_p = current_context_p->imports_p; + + /* Resolve imports and create local bindings. */ while (import_node_p != NULL) { ecma_value_t result = ecma_module_evaluate (import_node_p->module_request_p); @@ -762,6 +808,26 @@ ecma_module_connect_imports (void) return ECMA_VALUE_EMPTY; } /* ecma_module_connect_imports */ +/** + * Initialize the current module by creating the local binding for the imported variables + * and verifying indirect exports. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +ecma_module_initialize_current (void) +{ + ecma_value_t ret_value = ecma_module_connect_imports (); + + if (ecma_is_value_empty (ret_value)) + { + ret_value = ecma_module_check_indirect_exports (); + } + + return ret_value; +} /* ecma_module_initialize_current */ + /** * Parses an EcmaScript module. * @@ -818,7 +884,7 @@ ecma_module_parse (ecma_module_t *module_p) /**< module */ 0, (jerry_char_t *) source_p, source_size, - JERRY_PARSE_STRICT_MODE, + ECMA_PARSE_STRICT_MODE | ECMA_PARSE_MODULE, &bytecode_data_p); JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p; @@ -976,7 +1042,8 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */ ecma_module_release_module_context (module_p->context_p); } - if (module_p->state >= ECMA_MODULE_STATE_EVALUATING) + if (module_p->state >= ECMA_MODULE_STATE_EVALUATING + && module_p->scope_p != NULL) { ecma_deref_object (module_p->scope_p); } @@ -997,11 +1064,6 @@ finished: void ecma_module_cleanup (void) { - if (JERRY_CONTEXT (module_top_context_p)->parent_p != NULL) - { - return; - } - ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); while (current_p != NULL) { @@ -1010,6 +1072,7 @@ ecma_module_cleanup (void) current_p = next_p; } + JERRY_CONTEXT (ecma_modules_p) = NULL; JERRY_CONTEXT (module_top_context_p) = NULL; } /* ecma_module_cleanup */ diff --git a/jerry-core/ecma/base/ecma-module.h b/jerry-core/ecma/base/ecma-module.h index 290b4d5c..230a6ded 100644 --- a/jerry-core/ecma/base/ecma-module.h +++ b/jerry-core/ecma/base/ecma-module.h @@ -133,7 +133,7 @@ ecma_module_t *ecma_module_create_native_module (ecma_string_t *const path_p, ecma_object_t *const namespace_p); ecma_module_t *ecma_module_find_or_create_module (ecma_string_t *const path_p); -ecma_value_t ecma_module_connect_imports (void); +ecma_value_t ecma_module_initialize_current (void); ecma_value_t ecma_module_parse_modules (void); ecma_value_t ecma_module_check_indirect_exports (void); diff --git a/jerry-core/ecma/base/ecma-property-hashmap.c b/jerry-core/ecma/base/ecma-property-hashmap.c index a3ab4248..f86829e3 100644 --- a/jerry-core/ecma/base/ecma-property-hashmap.c +++ b/jerry-core/ecma/base/ecma-property-hashmap.c @@ -245,7 +245,6 @@ ecma_property_hashmap_insert (ecma_object_t *object_p, /**< object */ uint32_t mask = hashmap_p->max_property_count - 1; entry_index &= mask; - #ifndef JERRY_NDEBUG /* See the comment for this variable in ecma_property_hashmap_create. */ uint32_t start_entry_index = entry_index; diff --git a/jerry-core/ecma/base/ecma-property-hashmap.h b/jerry-core/ecma/base/ecma-property-hashmap.h index 13b41746..62b69445 100644 --- a/jerry-core/ecma/base/ecma-property-hashmap.h +++ b/jerry-core/ecma/base/ecma-property-hashmap.h @@ -72,7 +72,6 @@ void ecma_property_hashmap_insert (ecma_object_t *object_p, ecma_string_t *name_ ecma_property_hashmap_delete_status ecma_property_hashmap_delete (ecma_object_t *object_p, jmem_cpointer_t name_cp, ecma_property_t *property_p); - ecma_property_t *ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, ecma_string_t *name_p, jmem_cpointer_t *property_real_name_cp); #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c index ab3c1746..4c41fddd 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.c @@ -18,11 +18,7 @@ #include "ecma-iterator-object.h" #include "ecma-typedarray-object.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) - -#if !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) -#error "Iterator builtin requires ES2015 symbol builtin" -#endif /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#if ENABLED (JERRY_ES2015) #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -82,40 +78,14 @@ ecma_builtin_array_iterator_prototype_object_next (ecma_value_t this_val) /**< t ecma_object_t *array_object_p = ecma_get_object_from_value (iterated_value); - uint32_t length; - /* 8 - 9. */ -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) - if (ecma_is_typedarray (ecma_make_object_value (array_object_p))) + uint32_t length; + ecma_value_t len_value = ecma_op_object_get_length (array_object_p, &length); + + if (ECMA_IS_VALUE_ERROR (len_value)) { - length = ecma_typedarray_get_length (array_object_p); + return len_value; } - else - { -#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ - ecma_value_t len_value = ecma_op_object_get (array_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH)); - - if (ECMA_IS_VALUE_ERROR (len_value)) - { - return len_value; - } - - ecma_number_t length_number; - ecma_value_t length_value = ecma_get_number (len_value, &length_number); - - if (ECMA_IS_VALUE_ERROR (length_value)) - { - ecma_free_value (len_value); - return length_value; - } - - length = ecma_number_to_uint32 (length_number); - - ecma_free_value (len_value); -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ uint32_t index = ext_obj_p->u.pseudo_array.u1.iterator_index; @@ -161,12 +131,8 @@ ecma_builtin_array_iterator_prototype_object_next (ecma_value_t this_val) /**< t return ecma_create_iter_result_object (ecma_make_uint32_value (index), ECMA_VALUE_FALSE); } - /* 13. */ - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - /* 14. */ - ecma_value_t get_value = ecma_op_object_get (array_object_p, index_string_p); - ecma_deref_ecma_string (index_string_p); + ecma_value_t get_value = ecma_op_object_get_by_uint32_index (array_object_p, index); /* 15. */ if (ECMA_IS_VALUE_ERROR (get_value)) @@ -206,4 +172,4 @@ ecma_builtin_array_iterator_prototype_object_next (ecma_value_t this_val) /**< t * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.inc.h index f7ec656a..38606a8d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-iterator-prototype.inc.h @@ -19,7 +19,7 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_ARRAY_ITERATOR_UL, @@ -29,6 +29,6 @@ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_NEXT, ecma_builtin_array_iterator_prototype_object_next, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c new file mode 100644 index 00000000..12d826e1 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.c @@ -0,0 +1,28 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtin-helpers.h" +#include "ecma-builtins.h" + +#if ENABLED (JERRY_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-array-prototype-unscopables.inc.h" +#define BUILTIN_UNDERSCORED_ID array_prototype_unscopables +#include "ecma-builtin-internal-routines-template.inc.h" + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.inc.h new file mode 100644 index 00000000..4410c50c --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype-unscopables.inc.h @@ -0,0 +1,54 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Array.prototype[@@unscopables] built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +SIMPLE_VALUE (LIT_MAGIC_STRING_COPY_WITHIN, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_ENTRIES, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_FILL, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_FIND, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_FIND_INDEX, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_KEYS, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +SIMPLE_VALUE (LIT_MAGIC_STRING_VALUES, + ECMA_VALUE_TRUE, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) + +#endif /* ENABLED (JERRY_ES2015) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index a43a7341..1faa25d0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -24,7 +24,6 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" -#include "ecma-iterator-object.h" #include "ecma-objects.h" #include "ecma-string-object.h" #include "lit-char-helpers.h" @@ -73,9 +72,10 @@ enum ECMA_ARRAY_PROTOTYPE_FIND, ECMA_ARRAY_PROTOTYPE_FIND_INDEX, ECMA_ARRAY_PROTOTYPE_ENTRIES, - ECMA_ARRAY_PROTOTYPE_VALUES, ECMA_ARRAY_PROTOTYPE_KEYS, ECMA_ARRAY_PROTOTYPE_SYMBOL_ITERATOR, + ECMA_ARRAY_PROTOTYPE_FILL, + ECMA_ARRAY_PROTOTYPE_COPY_WITHIN, }; #define BUILTIN_INC_HEADER_NAME "ecma-builtin-array-prototype.inc.h" @@ -175,14 +175,13 @@ ecma_builtin_array_prototype_object_to_locale_string (ecma_object_t *obj_p, /**< } /* 7-8. */ - ecma_value_t first_value = ecma_builtin_helper_get_to_locale_string_at_index (obj_p, 0); + ecma_string_t *first_string_p = ecma_builtin_helper_get_to_locale_string_at_index (obj_p, 0); - if (ECMA_IS_VALUE_ERROR (first_value)) + if (JERRY_UNLIKELY (first_string_p == NULL)) { - return first_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *first_string_p = ecma_get_string_from_value (first_value); ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (first_string_p); ecma_deref_ecma_string (first_string_p); @@ -192,15 +191,14 @@ ecma_builtin_array_prototype_object_to_locale_string (ecma_object_t *obj_p, /**< /* 4. Implementation-defined: set the separator to a single comma character. */ ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COMMA); - ecma_value_t next_string_value = ecma_builtin_helper_get_to_locale_string_at_index (obj_p, k); + ecma_string_t *next_string_p = ecma_builtin_helper_get_to_locale_string_at_index (obj_p, k); - if (ECMA_IS_VALUE_ERROR (next_string_value)) + if (JERRY_UNLIKELY (next_string_p == NULL)) { ecma_stringbuilder_destroy (&builder); - return next_string_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *next_string_p = ecma_get_string_from_value (next_string_value); ecma_stringbuilder_append (&builder, next_string_p); ecma_deref_ecma_string (next_string_p); } @@ -223,17 +221,17 @@ ecma_builtin_array_prototype_object_concat (const ecma_value_t args[], /**< argu ecma_object_t *obj_p) /**< array object */ { /* 2. */ -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p); +#if ENABLED (JERRY_ES2015) + ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0); if (ECMA_IS_VALUE_ERROR (new_array)) { return new_array; } -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); uint32_t new_length = 0; @@ -281,16 +279,16 @@ ecma_builtin_array_prototype_object_concat (const ecma_value_t args[], /**< argu * See also: * ECMA-262 v5.1, 15.4.4.2 4th step * - * @return ecma value - * Returned value must be freed with ecma_free_value. + * @return NULL - if the conversion fails + * ecma_string_t * - otherwise */ -static ecma_value_t +static ecma_string_t * ecma_op_array_get_separator_string (ecma_value_t separator) /**< possible separator */ { if (ecma_is_value_undefined (separator)) { - return ecma_make_magic_string_value (LIT_MAGIC_STRING_COMMA_CHAR); + return ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR); } return ecma_op_to_string (separator); @@ -302,35 +300,31 @@ ecma_op_array_get_separator_string (ecma_value_t separator) /**< possible separa * See also: * ECMA-262 v5.1, 15.4.4.2 * - * @return ecma_value_t value - * Returned value must be freed with ecma_free_value. + * @return NULL - if the conversion fails + * ecma_string_t * - otherwise */ -static ecma_value_t +static ecma_string_t * ecma_op_array_get_to_string_at_index (ecma_object_t *obj_p, /**< this object */ uint32_t index) /**< array index */ { - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - - ecma_value_t index_value = ecma_op_object_get (obj_p, index_string_p); - - ecma_deref_ecma_string (index_string_p); + ecma_value_t index_value = ecma_op_object_get_by_uint32_index (obj_p, index); if (ECMA_IS_VALUE_ERROR (index_value)) { - return index_value; + return NULL; } if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) { - return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } - ecma_value_t ret_value = ecma_op_to_string (index_value); + ecma_string_t *ret_str_p = ecma_op_to_string (index_value); ecma_free_value (index_value); - return ret_value; + return ret_str_p; } /* ecma_op_array_get_to_string_at_index */ /** @@ -348,15 +342,13 @@ ecma_builtin_array_prototype_join (ecma_value_t separator_arg, /**< separator ar uint32_t length) /**< array object's length */ { /* 4-5. */ - ecma_value_t separator_value = ecma_op_array_get_separator_string (separator_arg); + ecma_string_t *separator_string_p = ecma_op_array_get_separator_string (separator_arg); - if (ECMA_IS_VALUE_ERROR (separator_value)) + if (JERRY_UNLIKELY (separator_string_p == NULL)) { - return separator_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *separator_string_p = ecma_get_string_from_value (separator_value); - if (length == 0) { /* 6. */ @@ -365,15 +357,14 @@ ecma_builtin_array_prototype_join (ecma_value_t separator_arg, /**< separator ar } /* 7-8. */ - ecma_value_t first_value = ecma_op_array_get_to_string_at_index (obj_p, 0); + ecma_string_t *first_string_p = ecma_op_array_get_to_string_at_index (obj_p, 0); - if (ECMA_IS_VALUE_ERROR (first_value)) + if (JERRY_UNLIKELY (first_string_p == NULL)) { ecma_deref_ecma_string (separator_string_p); - return first_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *first_string_p = ecma_get_string_from_value (first_value); ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (first_string_p); ecma_deref_ecma_string (first_string_p); @@ -383,18 +374,16 @@ ecma_builtin_array_prototype_join (ecma_value_t separator_arg, /**< separator ar /* 10.a */ ecma_stringbuilder_append (&builder, separator_string_p); - /* 10.b, 10.c */ - ecma_value_t next_string_value = ecma_op_array_get_to_string_at_index (obj_p, k); + /* 10.d */ + ecma_string_t *next_string_p = ecma_op_array_get_to_string_at_index (obj_p, k); - if (ECMA_IS_VALUE_ERROR (next_string_value)) + if (JERRY_UNLIKELY (next_string_p == NULL)) { ecma_deref_ecma_string (separator_string_p); ecma_stringbuilder_destroy (&builder); - return next_string_value; + return ECMA_VALUE_ERROR; } - /* 10.d */ - ecma_string_t *next_string_p = ecma_get_string_from_value (next_string_value); ecma_stringbuilder_append (&builder, next_string_p); ecma_deref_ecma_string (next_string_p); } @@ -426,22 +415,30 @@ ecma_builtin_array_prototype_object_pop (ecma_object_t *obj_p, /**< array object return ECMA_IS_VALUE_ERROR (set_length_value) ? set_length_value : ECMA_VALUE_UNDEFINED; } - /* 5.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (--len); - /* 5.b */ - ecma_value_t get_value = ecma_op_object_get (obj_p, index_str_p); + len--; + ecma_value_t get_value = ecma_op_object_get_by_uint32_index (obj_p, len); if (ECMA_IS_VALUE_ERROR (get_value)) { - ecma_deref_ecma_string (index_str_p); + return get_value; + } + + if (ecma_op_object_is_fast_array (obj_p)) + { + if (!ecma_op_ordinary_object_is_extensible (obj_p)) + { + ecma_free_value (get_value); + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); + } + + ecma_delete_fast_array_properties (obj_p, len); + return get_value; } /* 5.c */ - ecma_value_t del_value = ecma_op_object_delete (obj_p, index_str_p, true); - - ecma_deref_ecma_string (index_str_p); + ecma_value_t del_value = ecma_op_object_delete_by_uint32_index (obj_p, len, true); if (ECMA_IS_VALUE_ERROR (del_value)) { @@ -480,6 +477,37 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / { ecma_number_t n = (ecma_number_t) length; + if (ecma_op_object_is_fast_array (obj_p)) + { + if (!ecma_op_ordinary_object_is_extensible (obj_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); + } + + if ((ecma_number_t) (length + arguments_number) > UINT32_MAX) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length")); + } + + if (arguments_number == 0) + { + return ecma_make_uint32_value (length); + } + + uint32_t new_length = length + arguments_number; + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + ecma_value_t *buffer_p = ecma_fast_array_extend (obj_p, new_length) + length; + + for (uint32_t index = 0; index < arguments_number; index++) + { + buffer_p[index] = ecma_copy_value_if_not_object (argument_list_p[index]); + } + + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * arguments_number; + + return ecma_make_uint32_value (new_length); + } + /* 5. */ for (uint32_t index = 0; index < arguments_number; index++, n++) { @@ -517,42 +545,106 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { - /* 4. */ uint32_t middle = len / 2; - /* 5-6. */ + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE + && len != 0 + && ecma_op_ordinary_object_is_extensible (obj_p)) + { + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + for (uint32_t i = 0; i < middle; i++) + { + ecma_value_t tmp = buffer_p[i]; + buffer_p[i] = buffer_p[len - 1 - i]; + buffer_p[len - 1 - i] = tmp; + } + + return ecma_copy_value (this_arg); + } + } + for (uint32_t lower = 0; lower < middle; lower++) { + uint32_t upper = len - lower - 1; ecma_value_t ret_value = ECMA_VALUE_ERROR; - ecma_string_t *lower_str_p = ecma_new_ecma_string_from_uint32 (lower); - /* 6.d and 6.e */ + ecma_string_t *lower_str_p = ecma_new_ecma_string_from_uint32 (lower); + ecma_string_t *upper_str_p = ecma_new_ecma_string_from_uint32 (upper); + +#if ENABLED (JERRY_ES2015) + ecma_value_t lower_value = ECMA_VALUE_EMPTY; + ecma_value_t upper_value = ECMA_VALUE_EMPTY; + + ecma_value_t has_lower = ecma_op_object_has_property (obj_p, lower_str_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_lower)) + { + goto clean_up; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + bool lower_exist = ecma_is_value_true (has_lower); + + if (lower_exist) + { + lower_value = ecma_op_object_get (obj_p, lower_str_p); + + if (ECMA_IS_VALUE_ERROR (lower_value)) + { + goto clean_up; + } + } + + ecma_value_t has_upper = ecma_op_object_has_property (obj_p, upper_str_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_upper)) + { + goto clean_up; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + bool upper_exist = ecma_is_value_true (has_upper); + + if (upper_exist) + { + upper_value = ecma_op_object_get (obj_p, upper_str_p); + + if (ECMA_IS_VALUE_ERROR (upper_value)) + { + goto clean_up; + } + } +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t lower_value = ecma_op_object_get (obj_p, lower_str_p); if (ECMA_IS_VALUE_ERROR (lower_value)) { ecma_deref_ecma_string (lower_str_p); - return lower_value; + ecma_deref_ecma_string (upper_str_p); + return ret_value; } - /* 6.a */ - uint32_t upper = len - lower - 1; - /* 6.b and 6.c */ - ecma_string_t *upper_str_p = ecma_new_ecma_string_from_uint32 (upper); - ecma_value_t upper_value = ecma_op_object_get (obj_p, upper_str_p); if (ECMA_IS_VALUE_ERROR (upper_value)) { - upper_value = ECMA_VALUE_EMPTY; goto clean_up; } - /* 6.f and 6.g */ - bool lower_exist = ecma_op_object_has_property (obj_p, lower_str_p); - bool upper_exist = ecma_op_object_has_property (obj_p, upper_str_p); + ecma_value_t has_lower = ecma_op_object_has_property (obj_p, lower_str_p); + ecma_value_t has_upper = ecma_op_object_has_property (obj_p, upper_str_p); + + bool lower_exist = ecma_is_value_true (has_lower); + bool upper_exist = ecma_is_value_true (has_upper); +#endif /* ENABLED (JERRY_ES2015) */ - /* 6.h */ if (lower_exist && upper_exist) { ecma_value_t outer_put_value = ecma_op_object_put (obj_p, lower_str_p, upper_value, true); @@ -569,7 +661,6 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar goto clean_up; } } - /* 6.i */ else if (!lower_exist && upper_exist) { ecma_value_t put_value = ecma_op_object_put (obj_p, lower_str_p, upper_value, true); @@ -581,14 +672,11 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar ecma_value_t del_value = ecma_op_object_delete (obj_p, upper_str_p, true); - JERRY_ASSERT (ECMA_IS_VALUE_ERROR (del_value) || ecma_is_value_boolean (del_value)); - if (ECMA_IS_VALUE_ERROR (del_value)) { goto clean_up; } } - /* 6.j */ else if (lower_exist) { ecma_value_t del_value = ecma_op_object_delete (obj_p, lower_str_p, true); @@ -620,7 +708,6 @@ clean_up: } } - /* 7. */ return ecma_copy_value (this_arg); } /* ecma_builtin_array_prototype_object_reverse */ @@ -645,8 +732,33 @@ ecma_builtin_array_prototype_object_shift (ecma_object_t *obj_p, /**< array obje return ECMA_IS_VALUE_ERROR (set_length_value) ? set_length_value : ECMA_VALUE_UNDEFINED; } + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE + && len != 0 + && ecma_op_ordinary_object_is_extensible (obj_p)) + { + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + ecma_value_t ret_value = buffer_p[0]; + + if (ecma_is_value_object (ret_value)) + { + ecma_ref_object (ecma_get_object_from_value (ret_value)); + } + + memmove (buffer_p, buffer_p + 1, sizeof (ecma_value_t) * (len - 1)); + + buffer_p[len - 1] = ECMA_VALUE_UNDEFINED; + ecma_delete_fast_array_properties (obj_p, len - 1); + + return ret_value; + } + } + /* 5. */ - ecma_value_t first_value = ecma_op_object_get (obj_p, ecma_get_ecma_string_from_uint32 (0)); + ecma_value_t first_value = ecma_op_object_get_by_uint32_index (obj_p, 0); if (ECMA_IS_VALUE_ERROR (first_value)) { @@ -727,16 +839,14 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t arg1, /**< start */ { uint32_t start = 0, end = len; - /* 5. */ - ecma_number_t start_num; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg1, &start_num))) + /* 5. 6.*/ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg1, + len, + &start))) { return ECMA_VALUE_ERROR; } - start = ecma_builtin_helper_array_index_normalize (start_num, len, false); - /* 7. */ if (ecma_is_value_undefined (arg2)) { @@ -744,36 +854,90 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t arg1, /**< start */ } else { - /* 7. part 2 */ - ecma_number_t end_num; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg2, &end_num))) + /* 7. part 2, 8.*/ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg2, + len, + &end))) { return ECMA_VALUE_ERROR; } - - end = ecma_builtin_helper_array_index_normalize (end_num, len, false); } JERRY_ASSERT (start <= len && end <= len); -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p); + bool use_fast_path = ecma_op_object_is_fast_array (obj_p); + uint32_t copied_length = (end > start) ? end - start : 0; +#if ENABLED (JERRY_ES2015) + ecma_value_t new_array = ecma_op_array_species_create (obj_p, copied_length); if (ECMA_IS_VALUE_ERROR (new_array)) { return new_array; } -#else /* !ENABLED (JERRY_ES2015_CLASS) */ + use_fast_path &= ecma_op_object_is_fast_array (ecma_get_object_from_value (new_array)); +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); /* 9. */ uint32_t n = 0; + if (use_fast_path && copied_length > 0) + { + ecma_extended_object_t *ext_from_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_from_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE) + { + if (JERRY_UNLIKELY (obj_p->u1.property_list_cp == JMEM_CP_NULL)) + { + /** + * Very unlikely case: the buffer copied from is a fast buffer and the property list was deleted. + * There is no need to do any copy. + */ + return new_array; + } + + ecma_extended_object_t *ext_to_obj_p = (ecma_extended_object_t *) new_array_p; + +#if ENABLED (JERRY_ES2015) + uint32_t target_length = ext_to_obj_p->u.array.length; + ecma_value_t *to_buffer_p; + if (copied_length == target_length) + { + to_buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, new_array_p->u1.property_list_cp); + } + else if (copied_length > target_length) + { + to_buffer_p = ecma_fast_array_extend (new_array_p, copied_length); + } + else + { + ecma_delete_fast_array_properties (new_array_p, copied_length); + to_buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, new_array_p->u1.property_list_cp); + } +#else /* !ENABLED (JERRY_ES2015) */ + ecma_value_t *to_buffer_p = ecma_fast_array_extend (new_array_p, copied_length); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t *from_buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + for (uint32_t k = start; k < end; k++, n++) + { +#if ENABLED (JERRY_ES2015) + ecma_free_value_if_not_object (to_buffer_p[n]); +#endif /* ENABLED (JERRY_ES2015) */ + to_buffer_p[n] = ecma_copy_value_if_not_object (from_buffer_p[k]); + } + + ext_to_obj_p->u.array.u.hole_count &= ECMA_FAST_ARRAY_HOLE_ONE - 1; + + return new_array; + } + } + /* 10. */ for (uint32_t k = start; k < end; k++, n++) { @@ -793,11 +957,30 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t arg1, /**< start */ n, get_value, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - JERRY_ASSERT (ecma_is_value_true (put_comp)); ecma_free_value (get_value); + +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (put_comp)) + { + ecma_deref_object (new_array_p); + return put_comp; + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (ecma_is_value_true (put_comp)); +#endif /* ENABLED (JERRY_ES2015) */ } } +#if ENABLED (JERRY_ES2015) + ecma_value_t set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, ((ecma_number_t) n)); + + if (ECMA_IS_VALUE_ERROR (set_length_value)) + { + ecma_deref_object (new_array_p); + return set_length_value; + } +#endif /* ENABLED (JERRY_ES2015) */ + return new_array; } /* ecma_builtin_array_prototype_object_slice */ @@ -839,24 +1022,19 @@ ecma_builtin_array_prototype_object_sort_compare_helper (ecma_value_t lhs, /**< if (ecma_is_value_undefined (compare_func)) { /* Default comparison when no compare_func is passed. */ - ecma_value_t lhs_value = ecma_op_to_string (lhs); - - if (ECMA_IS_VALUE_ERROR (lhs_value)) + ecma_string_t *lhs_str_p = ecma_op_to_string (lhs); + if (JERRY_UNLIKELY (lhs_str_p == NULL)) { - return lhs_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *lhs_str_p = ecma_get_string_from_value (lhs_value); - ecma_value_t rhs_value = ecma_op_to_string (rhs); - - if (ECMA_IS_VALUE_ERROR (rhs_value)) + ecma_string_t *rhs_str_p = ecma_op_to_string (rhs); + if (JERRY_UNLIKELY (rhs_str_p == NULL)) { ecma_deref_ecma_string (lhs_str_p); - return rhs_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *rhs_str_p = ecma_get_string_from_value (rhs_value); - if (ecma_compare_ecma_strings_relational (lhs_str_p, rhs_str_p)) { result = ECMA_NUMBER_MINUS_ONE; @@ -939,6 +1117,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum ecma_collection_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ARRAY_INDICES); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (array_index_props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + uint32_t defined_prop_count = 0; ecma_value_t *buffer_p = array_index_props_p->buffer_p; @@ -1077,17 +1262,17 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p); +#if ENABLED (JERRY_ES2015) + ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0); if (ECMA_IS_VALUE_ERROR (new_array)) { return new_array; } -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); @@ -1096,16 +1281,15 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu if (args_number > 0) { - /* 5. */ - ecma_number_t start_num; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (args[0], &start_num))) + /* 5. 6. */ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0], + len, + &start))) { ecma_deref_object (new_array_p); return ECMA_VALUE_ERROR; } - start = ecma_builtin_helper_array_index_normalize (start_num, len, false); - /* * If there is only one argument, that will be the start argument, * and we must delete the additional elements. @@ -1118,7 +1302,7 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu { /* 7. */ ecma_number_t delete_num; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (args[1], &delete_num))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &delete_num))) { ecma_deref_object (new_array_p); return ECMA_VALUE_ERROR; @@ -1163,7 +1347,6 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu return get_value; } - if (ecma_is_value_found (get_value)) { /* 9.c.ii */ @@ -1171,12 +1354,30 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu k, get_value, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - JERRY_ASSERT (ecma_is_value_true (put_comp)); - ecma_free_value (get_value); +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (put_comp)) + { + ecma_deref_object (new_array_p); + return put_comp; + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (ecma_is_value_true (put_comp)); +#endif /* ENABLED (JERRY_ES2015) */ } } +#if ENABLED (JERRY_ES2015) + ecma_value_t new_set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, + ((ecma_number_t) delete_count)); + + if (ECMA_IS_VALUE_ERROR (new_set_length_value)) + { + ecma_deref_object (new_array_p); + return new_set_length_value; + } +#endif /* ENABLED (JERRY_ES2015) */ + /* 11. */ ecma_length_t item_count; @@ -1329,6 +1530,43 @@ ecma_builtin_array_prototype_object_unshift (const ecma_value_t args[], /**< arg ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { + + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE + && len != 0 + && ecma_op_ordinary_object_is_extensible (obj_p)) + { + if ((ecma_number_t) (len + args_number) > UINT32_MAX) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length")); + } + + if (args_number == 0) + { + return ecma_make_uint32_value (len); + } + + uint32_t new_length = len + args_number; + ecma_value_t *buffer_p = ecma_fast_array_extend (obj_p, new_length); + memmove (buffer_p + args_number, buffer_p, sizeof (ecma_value_t) * len); + + uint32_t index = 0; + + while (index < args_number) + { + buffer_p[index] = ecma_copy_value_if_not_object (args[index]); + index++; + } + + ext_obj_p->u.array.u.hole_count -= args_number * ECMA_FAST_ARRAY_HOLE_ONE; + + return ecma_make_uint32_value (new_length); + } + } + /* 5. and 6. */ for (uint32_t k = len; k > 0; k--) { @@ -1395,8 +1633,8 @@ ecma_builtin_array_prototype_object_unshift (const ecma_value_t args[], /**< arg * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_prototype_object_index_of (ecma_value_t arg1, /**< searchElement */ - ecma_value_t arg2, /**< fromIndex */ +ecma_builtin_array_prototype_object_index_of (const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number, /**< number of arguments */ ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { @@ -1407,19 +1645,64 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t arg1, /**< searchElem } /* 5. */ - ecma_number_t arg_from_idx; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg2, &arg_from_idx))) + ecma_number_t idx = 0; + if (args_number > 1) { - return ECMA_VALUE_ERROR; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &idx))) + { + return ECMA_VALUE_ERROR; + } } - ecma_number_t found_index = ECMA_NUMBER_MINUS_ONE; + /* 6. */ + if (idx >= len) + { + return ecma_make_number_value (-1); + } - uint32_t from_idx = ecma_builtin_helper_array_index_normalize (arg_from_idx, len, false); + /* 7. */ + ecma_number_t from_idx_num = idx; + + /* 8. */ + if (idx < 0) + { + from_idx_num = JERRY_MAX ((ecma_number_t) len + idx, 0); + } + + JERRY_ASSERT (from_idx_num >= 0 && from_idx_num <= UINT32_MAX); + uint32_t from_idx = (uint32_t) from_idx_num; + + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE) + { + if (JERRY_UNLIKELY (obj_p->u1.property_list_cp == JMEM_CP_NULL)) + { + return ecma_make_integer_value (-1); + } + + len = JERRY_MIN (ext_obj_p->u.array.length, len); + + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + while (from_idx < len) + { + if (ecma_op_strict_equality_compare (args[0], buffer_p[from_idx])) + { + return ecma_make_uint32_value (from_idx); + } + + from_idx++; + } + + return ecma_make_integer_value (-1); + } + } /* 6. */ - for (; from_idx < len && found_index < 0; from_idx++) + while (from_idx < len) { /* 9.a */ ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, from_idx); @@ -1431,15 +1714,18 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t arg1, /**< searchElem /* 9.b.i, 9.b.ii */ if (ecma_is_value_found (get_value) - && ecma_op_strict_equality_compare (arg1, get_value)) + && ecma_op_strict_equality_compare (args[0], get_value)) { - found_index = ((ecma_number_t) from_idx); + ecma_free_value (get_value); + return ecma_make_uint32_value (from_idx); } + from_idx++; + ecma_free_value (get_value); } - return ecma_make_number_value (found_index); + return ecma_make_integer_value (-1); } /* ecma_builtin_array_prototype_object_index_of */ /** @@ -1463,28 +1749,64 @@ ecma_builtin_array_prototype_object_last_index_of (const ecma_value_t args[], /* return ecma_make_integer_value (-1); } - uint32_t from_idx = len - 1; - + /* 5. */ + ecma_number_t idx = (ecma_number_t) len - 1; if (args_number > 1) { - ecma_number_t arg_from_idx; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (args[1], &arg_from_idx))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &idx))) { return ECMA_VALUE_ERROR; } - - from_idx = ecma_builtin_helper_array_index_normalize (arg_from_idx, len, true); } - ecma_number_t num = ECMA_NUMBER_MINUS_ONE; + uint32_t from_idx; + + /* 6 */ + if (idx >= 0) + { + from_idx = (uint32_t) (JERRY_MIN (idx, len - 1)); + } + else + { + ecma_number_t k = len + idx; + if (k < 0) + { + return ecma_make_integer_value (-1); + } + from_idx = (uint32_t) k; + } + ecma_value_t search_element = (args_number > 0) ? args[0] : ECMA_VALUE_UNDEFINED; - /* 8. - * We should break from the loop when from_idx < 0. We can still use an uint32_t for from_idx, and check - * for an underflow instead. This is safe, because from_idx will always start in [0, len - 1], - * and len is in [0, UINT_MAX], so from_idx >= len means we've had an underflow, and should stop. - */ - for (; from_idx < len && num < 0; from_idx--) + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE) + { + if (JERRY_UNLIKELY (obj_p->u1.property_list_cp == JMEM_CP_NULL)) + { + return ecma_make_integer_value (-1); + } + + len = JERRY_MIN (ext_obj_p->u.array.length, len); + + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + while (from_idx < len) + { + if (ecma_op_strict_equality_compare (search_element, buffer_p[from_idx])) + { + return ecma_make_uint32_value (from_idx); + } + from_idx--; + } + return ecma_make_integer_value (-1); + } + } + + /* 8. */ + while (from_idx < len) { /* 8.a */ ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, from_idx); @@ -1498,13 +1820,16 @@ ecma_builtin_array_prototype_object_last_index_of (const ecma_value_t args[], /* if (ecma_is_value_found (get_value) && ecma_op_strict_equality_compare (search_element, get_value)) { - num = ((ecma_number_t) from_idx); + ecma_free_value (get_value); + return ecma_make_uint32_value (from_idx); } + from_idx--; + ecma_free_value (get_value); } - return ecma_make_number_value (num); + return ecma_make_integer_value (-1); } /* ecma_builtin_array_prototype_object_last_index_of */ /** @@ -1631,17 +1956,19 @@ ecma_builtin_array_prototype_object_map (ecma_value_t arg1, /**< callbackfn */ } /* 6. */ -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p); +#if ENABLED (JERRY_ES2015) + ecma_value_t new_array = ecma_op_array_species_create (obj_p, len); if (ECMA_IS_VALUE_ERROR (new_array)) { return new_array; } -#else /* !ENABLED (JERRY_ES2015_CLASS) */ - ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); +#else /* !ENABLED (JERRY_ES2015) */ + ecma_value_t length_value = ecma_make_number_value (len); + ecma_value_t new_array = ecma_op_create_array_object (&length_value, 1, true); + ecma_free_value (length_value); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); @@ -1683,23 +2010,21 @@ ecma_builtin_array_prototype_object_map (ecma_value_t arg1, /**< callbackfn */ mapped_value, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - JERRY_ASSERT (ecma_is_value_true (put_comp)); - ecma_free_value (mapped_value); ecma_free_value (current_value); +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (put_comp)) + { + ecma_deref_object (new_array_p); + return put_comp; + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (ecma_is_value_true (put_comp)); +#endif /* ENABLED (JERRY_ES2015) */ } } - - ecma_value_t set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, ((ecma_number_t) len)); - - if (ECMA_IS_VALUE_ERROR (set_length_value)) - { - ecma_deref_object (new_array_p); - return set_length_value; - } - - return new_array; + return ecma_make_object_value (new_array_p); } /* ecma_builtin_array_prototype_object_map */ /** @@ -1724,17 +2049,17 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t arg1, /**< callbackfn * } /* 6. */ -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p); +#if ENABLED (JERRY_ES2015) + ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0); if (ECMA_IS_VALUE_ERROR (new_array)) { return new_array; } -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); @@ -1781,7 +2106,18 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t arg1, /**< callbackfn * new_array_index, get_value, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (put_comp)) + { + ecma_free_value (call_value); + ecma_free_value (get_value); + ecma_deref_object (new_array_p); + + return put_comp; + } +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (ecma_is_value_true (put_comp)); +#endif /* ENABLED (JERRY_ES2015) */ new_array_index++; } @@ -1804,27 +2140,26 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t arg1, /**< callbackfn * * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_reduce_from (ecma_value_t callbackfn, /**< routine's 1st argument */ - ecma_value_t initial_value, /**< routine's 2nd argument */ +ecma_builtin_array_reduce_from (const ecma_value_t args_p[], /**< routine's arguments */ ecma_length_t args_number, /**< arguments list length */ bool start_from_left, /**< whether the reduce starts from left or right */ ecma_object_t *obj_p, /**< array object */ uint32_t len) /**< array object's length */ { /* 4. */ - if (!ecma_op_is_callable (callbackfn)) + if (!ecma_op_is_callable (args_p[0])) { return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); } /* 5. */ - if (len == 0 && ecma_is_value_undefined (initial_value)) + if (len == 0 && args_number == 1) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Initial value cannot be undefined.")); + return ecma_raise_type_error (ECMA_ERR_MSG ("Reduce of empty array with no initial value.")); } - JERRY_ASSERT (ecma_is_value_object (callbackfn)); - ecma_object_t *func_object_p = ecma_get_object_from_value (callbackfn); + JERRY_ASSERT (ecma_is_value_object (args_p[0])); + ecma_object_t *func_object_p = ecma_get_object_from_value (args_p[0]); ecma_value_t accumulator = ECMA_VALUE_UNDEFINED; @@ -1835,7 +2170,7 @@ ecma_builtin_array_reduce_from (ecma_value_t callbackfn, /**< routine's 1st argu /* 7.a */ if (args_number > 1) { - accumulator = ecma_copy_value (initial_value); + accumulator = ecma_copy_value (args_p[1]); } else { @@ -1918,7 +2253,99 @@ ecma_builtin_array_reduce_from (ecma_value_t callbackfn, /**< routine's 1st argu return accumulator; } /* ecma_builtin_array_reduce_from */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) + +/** + * The Array.prototype object's 'fill' routine + * + * Note: this method only supports length up to uint32, instead of max_safe_integer + * + * See also: + * ECMA-262 v6, 22.1.3.6 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_prototype_fill (ecma_value_t value, /**< value */ + ecma_value_t start_val, /**< start value */ + ecma_value_t end_val, /**< end value */ + ecma_object_t *obj_p, /**< array object */ + uint32_t len) /**< array object's length */ +{ + uint32_t k, final; + + /* 5. 6. 7. */ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (start_val, + len, + &k))) + { + return ECMA_VALUE_ERROR; + } + + /* 8. */ + if (ecma_is_value_undefined (end_val)) + { + final = len; + } + else + { + /* 8 part 2, 9, 10 */ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (end_val, + len, + &final))) + { + return ECMA_VALUE_ERROR; + } + } + + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE + && ecma_op_ordinary_object_is_extensible (obj_p)) + { + if (JERRY_UNLIKELY (obj_p->u1.property_list_cp == JMEM_CP_NULL)) + { + ecma_ref_object (obj_p); + return ecma_make_object_value (obj_p); + } + + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + while (k < final) + { + ecma_free_value_if_not_object (buffer_p[k]); + buffer_p[k] = ecma_copy_value_if_not_object (value); + k++; + } + + ecma_ref_object (obj_p); + return ecma_make_object_value (obj_p); + } + } + + /* 11. */ + while (k < final) + { + /* 11.a - 11.b */ + ecma_value_t put_val = ecma_op_object_put_by_number_index (obj_p, k, value, true); + + /* 11. c */ + if (ECMA_IS_VALUE_ERROR (put_val)) + { + return put_val; + } + + /* 11.d */ + k++; + } + + ecma_ref_object (obj_p); + return ecma_make_object_value (obj_p); +} /* ecma_builtin_array_prototype_fill */ + /** * The Array.prototype object's 'find' and 'findIndex' routine * @@ -1952,85 +2379,207 @@ ecma_builtin_array_prototype_object_find (ecma_value_t predicate, /**< callback for (uint32_t index = 0; index < len; index++) { /* 8.a - 8.c */ - ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, index); + ecma_value_t get_value = ecma_op_object_get_by_uint32_index (obj_p, index); if (ECMA_IS_VALUE_ERROR (get_value)) { return get_value; } - if (ecma_is_value_found (get_value)) + /* 8.d - 8.e */ + ecma_value_t current_index = ecma_make_uint32_value (index); + + ecma_value_t call_args[] = { get_value, current_index, ecma_make_object_value (obj_p) }; + + ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); + + if (ECMA_IS_VALUE_ERROR (call_value)) { - /* 8.d - 8.e */ - ecma_value_t current_index = ecma_make_uint32_value (index); + ecma_free_value (get_value); + return call_value; + } - ecma_value_t call_args[] = { get_value, current_index, ecma_make_object_value (obj_p) }; + bool call_value_to_bool = ecma_op_to_boolean (call_value); - ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); + ecma_free_value (call_value); - if (ECMA_IS_VALUE_ERROR (call_value)) + if (call_value_to_bool) + { + /* 8.f */ + if (is_find) { - ecma_free_value (get_value); - return call_value; - } - - bool call_value_to_bool = ecma_op_to_boolean (call_value); - - ecma_free_value (call_value); - - if (call_value_to_bool) - { - /* 8.f */ - if (is_find) - { - ecma_free_value (current_index); - return get_value; - } - - ecma_free_value (get_value); - return current_index; + ecma_free_value (current_index); + return get_value; } ecma_free_value (get_value); - ecma_free_value (current_index); + return current_index; } + + ecma_free_value (get_value); + ecma_free_value (current_index); } /* 9. */ return is_find ? ECMA_VALUE_UNDEFINED : ecma_make_integer_value (-1); } /* ecma_builtin_array_prototype_object_find */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) /** - * Helper function for Array.prototype object's {'keys', 'values', 'entries', '@@iterator'} - * routines common parts. + * The Array.prototype object's 'copyWithin' routine * * See also: - * ECMA-262 v6, 22.1.3.4 - * ECMA-262 v6, 22.1.3.13 - * ECMA-262 v6, 22.1.3.29 - * ECMA-262 v6, 22.1.3.30 + * ECMA-262 v6, 22.1.3.3 * - * Note: - * Returned value must be freed with ecma_free_value. - * - * @return iterator result object, if success - * error - otherwise + * @return ecma value + * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_iterators_helper (ecma_object_t *obj_p, /**< array object */ - uint8_t type) /**< any combination of - * ecma_iterator_type_t bits */ +ecma_builtin_array_prototype_object_copy_within (const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number, /**< number of arguments */ + ecma_object_t *obj_p, /**< array object */ + uint32_t len) /**< array object's length */ { - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_ITERATOR_PROTOTYPE); + if (args_number == 0) + { + return ecma_copy_value (ecma_make_object_value (obj_p)); + } - return ecma_op_create_iterator_object (ecma_make_object_value (obj_p), - prototype_obj_p, - ECMA_PSEUDO_ARRAY_ITERATOR, - type); -} /* ecma_builtin_array_iterators_helper */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ + /* 5 - 7 */ + uint32_t target; + + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0], len, &target))) + { + return ECMA_VALUE_ERROR; + } + + uint32_t start = 0; + uint32_t end = len; + + if (args_number > 1) + { + /* 8 - 10 */ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[1], len, &start))) + { + return ECMA_VALUE_ERROR; + } + + if (args_number > 2) + { + /* 11 */ + if (ecma_is_value_undefined (args[2])) + { + end = len; + } + else + { + /* 11 part 2, 12, 13 */ + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[2], len, &end))) + { + return ECMA_VALUE_ERROR; + } + } + } + } + + if (target >= len || start >= end || end == 0) + { + ecma_ref_object (obj_p); + return ecma_make_object_value (obj_p); + } + + uint32_t count = JERRY_MIN (end - start, len - target); + + bool forward = true; + + if (start < target && target < start + count) + { + start = start + count - 1; + target = target + count - 1; + forward = false; + } + + if (ecma_op_object_is_fast_array (obj_p)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + + if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE) + { + if (obj_p->u1.property_list_cp != JMEM_CP_NULL) + { + ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); + + for (; count > 0; count--) + { + ecma_value_t copy_value = ecma_copy_value_if_not_object (buffer_p[start]); + + ecma_free_value_if_not_object (buffer_p[target]); + + buffer_p[target] = copy_value; + + if (forward) + { + start++; + target++; + } + else + { + start--; + target--; + } + } + } + + ecma_ref_object (obj_p); + return ecma_make_object_value (obj_p); + } + } + + while (count > 0) + { + ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, start); + + if (ECMA_IS_VALUE_ERROR (get_value)) + { + return get_value; + } + + ecma_value_t op_value; + + if (ecma_is_value_found (get_value)) + { + op_value = ecma_op_object_put_by_uint32_index (obj_p, target, get_value, true); + } + else + { + op_value = ecma_op_object_delete_by_uint32_index (obj_p, target, true); + } + + ecma_free_value (get_value); + + if (ECMA_IS_VALUE_ERROR (op_value)) + { + return op_value; + } + + ecma_free_value (op_value); + + if (forward) + { + start++; + target++; + } + else + { + start--; + target--; + } + + count--; + } + + return ecma_copy_value (ecma_make_object_value (obj_p)); +} /* ecma_builtin_array_prototype_object_copy_within */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Dispatcher of the built-in's routines @@ -2075,34 +2624,29 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< return ret_value; } -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) if (JERRY_UNLIKELY (builtin_routine_id >= ECMA_ARRAY_PROTOTYPE_ENTRIES - && builtin_routine_id <= ECMA_ARRAY_PROTOTYPE_SYMBOL_ITERATOR)) + && builtin_routine_id <= ECMA_ARRAY_PROTOTYPE_KEYS)) { ecma_value_t ret_value; if (builtin_routine_id == ECMA_ARRAY_PROTOTYPE_ENTRIES) { - ret_value = ecma_builtin_array_iterators_helper (obj_p, ECMA_ITERATOR_KEYS_VALUES); - } - else if (builtin_routine_id == ECMA_ARRAY_PROTOTYPE_KEYS) - { - ret_value = ecma_builtin_array_iterators_helper (obj_p, ECMA_ITERATOR_KEYS); + ret_value = ecma_op_create_array_iterator (obj_p, ECMA_ITERATOR_KEYS_VALUES); } else { - JERRY_ASSERT (builtin_routine_id == ECMA_ARRAY_PROTOTYPE_VALUES - || builtin_routine_id == ECMA_ARRAY_PROTOTYPE_SYMBOL_ITERATOR); - - ret_value = ecma_builtin_array_iterators_helper (obj_p, ECMA_ITERATOR_VALUES); + JERRY_ASSERT (builtin_routine_id == ECMA_ARRAY_PROTOTYPE_KEYS); + ret_value = ecma_op_create_array_iterator (obj_p, ECMA_ITERATOR_KEYS); } ecma_deref_object (obj_p); return ret_value; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ - ecma_value_t len_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH); + uint32_t length; + ecma_value_t len_value = ecma_op_object_get_length (obj_p, &length); if (ECMA_IS_VALUE_ERROR (len_value)) { @@ -2110,18 +2654,7 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< return len_value; } - ecma_number_t length_number; - ecma_value_t ret_value = ecma_get_number (len_value, &length_number); - - if (!ecma_is_value_empty (ret_value)) - { - ecma_free_value (len_value); - ecma_deref_object (obj_p); - return ret_value; - } - - uint32_t length = ecma_number_to_uint32 (length_number); - + ecma_value_t ret_value; ecma_value_t routine_arg_1 = arguments_list_p[0]; ecma_value_t routine_arg_2 = arguments_list_p[1]; @@ -2194,8 +2727,8 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< } case ECMA_ARRAY_PROTOTYPE_INDEX_OF: { - ret_value = ecma_builtin_array_prototype_object_index_of (routine_arg_1, - routine_arg_2, + ret_value = ecma_builtin_array_prototype_object_index_of (arguments_list_p, + arguments_number, obj_p, length); break; @@ -2230,15 +2763,22 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< case ECMA_ARRAY_PROTOTYPE_REDUCE: case ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT: { - ret_value = ecma_builtin_array_reduce_from (routine_arg_1, - routine_arg_2, + ret_value = ecma_builtin_array_reduce_from (arguments_list_p, arguments_number, builtin_routine_id == ECMA_ARRAY_PROTOTYPE_REDUCE, obj_p, length); break; } -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) + case ECMA_ARRAY_PROTOTYPE_COPY_WITHIN: + { + ret_value = ecma_builtin_array_prototype_object_copy_within (arguments_list_p, + arguments_number, + obj_p, + length); + break; + } case ECMA_ARRAY_PROTOTYPE_FIND: case ECMA_ARRAY_PROTOTYPE_FIND_INDEX: { @@ -2249,7 +2789,16 @@ ecma_builtin_array_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< length); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + case ECMA_ARRAY_PROTOTYPE_FILL: + { + ret_value = ecma_builtin_array_prototype_fill (routine_arg_1, + routine_arg_2, + arguments_list_p[2], + obj_p, + length); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (builtin_routine_id == ECMA_ARRAY_PROTOTYPE_FILTER); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h index ad86d85e..04a3f15c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.inc.h @@ -29,6 +29,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_ARRAY, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#if ENABLED (JERRY_ES2015) +/* ECMA-262 v6, 22.1.3.31 */ +OBJECT_VALUE (LIT_GLOBAL_SYMBOL_UNSCOPABLES, + ECMA_BUILTIN_ID_ARRAY_PROTOTYPE_UNSCOPABLES, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +#endif /* ENABLED (JERRY_ES2015) */ + /* Number properties: * (property name, object pointer getter) */ @@ -60,18 +67,20 @@ ROUTINE (LIT_MAGIC_STRING_FOR_EACH_UL, ECMA_ARRAY_PROTOTYPE_FOR_EACH, 2, 1) ROUTINE (LIT_MAGIC_STRING_MAP, ECMA_ARRAY_PROTOTYPE_MAP, 2, 1) ROUTINE (LIT_MAGIC_STRING_FILTER, ECMA_ARRAY_PROTOTYPE_FILTER, 2, 1) /* Note these 2 routines must be in this order */ -ROUTINE (LIT_MAGIC_STRING_REDUCE, ECMA_ARRAY_PROTOTYPE_REDUCE, NON_FIXED, 1) -ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT, NON_FIXED, 1) -#if ENABLED (JERRY_ES2015_BUILTIN) +ROUTINE (LIT_MAGIC_STRING_REDUCE, ECMA_ARRAY_PROTOTYPE_REDUCE, 2, 1) +ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ECMA_ARRAY_PROTOTYPE_REDUCE_RIGHT, 2, 1) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_FIND, ECMA_ARRAY_PROTOTYPE_FIND, 2, 1) ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ECMA_ARRAY_PROTOTYPE_FIND_INDEX, 2, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +ROUTINE (LIT_MAGIC_STRING_FILL, ECMA_ARRAY_PROTOTYPE_FILL, 3, 1) +ROUTINE (LIT_MAGIC_STRING_COPY_WITHIN, ECMA_ARRAY_PROTOTYPE_COPY_WITHIN, NON_FIXED, 2) ROUTINE (LIT_MAGIC_STRING_ENTRIES, ECMA_ARRAY_PROTOTYPE_ENTRIES, 0, 0) -ROUTINE (LIT_MAGIC_STRING_VALUES, ECMA_ARRAY_PROTOTYPE_VALUES, 0, 0) ROUTINE (LIT_MAGIC_STRING_KEYS, ECMA_ARRAY_PROTOTYPE_KEYS, 0, 0) -ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ECMA_ARRAY_PROTOTYPE_SYMBOL_ITERATOR, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_VALUES, LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +INTRINSIC_PROPERTY (LIT_GLOBAL_SYMBOL_ITERATOR, LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c index deb16d62..d676b798 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c @@ -15,14 +15,17 @@ #include "ecma-alloc.h" #include "ecma-builtins.h" +#include "ecma-builtin-helpers.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" +#include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "ecma-iterator-object.h" #include "ecma-objects.h" #include "ecma-array-object.h" -#include "ecma-try-catch-macro.h" +#include "jcontext.h" #include "jrt.h" #if ENABLED (JERRY_BUILTIN_ARRAY) @@ -58,20 +61,419 @@ ecma_builtin_array_object_is_array (ecma_value_t this_arg, /**< 'this' argument ecma_value_t arg) /**< first argument */ { JERRY_UNUSED (this_arg); - ecma_value_t is_array = ECMA_VALUE_FALSE; - if (ecma_is_value_object (arg)) + return ecma_is_value_array (arg); +} /* ecma_builtin_array_object_is_array */ + +#if ENABLED (JERRY_ES2015) +/** + * The Array object's 'from' routine + * + * See also: + * ECMA-262 v6, 22.1.2.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_object_from (ecma_value_t this_arg, /**< 'this' argument */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + /* 1. */ + ecma_value_t constructor = this_arg; + ecma_value_t call_this_arg = ECMA_VALUE_UNDEFINED; + ecma_value_t items = arguments_list_p[0]; + ecma_value_t mapfn = (arguments_list_len > 1) ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED; + + /* 2. */ + ecma_object_t *mapfn_obj_p = NULL; + + /* 3. */ + if (!ecma_is_value_undefined (mapfn)) { - ecma_object_t *obj_p = ecma_get_object_from_value (arg); - - if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_ARRAY_UL) + /* 3.a */ + if (!ecma_op_is_callable (mapfn)) { - is_array = ECMA_VALUE_TRUE; + return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); } + + /* 3.b */ + if (arguments_list_len > 2) + { + call_this_arg = arguments_list_p[2]; + } + + /* 3.c */ + mapfn_obj_p = ecma_get_object_from_value (mapfn); } - return is_array; -} /* ecma_builtin_array_object_is_array */ + /* 4. */ + ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items, LIT_GLOBAL_SYMBOL_ITERATOR); + + /* 5. */ + if (ECMA_IS_VALUE_ERROR (using_iterator)) + { + return using_iterator; + } + + ecma_value_t ret_value = ECMA_VALUE_ERROR; + + /* 6. */ + if (!ecma_is_value_undefined (using_iterator)) + { + ecma_value_t array; + + /* 6.a */ + if (ecma_is_constructor (constructor)) + { + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); + + array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, NULL, 0); + + if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) + { + ecma_free_value (using_iterator); + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object")); + } + } + else + { + /* 6.b */ + array = ecma_op_create_array_object (NULL, 0, false); + } + + /* 6.c */ + if (ECMA_IS_VALUE_ERROR (array)) + { + ecma_free_value (using_iterator); + return array; + } + + ecma_object_t *array_obj_p = ecma_get_object_from_value (array); + + /* 6.d */ + ecma_value_t iterator = ecma_op_get_iterator (items, using_iterator); + ecma_free_value (using_iterator); + + /* 6.e */ + if (ECMA_IS_VALUE_ERROR (iterator)) + { + ecma_free_value (array); + return iterator; + } + + /* 6.f */ + uint32_t k = 0; + + /* 6.g */ + while (true) + { + /* 6.g.ii */ + ecma_value_t next = ecma_op_iterator_step (iterator); + + /* 6.g.iii */ + if (ECMA_IS_VALUE_ERROR (next)) + { + goto iterator_cleanup; + } + + /* 6.g.iii */ + if (ecma_is_value_false (next)) + { + /* 6.g.iv.1 */ + ecma_value_t len_value = ecma_make_uint32_value (k); + ecma_value_t set_status = ecma_op_object_put (array_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), + len_value, + true); + ecma_free_value (len_value); + + /* 6.g.iv.2 */ + if (ECMA_IS_VALUE_ERROR (set_status)) + { + goto iterator_cleanup; + } + + ecma_free_value (iterator); + /* 6.g.iv.3 */ + return array; + } + + /* 6.g.v */ + ecma_value_t next_value = ecma_op_iterator_value (next); + + ecma_free_value (next); + + /* 6.g.vi */ + if (ECMA_IS_VALUE_ERROR (next_value)) + { + goto iterator_cleanup; + } + + ecma_value_t mapped_value; + /* 6.g.vii */ + if (mapfn_obj_p != NULL) + { + /* 6.g.vii.1 */ + ecma_value_t args_p[2] = { next_value, ecma_make_uint32_value (k) }; + /* 6.g.vii.3 */ + mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2); + ecma_free_value (args_p[1]); + ecma_free_value (next_value); + + /* 6.g.vii.2 */ + if (ECMA_IS_VALUE_ERROR (mapped_value)) + { + ecma_op_iterator_close (iterator); + goto iterator_cleanup; + } + } + else + { + /* 6.g.viii */ + mapped_value = next_value; + } + + /* 6.g.ix */ + const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; + ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags); + + ecma_free_value (mapped_value); + + /* 6.g.x */ + if (ECMA_IS_VALUE_ERROR (set_status)) + { + ecma_op_iterator_close (iterator); + goto iterator_cleanup; + } + + /* 6.g.xi */ + k++; + } + +iterator_cleanup: + ecma_free_value (iterator); + ecma_free_value (array); + + return ret_value; + } + + /* 8. */ + ecma_value_t array_like = ecma_op_to_object (items); + + /* 9. */ + if (ECMA_IS_VALUE_ERROR (array_like)) + { + return array_like; + } + + ecma_object_t *array_like_obj_p = ecma_get_object_from_value (array_like); + + /* 10. */ + uint32_t len; + ecma_value_t len_value = ecma_op_object_get_length (array_like_obj_p, &len); + + /* 11. */ + if (ECMA_IS_VALUE_ERROR (len_value)) + { + goto cleanup; + } + + len_value = ecma_make_uint32_value (len); + + /* 12. */ + ecma_value_t array; + + /* 12.a */ + if (ecma_is_constructor (constructor)) + { + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); + + array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, &len_value, 1); + + if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) + { + ecma_free_value (len_value); + ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object")); + goto cleanup; + } + } + else + { + /* 13.a */ + array = ecma_op_create_array_object (&len_value, 1, true); + } + + ecma_free_value (len_value); + + /* 14. */ + if (ECMA_IS_VALUE_ERROR (array)) + { + goto cleanup; + } + + ecma_object_t *array_obj_p = ecma_get_object_from_value (array); + + /* 15. */ + uint32_t k = 0; + + /* 16. */ + while (k < len) + { + /* 16.b */ + ecma_value_t k_value = ecma_op_object_get_by_uint32_index (array_like_obj_p, k); + + /* 16.c */ + if (ECMA_IS_VALUE_ERROR (k_value)) + { + goto construct_cleanup; + } + + ecma_value_t mapped_value; + /* 16.d */ + if (mapfn_obj_p != NULL) + { + /* 16.d.i */ + ecma_value_t args_p[2] = { k_value, ecma_make_uint32_value (k) }; + mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2); + ecma_free_value (args_p[1]); + ecma_free_value (k_value); + + /* 16.d.ii */ + if (ECMA_IS_VALUE_ERROR (mapped_value)) + { + goto construct_cleanup; + } + } + else + { + /* 16.e */ + mapped_value = k_value; + } + + /* 16.f */ + const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; + ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags); + + ecma_free_value (mapped_value); + + /* 16.g */ + if (ECMA_IS_VALUE_ERROR (set_status)) + { + goto construct_cleanup; + } + + /* 16.h */ + k++; + } + + /* 17. */ + len_value = ecma_make_uint32_value (k); + ecma_value_t set_status = ecma_op_object_put (array_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), + len_value, + true); + ecma_free_value (len_value); + + /* 18. */ + if (ECMA_IS_VALUE_ERROR (set_status)) + { + goto construct_cleanup; + } + + /* 19. */ + ecma_deref_object (array_like_obj_p); + return ecma_make_object_value (array_obj_p); + +construct_cleanup: + ecma_deref_object (array_obj_p); +cleanup: + ecma_deref_object (array_like_obj_p); + return ret_value; +} /* ecma_builtin_array_object_from */ + +/** + * The Array object's 'of' routine + * + * See also: + * ECMA-262 v6, 22.1.2.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + if (!ecma_is_constructor (this_arg)) + { + return ecma_op_create_array_object (arguments_list_p, arguments_list_len, false); + } + + ecma_value_t len = ecma_make_uint32_value (arguments_list_len); + + ecma_value_t ret_val = ecma_op_function_construct (ecma_get_object_from_value (this_arg), + ecma_get_object_from_value (this_arg), + &len, + 1); + + if (ECMA_IS_VALUE_ERROR (ret_val)) + { + ecma_free_value (len); + return ret_val; + } + + uint32_t k = 0; + ecma_object_t *obj_p = ecma_get_object_from_value (ret_val); + const uint32_t prop_status_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; + + while (k < arguments_list_len) + { + ecma_value_t define_status = ecma_builtin_helper_def_prop_by_index (obj_p, + k, + arguments_list_p[k], + prop_status_flags); + + if (ECMA_IS_VALUE_ERROR (define_status)) + { + ecma_free_value (len); + ecma_deref_object (obj_p); + return define_status; + } + + k++; + } + + ret_val = ecma_op_object_put (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), + len, + true); + + ecma_free_value (len); + + if (ECMA_IS_VALUE_ERROR (ret_val)) + { + ecma_deref_object (obj_p); + return ret_val; + } + + return ecma_make_object_value (obj_p); +} /* ecma_builtin_array_object_of */ + +/** + * 22.1.2.5 get Array [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_array_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_array_species_get */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Handle calling [[Call]] of built-in Array object @@ -84,7 +486,7 @@ ecma_builtin_array_dispatch_call (const ecma_value_t *arguments_list_p, /**< arg { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - return ecma_builtin_array_dispatch_construct (arguments_list_p, arguments_list_len); + return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); } /* ecma_builtin_array_dispatch_call */ /** @@ -98,7 +500,30 @@ ecma_builtin_array_dispatch_construct (const ecma_value_t *arguments_list_p, /** { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); +#if !ENABLED (JERRY_ES2015) return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); +#else /* ENABLED (JERRY_ES2015) */ + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), + ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); + + if (proto_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ecma_op_create_array_object (arguments_list_p, arguments_list_len, true); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (proto_p); + return ECMA_VALUE_ERROR; + } + + ecma_object_t *object_p = ecma_get_object_from_value (result); + ECMA_SET_NON_NULL_POINTER (object_p->u2.prototype_cp, proto_p); + ecma_deref_object (proto_p); + return result; +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_builtin_array_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h index ccea4a5e..ff1df5f0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h @@ -32,14 +32,22 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* Number properties: * (property name, object pointer getter) */ -/* ECMA-262 v5, 15.4.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_IS_ARRAY_UL, ecma_builtin_array_object_is_array, 1, 1) +#if ENABLED (JERRY_ES2015) +ROUTINE (LIT_MAGIC_STRING_FROM, ecma_builtin_array_object_from, NON_FIXED, 1) +ROUTINE (LIT_MAGIC_STRING_OF, ecma_builtin_array_object_of, NON_FIXED, 0) + +/* ECMA-262 v6, 22.1.2.5 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_array_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +#endif /* ENABLED (JERRY_ES2015) */ #endif /* !(ENABLED (JERRY_BUILTIN_ARRAY)) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c index e393912f..2256d38e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c @@ -61,6 +61,10 @@ ecma_builtin_arraybuffer_prototype_bytelength_getter (ecma_value_t this_arg) /** if (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)) { + if (ecma_arraybuffer_is_detached (object_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_length_t len = ecma_arraybuffer_get_length (object_p); return ecma_make_uint32_value (len); @@ -96,31 +100,34 @@ ecma_builtin_arraybuffer_prototype_object_slice (ecma_value_t this_arg, /**< thi return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an ArrayBuffer object.")); } + if (ecma_arraybuffer_is_detached (object_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_length_t len = ecma_arraybuffer_get_length (object_p); ecma_length_t start = 0, end = len; ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ECMA_OP_TO_NUMBER_TRY_CATCH (start_num, - arg1, - ret_value); - - start = ecma_builtin_helper_array_index_normalize (start_num, len, false); + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg1, + len, + &start))) + { + return ECMA_VALUE_ERROR; + } if (!ecma_is_value_undefined (arg2)) { - ECMA_OP_TO_NUMBER_TRY_CATCH (end_num, - arg2, - ret_value); - - end = ecma_builtin_helper_array_index_normalize (end_num, len, false); - - ECMA_OP_TO_NUMBER_FINALIZE (end_num); + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg2, + len, + &end))) + { + return ECMA_VALUE_ERROR; + } } - ECMA_OP_TO_NUMBER_FINALIZE (start_num); - if (ret_value != ECMA_VALUE_EMPTY) { return ret_value; diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.inc.h index 852e356e..6753cac6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.inc.h @@ -31,14 +31,14 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, /* Readonly accessor properties */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_LENGTH_UL, ecma_builtin_arraybuffer_prototype_bytelength_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 24.1.4.4 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_ARRAY_BUFFER_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c index 94cbe108..57874b06 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c @@ -19,7 +19,9 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-arraybuffer-object.h" +#include "ecma-dataview-object.h" #include "ecma-try-catch-macro.h" +#include "ecma-typedarray-object.h" #include "jrt.h" #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -55,11 +57,12 @@ ecma_builtin_arraybuffer_object_is_view (ecma_value_t this_arg, /**< 'this' argu ecma_value_t arg) /**< argument 1 */ { JERRY_UNUSED (this_arg); +#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) + return ecma_make_boolean_value (ecma_is_typedarray (arg) || ecma_is_dataview (arg)); +#else JERRY_UNUSED (arg); - - /* TODO: if arg has [[ViewArrayBuffer]], return true */ - return ECMA_VALUE_FALSE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW */ } /* ecma_builtin_arraybuffer_object_is_view */ /** @@ -94,6 +97,18 @@ ecma_builtin_arraybuffer_dispatch_construct (const ecma_value_t *arguments_list_ return ecma_op_create_arraybuffer_object (arguments_list_p, arguments_list_len); } /* ecma_builtin_arraybuffer_dispatch_construct */ +/** + * 24.1.3.3 get ArrayBuffer [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_arraybuffer_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_arraybuffer_species_get */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h index 2ed9fa4a..a3b162f3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h @@ -26,7 +26,7 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* Object properties: * (property name, object pointer getter) */ @@ -41,6 +41,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* ES2015 24.1.3.1 */ ROUTINE (LIT_MAGIC_STRING_IS_VIEW_UL, ecma_builtin_arraybuffer_object_is_view, 1, 1) +/* ES2015 24.1.3.3 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_arraybuffer_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-boolean.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-boolean.inc.h index a26f129d..dd5132b9 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-boolean.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-boolean.inc.h @@ -32,10 +32,9 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* Number properties: * (property name, object pointer getter) */ -/* ECMA-262 v5, 15.6.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) #endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c index fc443f95..8f2240e0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "ecma-arraybuffer-object.h" +#include "ecma-exceptions.h" #include "ecma-dataview-object.h" #include "ecma-gc.h" @@ -110,11 +112,20 @@ ecma_builtin_dataview_prototype_object_getters (ecma_value_t this_arg, /**< this } case ECMA_DATAVIEW_PROTOTYPE_BYTE_LENGTH_GETTER: { + if (ecma_arraybuffer_is_detached (obj_p->buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } return ecma_make_uint32_value (obj_p->header.u.class_prop.u.length); } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATAVIEW_PROTOTYPE_BYTE_OFFSET_GETTER); + + if (ecma_arraybuffer_is_detached (obj_p->buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } return ecma_make_uint32_value (obj_p->byte_offset); } } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.inc.h index 3dd9efde..03b9a703 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.inc.h @@ -29,12 +29,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_DATAVIEW, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 23.2.4.21 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_DATAVIEW_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -62,17 +62,17 @@ ROUTINE (LIT_MAGIC_STRING_SET_UINT32_UL, ECMA_DATAVIEW_PROTOTYPE_SET_UINT32, 2, /* ECMA-262 v6, 24.2.4.1 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BUFFER, ECMA_DATAVIEW_PROTOTYPE_BUFFER_GETTER, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ECMA-262 v6, 24.2.4.2 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_LENGTH_UL, ECMA_DATAVIEW_PROTOTYPE_BYTE_LENGTH_GETTER, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ECMA-262 v6, 24.2.4.3 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_OFFSET_UL, ECMA_DATAVIEW_PROTOTYPE_BYTE_OFFSET_GETTER, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview.inc.h index 75fbc688..0732f6c6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview.inc.h @@ -27,7 +27,7 @@ /* ECMA-262 v6, 23.1.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 3, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ECMA-262 v6, 23.1 */ STRING_VALUE (LIT_MAGIC_STRING_NAME, diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c index 95b83a0c..d80d15f1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c @@ -22,6 +22,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" #if ENABLED (JERRY_BUILTIN_DATE) @@ -98,6 +99,10 @@ enum ECMA_DATE_PROTOTYPE_GET_TIME, /* ECMA-262 v5, 15.9.5.9 */ ECMA_DATE_PROTOTYPE_SET_TIME, /* ECMA-262 v5, 15.9.5.27 */ ECMA_DATE_PROTOTYPE_TO_JSON, /* ECMA-262 v5, 15.9.5.44 */ + +#if ENABLED (JERRY_ES2015) + ECMA_DATE_PROTOTYPE_TO_PRIMITIVE, /* ECMA-262 v6 20.3.4.45 */ +#endif /* ENABLED (JERRY_ES2015) */ }; #define BUILTIN_INC_HEADER_NAME "ecma-builtin-date-prototype.inc.h" @@ -179,6 +184,46 @@ ecma_builtin_date_prototype_to_json (ecma_value_t this_arg) /**< this argument * return ret_value; } /* ecma_builtin_date_prototype_to_json */ +#if ENABLED (JERRY_ES2015) +/** + * The Date.prototype object's toPrimitive routine + * + * See also: + * ECMA-262 v6, 20.3.4.45 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_date_prototype_to_primitive (ecma_value_t this_arg, /**< this argument */ + ecma_value_t hint_arg) /**< {"default", "number", "string"} */ +{ + if (ecma_is_value_object (this_arg) && ecma_is_value_string (hint_arg)) + { + ecma_string_t *hint_str_p = ecma_get_string_from_value (hint_arg); + + ecma_preferred_type_hint_t hint = ECMA_PREFERRED_TYPE_NUMBER; + + if (hint_str_p == ecma_get_magic_string (LIT_MAGIC_STRING_STRING) + || hint_str_p == ecma_get_magic_string (LIT_MAGIC_STRING_DEFAULT)) + { + hint = ECMA_PREFERRED_TYPE_STRING; + } + else if (hint_str_p == ecma_get_magic_string (LIT_MAGIC_STRING_NUMBER)) + { + hint = ECMA_PREFERRED_TYPE_NUMBER; + } + + if (hint != ECMA_PREFERRED_TYPE_NO) + { + return ecma_op_general_object_ordinary_value (ecma_get_object_from_value (this_arg), hint); + } + } + + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type in toPrimitive.")); +} /* ecma_builtin_date_prototype_to_primitive */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * Dispatch get date functions * @@ -192,7 +237,7 @@ ecma_builtin_date_prototype_dispatch_get (uint16_t builtin_routine_id, /**< buil { if (ecma_number_is_nan (date_num)) { - return ecma_make_magic_string_value (LIT_MAGIC_STRING_NAN); + return ecma_make_nan_value (); } switch (builtin_routine_id) @@ -560,15 +605,21 @@ ecma_builtin_date_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< return ecma_builtin_date_prototype_to_json (this_arg); } +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_PRIMITIVE)) + { + ecma_value_t argument = arguments_number > 0 ? arguments_list[0] : ECMA_VALUE_UNDEFINED; + return ecma_builtin_date_prototype_to_primitive (this_arg, argument); + } +#endif /* ENABLED (JERRY_ES2015) */ + if (!ecma_is_value_object (this_arg) || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_DATE_UL)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Date object expected")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Date object")); } - ecma_object_t *object_p = ecma_get_object_from_value (this_arg); - - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); ecma_number_t *prim_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.inc.h index 54308014..765fe4b6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.inc.h @@ -68,6 +68,9 @@ ROUTINE (LIT_MAGIC_STRING_SET_UTC_FULL_YEAR_UL, ECMA_DATE_PROTOTYPE_SET_UTC_FULL ROUTINE (LIT_MAGIC_STRING_TO_UTC_STRING_UL, ECMA_DATE_PROTOTYPE_TO_UTC_STRING, 0, 0) ROUTINE (LIT_MAGIC_STRING_TO_ISO_STRING_UL, ECMA_DATE_PROTOTYPE_TO_ISO_STRING, 0, 0) ROUTINE (LIT_MAGIC_STRING_TO_JSON_UL, ECMA_DATE_PROTOTYPE_TO_JSON, 1, 1) +#if ENABLED (JERRY_ES2015) +ROUTINE_CONFIGURABLE_ONLY (LIT_GLOBAL_SYMBOL_TO_PRIMITIVE, ECMA_DATE_PROTOTYPE_TO_PRIMITIVE, 1, 1) +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c index 615737a3..e04eea78 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c @@ -15,6 +15,8 @@ #include +#include "jcontext.h" +#include "ecma-function-object.h" #include "ecma-alloc.h" #include "ecma-builtin-helpers.h" #include "ecma-conversion.h" @@ -52,22 +54,137 @@ static ecma_number_t ecma_date_parse_date_chars (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */ - uint32_t num_of_chars) /**< number of characters to read and convert */ + uint32_t num_of_chars, /**< number of characters to read and convert */ + uint32_t min, /**< minimum valid value */ + uint32_t max) /**< maximum valid value */ { JERRY_ASSERT (num_of_chars > 0); const lit_utf8_byte_t *str_start_p = *str_p; while (num_of_chars--) { - if (*str_p >= str_end_p || !lit_char_is_decimal_digit (lit_utf8_read_next (str_p))) + if (*str_p >= str_end_p || !lit_char_is_decimal_digit (lit_cesu8_read_next (str_p))) { return ecma_number_make_nan (); } } - return ecma_utf8_string_to_number (str_start_p, (lit_utf8_size_t) (*str_p - str_start_p)); + ecma_number_t parsed_number = ecma_utf8_string_to_number (str_start_p, (lit_utf8_size_t) (*str_p - str_start_p)); + + if (parsed_number < min || parsed_number > max) + { + return ecma_number_make_nan (); + } + + return parsed_number; } /* ecma_date_parse_date_chars */ +/** + * Helper function to try to parse a special chracter (+,-,T,Z,:,.) in a date string + * + * @return true if the first character is same as the expected, false otherwise + */ +static bool +ecma_date_parse_special_char (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ + const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */ + const lit_utf8_byte_t expected_char) /**< expected character */ +{ + if ((*str_p < str_end_p) && (**str_p == expected_char)) + { + (*str_p)++; + return true; + } + + return false; +} /* ecma_date_parse_special_char */ + +/** + * Helper function to try to parse a 4-5-6 digit year with optional negative sign in a date string + * + * Date.prototype.toString() and Date.prototype.toUTCString() emits year + * in this format and Date.parse() should parse this format too. + * + * @return the parsed year or NaN. + */ +static ecma_number_t +ecma_date_parse_year (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ + const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */ +{ + bool is_year_sign_negative = ecma_date_parse_special_char (str_p, str_end_p, '-'); + const lit_utf8_byte_t *str_start_p = *str_p; + int32_t parsed_year = 0; + + while ((str_start_p - *str_p < 6) && (str_start_p < str_end_p) && lit_char_is_decimal_digit (*str_start_p)) + { + parsed_year = 10 * parsed_year + *str_start_p - LIT_CHAR_0; + str_start_p++; + } + + if (str_start_p - *str_p >=4) + { + *str_p = str_start_p; + if (is_year_sign_negative) + { + return -parsed_year; + } + return parsed_year; + } + + return ecma_number_make_nan (); +} /* ecma_date_parse_year */ + +/** + * Helper function to try to parse a day name in a date string + * Valid day names: Sun, Mon, Tue, Wed, Thu, Fri, Sat + * See also: + * ECMA-262 v9, 20.3.4.41.2 Table 46 + * + * @return true if the string starts with a valid day name, false otherwise + */ +static bool +ecma_date_parse_day_name (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ + const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */ +{ + if (*str_p + 3 < str_end_p) + { + for (uint32_t i = 0; i < 7; i++) + { + if (!memcmp (day_names_p[i], *str_p, 3)) + { + (*str_p) += 3; + return true; + } + } + } + return false; +} /* ecma_date_parse_day_name */ + +/** + * Helper function to try to parse a month name in a date string + * Valid month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec + * See also: + * ECMA-262 v9, 20.3.4.41.2 Table 47 + * + * @return number of the month if the string starts with a valid month name, 0 otherwise + */ +static uint32_t +ecma_date_parse_month_name (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ + const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */ +{ + if (*str_p + 3 < str_end_p) + { + for (uint32_t i = 0; i < 12; i++) + { + if (!memcmp (month_names_p[i], *str_p, 3)) + { + (*str_p) += 3; + return (i+1); + } + } + } + return 0; +} /* ecma_date_parse_month_name */ + /** * Calculate MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) for Date constructor and UTC * @@ -169,52 +286,31 @@ ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to t } /* ecma_date_construct_helper */ /** - * The Date object's 'parse' routine + * Helper function used by ecma_builtin_date_parse * * See also: - * ECMA-262 v5, 15.9.4.2 - * ECMA-262 v5, 15.9.1.15 + * ECMA-262 v5, 15.9.4.2 Date.parse (string) + * ECMA-262 v5, 15.9.1.15 Date Time String Format * - * @return ecma value - * Returned value must be freed with ecma_free_value. + * @return the parsed date as ecma_number_t or NaN otherwise */ -static ecma_value_t -ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ - ecma_value_t arg) /**< string */ +static ecma_number_t +ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_p, + const lit_utf8_byte_t *date_str_end_p) { - JERRY_UNUSED (this_arg); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_number_t date_num = ecma_number_make_nan (); - - /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ - ECMA_TRY_CATCH (date_str_value, - ecma_op_to_string (arg), - ret_value); - - ecma_string_t *date_str_p = ecma_get_string_from_value (date_str_value); - - ECMA_STRING_TO_UTF8_STRING (date_str_p, date_start_p, date_start_size); - - const lit_utf8_byte_t *date_str_curr_p = date_start_p; - const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size; - /* 1. read year */ uint32_t year_digits = 4; - bool year_sign = false; /* false: positive, true: negative */ - if (*date_str_curr_p == '-' || *date_str_curr_p == '+') + + bool is_year_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'); + if (is_year_sign_negative || ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+')) { year_digits = 6; - if (*date_str_curr_p == '-') - { - year_sign = true; - } - /* eat up '-' or '+' */ - date_str_curr_p++; } - ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, year_digits); - if (year_sign) + ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, year_digits, + 0, (year_digits == 4) ? 9999 : 999999); + if (is_year_sign_negative) { year = -year; } @@ -226,40 +322,20 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ ecma_number_t time = ECMA_NUMBER_ZERO; /* 2. read month if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == '-') + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-')) { - /* eat up '-' */ - date_str_curr_p++; - month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); - - if (month > 12 || month < 1) - { - month = ecma_number_make_nan (); - } + month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 12); } /* 3. read day if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == '-') + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-')) { - /* eat up '-' */ - date_str_curr_p++; - day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); - - if (day < 1 || day > 31) - { - day = ecma_number_make_nan (); - } + day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 31); } /* 4. read time if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == 'T') + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T')) { - /* eat up 'T' */ - date_str_curr_p++; - ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; @@ -271,54 +347,28 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ if (remaining_length >= 5) { /* 4.1 read hours and minutes */ - hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); + hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); - if (hours < 0 || hours > 24) + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) { - hours = ecma_number_make_nan (); - } - - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == ':') - { - /* eat up ':' */ - date_str_curr_p++; - - minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); - - if (minutes < 0 || minutes > 59) - { - minutes = ecma_number_make_nan (); - } + minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); /* 4.2 read seconds if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == ':') + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) { - /* eat up ':' */ - date_str_curr_p++; - seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); - - if (seconds < 0 || seconds > 59) - { - seconds = ecma_number_make_nan (); - } + seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); /* 4.3 read milliseconds if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == '.') + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '.')) { - /* eat up '.' */ - date_str_curr_p++; - milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3); - - if (milliseconds < 0) - { - milliseconds = ecma_number_make_nan (); - } + milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, 0, 999); } } } + else + { + minutes = ecma_number_make_nan (); + } if (hours == 24 && (minutes != 0 || seconds != 0 || milliseconds != 0)) { @@ -333,62 +383,29 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ } /* 4.4 read timezone if any */ - if (date_str_curr_p < date_str_end_p - && *date_str_curr_p == 'Z' - && !ecma_number_is_nan (time)) + if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'Z') && !ecma_number_is_nan (time)) { - date_str_curr_p++; time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } - else if (date_str_curr_p < date_str_end_p - && (*date_str_curr_p == '+' || *date_str_curr_p == '-')) + else { - ecma_length_t remaining_date_length; - remaining_date_length = lit_utf8_string_length (date_str_curr_p, - (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) - 1; - - if (remaining_date_length == 5) + bool is_timezone_sign_negative; + if ((lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) == 6) + && ((is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-')) + || ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+'))) { - bool is_negative = false; - - if (*date_str_curr_p == '-') - { - is_negative = true; - } - - /* eat up '+/-' */ - date_str_curr_p++; - /* read hours and minutes */ - hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); + hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); - if (hours < 0 || hours > 24) - { - hours = ecma_number_make_nan (); - } - else if (hours == 24) + if (hours == 24) { hours = ECMA_NUMBER_ZERO; } - /* eat up ':' */ - date_str_curr_p++; - - minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); - - if (minutes < 0 || minutes > 59) - { - minutes = ecma_number_make_nan (); - } - - if (is_negative) - { - time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); - } - else - { - time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); - } + ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'); + minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); + ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); + time += is_timezone_sign_negative ? timezone_offset : -timezone_offset; } } } @@ -396,16 +413,232 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ if (date_str_curr_p >= date_str_end_p) { ecma_number_t date = ecma_date_make_day (year, month - 1, day); - date_num = ecma_date_make_date (date, time); + return ecma_date_make_date (date, time); + } + } + return ecma_number_make_nan (); +} /* ecma_builtin_date_parse_ISO_string_format */ + +/** + * Helper function used by ecma_builtin_date_parse + * + * See also: + * ECMA-262 v5, 15.9.4.2 Date.parse (string) + * ECMA-262 v9, 20.3.4.41 Date.prototype.toString () + * ECMA-262 v9, 20.3.4.43 Date.prototype.toUTCString () + * + * Used by: ecma_builtin_date_parse + * + * @return the parsed date as ecma_number_t or NaN otherwise + */ +static ecma_number_t +ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p, + const lit_utf8_byte_t *date_str_end_p) +{ + const ecma_number_t nan = ecma_number_make_nan (); + + if (!ecma_date_parse_day_name (&date_str_curr_p, date_str_end_p)) + { + return nan; + } + + const bool is_toUTCString_format = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ','); + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + ecma_number_t month = 0; + ecma_number_t day = 0; + if (is_toUTCString_format) + { + day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31); + if (ecma_number_is_nan (day)) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p); + if (!(int) month) + { + return nan; + } + } + else + { + month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p); + if (!(int) month) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31); + if (ecma_number_is_nan (day)) + { + return nan; } } - ret_value = ecma_make_number_value (date_num); + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + ecma_number_t year = ecma_date_parse_year (&date_str_curr_p, date_str_end_p); + if (ecma_number_is_nan (year)) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + ecma_number_t hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); + if (ecma_number_is_nan (hours)) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) + { + return nan; + } + + ecma_number_t minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); + if (ecma_number_is_nan (minutes)) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) + { + return nan; + } + + ecma_number_t seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); + if (ecma_number_is_nan (seconds)) + { + return nan; + } + + if (hours == 24 && (minutes != 0 || seconds != 0)) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'G')) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'M')) + { + return nan; + } + + if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T')) + { + return nan; + } + + ecma_number_t time = ecma_date_make_time (hours, minutes, seconds, 0); + + if (!is_toUTCString_format) + { + bool is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'); + if (!is_timezone_sign_negative && !ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+')) + { + return nan; + } + + hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); + if (ecma_number_is_nan (hours)) + { + return nan; + } + if (hours == 24) + { + hours = ECMA_NUMBER_ZERO; + } + + minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); + if (ecma_number_is_nan (minutes)) + { + return nan; + } + + ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); + time += is_timezone_sign_negative ? timezone_offset : -timezone_offset; + } + + if (date_str_curr_p >= date_str_end_p) + { + ecma_number_t date = ecma_date_make_day (year, month - 1, day); + return ecma_date_make_date (date, time); + } + + return nan; +} /* ecma_builtin_date_parse_toString_formats */ + +/** + * The Date object's 'parse' routine + * + * See also: + * ECMA-262 v5, 15.9.4.2 Date.parse (string) + * ECMA-262 v5, 15.9.1.15 Date Time String Format + * ECMA-262 v9, 20.3.4.41 Date.prototype.toString () + * ECMA-262 v9, 20.3.4.43 Date.prototype.toUTCString () + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */ + ecma_value_t arg) /**< string */ +{ + JERRY_UNUSED (this_arg); + + /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ + ecma_string_t *date_str_p = ecma_op_to_string (arg); + if (JERRY_UNLIKELY (date_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ECMA_STRING_TO_UTF8_STRING (date_str_p, date_start_p, date_start_size); + const lit_utf8_byte_t *date_str_curr_p = date_start_p; + const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size; + + // try to parse date string as ISO string - ECMA-262 v5, 15.9.1.15 + ecma_number_t ret_value = ecma_builtin_date_parse_ISO_string_format (date_str_curr_p, date_str_end_p); + + if (ecma_number_is_nan (ret_value)) + { + // try to parse date string in Date.prototype.toString() or toUTCString() format + ret_value = ecma_builtin_date_parse_toString_formats (date_str_curr_p, date_str_end_p); + } ECMA_FINALIZE_UTF8_STRING (date_start_p, date_start_size); - ECMA_FINALIZE (date_str_value); - - return ret_value; + ecma_deref_ecma_string (date_str_p); + return ecma_make_number_value (ret_value); } /* ecma_builtin_date_parse */ /** @@ -503,6 +736,17 @@ ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< ecma_number_t prim_value_num = ECMA_NUMBER_ZERO; ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_DATE_PROTOTYPE); +#if ENABLED (JERRY_ES2015) + if (JERRY_CONTEXT (current_new_target)) + { + prototype_obj_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), + ECMA_BUILTIN_ID_DATE_PROTOTYPE); + if (JERRY_UNLIKELY (prototype_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + } +#endif /* !(ENABLED (JERRY_ES2015) */ ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); @@ -579,7 +823,12 @@ ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< JERRY_ASSERT (ECMA_IS_VALUE_ERROR (ret_value)); ecma_deref_object (obj_p); } - +#if ENABLED (JERRY_ES2015) + if (JERRY_CONTEXT (current_new_target)) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* !(ENABLED (JERRY_ES2015) */ return ret_value; } /* ecma_builtin_date_dispatch_construct */ @@ -589,4 +838,7 @@ ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< * @} */ +#undef BREAK_IF_FALSE +#undef BREAK_IF_NAN + #endif /* ENABLED (JERRY_BUILTIN_DATE) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-date.inc.h index fc38bf56..f805b779 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date.inc.h @@ -28,7 +28,7 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 7, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) ROUTINE (LIT_MAGIC_STRING_PARSE, ecma_builtin_date_parse, 1, 1) ROUTINE (LIT_MAGIC_STRING_UTC_U, ecma_builtin_date_utc, NON_FIXED, 7) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c index 69312ed3..1d217cb2 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c @@ -20,6 +20,7 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "lit-char-helpers.h" #include "ecma-objects.h" #include "ecma-string-object.h" #include "ecma-try-catch-macro.h" @@ -43,6 +44,34 @@ * @{ */ +/** + * Helper method to get a property value from an error object + * + * @return ecma_string_t + */ +static ecma_string_t * +ecma_builtin_error_prototype_object_to_string_helper (ecma_object_t *obj_p, /**< error object */ + lit_magic_string_id_t property_id, /**< property id */ + lit_magic_string_id_t default_value) /**< default prop value */ +{ + ecma_value_t prop_value = ecma_op_object_get_by_magic_id (obj_p, property_id); + + if (ECMA_IS_VALUE_ERROR (prop_value)) + { + return NULL; + } + + if (ecma_is_value_undefined (prop_value)) + { + return ecma_get_magic_string (default_value); + } + + ecma_string_t *ret_str_p = ecma_op_to_string (prop_value); + ecma_free_value (prop_value); + + return ret_str_p; +} /* ecma_builtin_error_prototype_object_to_string_helper */ + /** * The Error.prototype object's 'toString' routine * @@ -55,125 +84,52 @@ static ecma_value_t ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - /* 2. */ if (!ecma_is_value_object (this_arg)) { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an object.")); + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an object.")); } - else + + ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + + ecma_string_t *name_string_p = ecma_builtin_error_prototype_object_to_string_helper (obj_p, + LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_ERROR_UL); + + if (JERRY_UNLIKELY (name_string_p == NULL)) { - ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); - - ECMA_TRY_CATCH (name_get_ret_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NAME), - ret_value); - - ecma_value_t name_to_str_completion; - - if (ecma_is_value_undefined (name_get_ret_value)) - { - name_to_str_completion = ecma_make_magic_string_value (LIT_MAGIC_STRING_ERROR_UL); - } - else - { - name_to_str_completion = ecma_op_to_string (name_get_ret_value); - } - - if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (name_to_str_completion))) - { - ret_value = ecma_copy_value (name_to_str_completion); - } - else - { - ECMA_TRY_CATCH (msg_get_ret_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_MESSAGE), - ret_value); - - ecma_value_t msg_to_str_completion; - - if (ecma_is_value_undefined (msg_get_ret_value)) - { - msg_to_str_completion = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - } - else - { - msg_to_str_completion = ecma_op_to_string (msg_get_ret_value); - } - - if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (msg_to_str_completion))) - { - ret_value = ecma_copy_value (msg_to_str_completion); - } - else - { - ecma_string_t *name_string_p = ecma_get_string_from_value (name_to_str_completion); - ecma_string_t *msg_string_p = ecma_get_string_from_value (msg_to_str_completion); - - ecma_string_t *ret_str_p; - - if (ecma_string_is_empty (name_string_p)) - { - ret_str_p = msg_string_p; - ecma_ref_ecma_string (ret_str_p); - } - else if (ecma_string_is_empty (msg_string_p)) - { - ret_str_p = name_string_p; - ecma_ref_ecma_string (ret_str_p); - } - else - { - const lit_utf8_size_t name_size = ecma_string_get_size (name_string_p); - const lit_utf8_size_t msg_size = ecma_string_get_size (msg_string_p); - const lit_utf8_size_t colon_size = lit_get_magic_string_size (LIT_MAGIC_STRING_COLON_CHAR); - const lit_utf8_size_t space_size = lit_get_magic_string_size (LIT_MAGIC_STRING_SPACE_CHAR); - const lit_utf8_size_t size = name_size + msg_size + colon_size + space_size; - - JMEM_DEFINE_LOCAL_ARRAY (ret_str_buffer, size, lit_utf8_byte_t); - lit_utf8_byte_t *ret_str_buffer_p = ret_str_buffer; - - lit_utf8_size_t bytes = ecma_string_copy_to_cesu8_buffer (name_string_p, ret_str_buffer_p, name_size); - JERRY_ASSERT (bytes == name_size); - ret_str_buffer_p = ret_str_buffer_p + bytes; - JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); - - ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_COLON_CHAR, - ret_str_buffer_p, - colon_size); - JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); - - ret_str_buffer_p = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_SPACE_CHAR, - ret_str_buffer_p, - space_size); - JERRY_ASSERT (ret_str_buffer_p <= ret_str_buffer + size); - - bytes = ecma_string_copy_to_cesu8_buffer (msg_string_p, ret_str_buffer_p, msg_size); - JERRY_ASSERT (bytes == msg_size); - ret_str_buffer_p = ret_str_buffer_p + bytes; - JERRY_ASSERT (ret_str_buffer_p == ret_str_buffer + size); - - ret_str_p = ecma_new_ecma_string_from_utf8 (ret_str_buffer, - size); - - JMEM_FINALIZE_LOCAL_ARRAY (ret_str_buffer); - } - - ret_value = ecma_make_string_value (ret_str_p); - } - - ecma_free_value (msg_to_str_completion); - - ECMA_FINALIZE (msg_get_ret_value); - } - - ecma_free_value (name_to_str_completion); - - ECMA_FINALIZE (name_get_ret_value); + return ECMA_VALUE_ERROR; } - return ret_value; + ecma_string_t *msg_string_p = ecma_builtin_error_prototype_object_to_string_helper (obj_p, + LIT_MAGIC_STRING_MESSAGE, + LIT_MAGIC_STRING__EMPTY); + + if (JERRY_UNLIKELY (msg_string_p == NULL)) + { + ecma_deref_ecma_string (name_string_p); + return ECMA_VALUE_ERROR; + } + + if (ecma_string_is_empty (name_string_p)) + { + return ecma_make_string_value (msg_string_p); + } + + if (ecma_string_is_empty (msg_string_p)) + { + return ecma_make_string_value (name_string_p); + } + + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (name_string_p); + + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *)": ", 2); + ecma_stringbuilder_append (&builder, msg_string_p); + + ecma_deref_ecma_string (name_string_p); + ecma_deref_ecma_string (msg_string_p); + + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_builtin_error_prototype_object_to_string */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-error.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-error.inc.h index 3fbddac2..e965de49 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-error.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-error.inc.h @@ -22,10 +22,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-evalerror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-evalerror.inc.h index c6d7626b..f2fd2682 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-evalerror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-evalerror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c index a821dcf2..1283b58a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c @@ -23,8 +23,10 @@ #include "ecma-helpers.h" #include "ecma-function-object.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" #include "jrt.h" +#include "ecma-builtin-function-prototype.h" #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -44,6 +46,9 @@ enum ECMA_FUNCTION_PROTOTYPE_CALL, ECMA_FUNCTION_PROTOTYPE_APPLY, ECMA_FUNCTION_PROTOTYPE_BIND, +#if ENABLED (JERRY_ES2015) + ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE, +#endif /* ENABLED (JERRY_ES2015) */ }; #define BUILTIN_INC_HEADER_NAME "ecma-builtin-function-prototype.inc.h" @@ -89,7 +94,7 @@ ecma_builtin_function_prototype_object_to_string (void) * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, /**< this argument object */ ecma_value_t arg1, /**< first argument */ ecma_value_t arg2) /**< second argument */ @@ -108,27 +113,15 @@ ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, /**< th ecma_object_t *obj_p = ecma_get_object_from_value (arg2); - /* 4. */ - ecma_value_t length_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH); - if (ECMA_IS_VALUE_ERROR (length_value)) + /* 4-5. */ + uint32_t length; + ecma_value_t len_value = ecma_op_object_get_length (obj_p, &length); + + if (ECMA_IS_VALUE_ERROR (len_value)) { - return length_value; + return len_value; } - ecma_number_t length_number; - ecma_value_t get_result = ecma_get_number (length_value, &length_number); - - ecma_free_value (length_value); - - if (ECMA_IS_VALUE_ERROR (get_result)) - { - return get_result; - } - JERRY_ASSERT (ecma_is_value_empty (get_result)); - - /* 5. */ - const uint32_t length = ecma_number_to_uint32 (length_number); - if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT) { return ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply().")); @@ -142,9 +135,7 @@ ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, /**< th /* 7. */ for (index = 0; index < length; index++) { - ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t get_value = ecma_op_object_get (obj_p, curr_idx_str_p); - ecma_deref_ecma_string (curr_idx_str_p); + ecma_value_t get_value = ecma_op_object_get_by_uint32_index (obj_p, index); if (ECMA_IS_VALUE_ERROR (get_value)) { @@ -218,49 +209,83 @@ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /** ecma_length_t arguments_number) /**< number of arguments */ { /* 4. 11. 18. */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *prototype_obj_p; + +#if !ENABLED (JERRY_ES2015) + prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); +#else /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (this_arg_obj_p)) + { + ecma_value_t proto = ecma_proxy_object_get_prototype_of (this_arg_obj_p); + + if (ECMA_IS_VALUE_ERROR (proto)) + { + return proto; + } + prototype_obj_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (this_arg_obj_p); + if (proto_cp != JMEM_CP_NULL) + { + prototype_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (prototype_obj_p); + } + else + { + prototype_obj_p = NULL; + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +#endif /* !ENABLED (JERRY_ES2015) */ ecma_object_t *function_p; - ecma_extended_object_t *ext_function_p; + ecma_bound_function_t *bound_func_p; if (arguments_number == 0 || (arguments_number == 1 && !ecma_is_value_integer_number (arguments_list_p[0]))) { function_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_extended_object_t), + sizeof (ecma_bound_function_t), ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 8. */ - ext_function_p = (ecma_extended_object_t *) function_p; - ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, - this_arg_obj_p); + bound_func_p = (ecma_bound_function_t *) function_p; + ECMA_SET_NON_NULL_POINTER_TAG (bound_func_p->header.u.bound_function.target_function, + this_arg_obj_p, + 0); - ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; + bound_func_p->header.u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; if (arguments_number != 0) { - ext_function_p->u.bound_function.args_len_or_this = ecma_copy_value_if_not_object (arguments_list_p[0]); + bound_func_p->header.u.bound_function.args_len_or_this = ecma_copy_value_if_not_object (arguments_list_p[0]); } } else { JERRY_ASSERT (arguments_number > 0); - size_t obj_size = sizeof (ecma_extended_object_t) + (arguments_number * sizeof (ecma_value_t)); + size_t obj_size = sizeof (ecma_bound_function_t) + (arguments_number * sizeof (ecma_value_t)); function_p = ecma_create_object (prototype_obj_p, obj_size, ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 8. */ - ext_function_p = (ecma_extended_object_t *) function_p; - ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, - this_arg_obj_p); + bound_func_p = (ecma_bound_function_t *) function_p; + ECMA_SET_NON_NULL_POINTER_TAG (bound_func_p->header.u.bound_function.target_function, + this_arg_obj_p, + 0); /* NOTE: This solution provides temporary false data about the object's size but prevents GC from freeing it until it's not fully initialized. */ - ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); + bound_func_p->header.u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED; + ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1); for (ecma_length_t i = 0; i < arguments_number; i++) { @@ -268,8 +293,9 @@ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /** } ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) arguments_number); - ext_function_p->u.bound_function.args_len_or_this = args_len_or_this; + bound_func_p->header.u.bound_function.args_len_or_this = args_len_or_this; } + #if defined(JERRY_FUNCTION_NAME) && !defined(__APPLE__) ecma_object_type_t obj_type = ecma_get_object_type(this_arg_obj_p); if (obj_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION || obj_type == ECMA_OBJECT_TYPE_FUNCTION) { @@ -285,6 +311,48 @@ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /** } #endif +#if ENABLED (JERRY_ES2015) + ecma_integer_value_t len = 0; + ecma_string_t *len_string = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (this_arg_obj_p, + len_string, + &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + ecma_value_t len_value = ecma_op_object_get (this_arg_obj_p, + len_string); + + if (ECMA_IS_VALUE_ERROR (len_value)) + { + return len_value; + } + + if (ecma_is_value_number (len_value)) + { + ecma_number_t len_num; + ecma_op_to_integer (len_value, &len_num); + len = (ecma_integer_value_t) len_num; + } + } + + bound_func_p->target_length = len; + + if (prototype_obj_p != NULL) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * @@ -339,6 +407,13 @@ ecma_builtin_function_prototype_dispatch_routine (uint16_t builtin_routine_id, / { if (!ecma_op_is_callable (this_arg)) { +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (builtin_routine_id == ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE)) + { + return ECMA_VALUE_FALSE; + } +#endif /* ENABLED (JERRY_ES2015) */ + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function.")); } @@ -364,6 +439,12 @@ ecma_builtin_function_prototype_dispatch_routine (uint16_t builtin_routine_id, / { return ecma_builtin_function_prototype_object_bind (func_obj_p, arguments_list_p, arguments_number); } +#if ENABLED (JERRY_ES2015) + case ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE: + { + return ecma_op_object_has_instance (func_obj_p, arguments_list_p[0]); + } +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_UNREACHABLE (); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.h b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.h new file mode 100644 index 00000000..97ba3137 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.h @@ -0,0 +1,23 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_BUILTIN_FUNCTION_PROTOTYPE_H +#define ECMA_BUILTIN_FUNCTION_PROTOTYPE_H + +ecma_value_t ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, + ecma_value_t arg1, + ecma_value_t arg2); + +#endif /* !ECMA_BUILTIN_FUNCTION_PROTOTYPE_H */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.inc.h index 945a14fc..94f0e870 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.inc.h @@ -30,10 +30,9 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, /* Number properties: * (property name, object pointer getter) */ -/* ECMA-262 v5, 15.3.4 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 0, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -42,4 +41,20 @@ ROUTINE (LIT_MAGIC_STRING_APPLY, ECMA_FUNCTION_PROTOTYPE_APPLY, 2, 2) ROUTINE (LIT_MAGIC_STRING_CALL, ECMA_FUNCTION_PROTOTYPE_CALL, NON_FIXED, 1) ROUTINE (LIT_MAGIC_STRING_BIND, ECMA_FUNCTION_PROTOTYPE_BIND, NON_FIXED, 1) +#if ENABLED (JERRY_ES2015) +/** + * ECMA-262 v6.0 19.2.3.6 @@hasInstance + * the property attributes are: { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }. + */ +ROUTINE_WITH_FLAGS (LIT_GLOBAL_SYMBOL_HAS_INSTANCE, ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE, 1, 1, 0 /* flags */) +ACCESSOR_BUILTIN_FUNCTION (LIT_MAGIC_STRING_ARGUMENTS, + ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, + ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +ACCESSOR_BUILTIN_FUNCTION (LIT_MAGIC_STRING_CALLER, + ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, + ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +#endif /* ENABLED (JERRY_ES2015) */ + #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c index 1553aa65..e9499168 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c @@ -59,60 +59,6 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**< return ecma_builtin_function_dispatch_construct (arguments_list_p, arguments_list_len); } /* ecma_builtin_function_dispatch_call */ -/** - * Helper method to count and convert the arguments for the Function constructor call. - * - * Performs the operation described in ECMA 262 v5.1 15.3.2.1 steps 5.a-d - * - * - * @return ecma value - concatenated arguments as a string. - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_function_helper_get_function_arguments (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ -{ - JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - - if (arguments_list_len <= 1) - { - return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - } - - ecma_value_t final_str = ecma_op_to_string (arguments_list_p[0]); - - if (arguments_list_len == 2 || ECMA_IS_VALUE_ERROR (final_str)) - { - return final_str; - } - - for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++) - { - ecma_value_t new_str = ecma_op_to_string (arguments_list_p[idx]); - - if (ECMA_IS_VALUE_ERROR (new_str)) - { - ecma_free_value (final_str); - - /* Return with the error. */ - final_str = new_str; - break; - } - - ecma_string_t *final_str_p = ecma_get_string_from_value (final_str); - final_str_p = ecma_append_magic_string_to_string (final_str_p, - LIT_MAGIC_STRING_COMMA_CHAR); - - ecma_string_t *new_str_p = ecma_get_string_from_value (new_str); - final_str_p = ecma_concat_ecma_strings (final_str_p, new_str_p); - ecma_deref_ecma_string (new_str_p); - - final_str = ecma_make_string_value (final_str_p); - } - - return final_str; -} /* ecma_builtin_function_helper_get_function_arguments */ - /** * Handle calling [[Construct]] of built-in Function object * @@ -125,71 +71,7 @@ ecma_value_t ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { - JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - - ecma_value_t arguments_value = ecma_builtin_function_helper_get_function_arguments (arguments_list_p, - arguments_list_len); - - if (ECMA_IS_VALUE_ERROR (arguments_value)) - { - return arguments_value; - } - - ecma_value_t function_body_value; - - if (arguments_list_len > 0) - { - function_body_value = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]); - - if (ECMA_IS_VALUE_ERROR (function_body_value)) - { - ecma_free_value (arguments_value); - return function_body_value; - } - } - else - { - /* Very unlikely code path, not optimized. */ - function_body_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - } - - ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value); - ecma_string_t *function_body_str_p = ecma_get_string_from_value (function_body_value); - - ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); - ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); - -#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) - JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); -#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - - ecma_compiled_code_t *bytecode_data_p = NULL; - - ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, - arguments_buffer_size, - function_body_buffer_p, - function_body_buffer_size, - ECMA_PARSE_NO_OPTS, - &bytecode_data_p); - - if (!ECMA_IS_VALUE_ERROR (ret_value)) - { - JERRY_ASSERT (ecma_is_value_true (ret_value)); - - ecma_object_t *func_obj_p = ecma_op_create_function_object (ecma_get_global_environment (), - bytecode_data_p); - - ecma_bytecode_deref (bytecode_data_p); - ret_value = ecma_make_object_value (func_obj_p); - } - - ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size); - ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size); - - ecma_deref_ecma_string (arguments_str_p); - ecma_deref_ecma_string (function_body_str_p); - - return ret_value; + return ecma_op_create_dynamic_function (arguments_list_p, arguments_list_len, ECMA_PARSE_NO_OPTS); } /* ecma_builtin_function_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-function.inc.h index c6a4a7bd..ede26615 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.inc.h @@ -30,9 +30,8 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* Number properties: * (property name, object pointer getter) */ -/* ECMA-262 v5, 15.3.3.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c new file mode 100644 index 00000000..258ce9b8 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c @@ -0,0 +1,72 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-globals.h" + +#if ENABLED (JERRY_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" +#include "ecma-function-object.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator-function.inc.h" +#define BUILTIN_UNDERSCORED_ID generator_function +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup generator ECMA GeneratorFunction object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in GeneratorFunction object + * + * @return constructed generator function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_generator_function_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_op_create_dynamic_function (arguments_list_p, arguments_list_len, ECMA_PARSE_GENERATOR_FUNCTION); +} /* ecma_builtin_generator_function_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in GeneratorFunction object + * +* @return constructed generator function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_generator_function_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_generator_function_dispatch_call (arguments_list_p, arguments_list_len); +} /* ecma_builtin_generator_function_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h new file mode 100644 index 00000000..d4e8c4bc --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h @@ -0,0 +1,41 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * %GeneratorFunction% built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 25.2.2 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.2.2.1 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.2.2.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_GENERATOR, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c new file mode 100644 index 00000000..a09deba3 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c @@ -0,0 +1,250 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-iterator-object.h" +#include "jcontext.h" +#include "opcodes.h" +#include "vm-defines.h" + +#if ENABLED (JERRY_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID generator_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup generator ECMA Generator.prototype object built-in + * @{ + */ + +/** + * Byte code sequence which returns from the generator. + */ +static const uint8_t ecma_builtin_generator_prototype_return[2] = +{ + CBC_EXT_OPCODE, CBC_EXT_RETURN +}; + +/** + * Byte code sequence which throws an exception. + */ +static const uint8_t ecma_builtin_generator_prototype_throw[1] = +{ + CBC_THROW +}; + +/** + * Helper function for next / return / throw + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this argument */ + ecma_value_t arg, /**< argument */ + ecma_iterator_command_type_t resume_mode) /**< resume mode */ +{ + vm_executable_object_t *executable_object_p = NULL; + + if (ecma_is_value_object (this_arg)) + { + ecma_object_t *object_p = ecma_get_object_from_value (this_arg); + + if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS) + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_GENERATOR_UL) + { + executable_object_p = (vm_executable_object_t *) ext_object_p; + } + } + } + + if (executable_object_p == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a generator object.")); + } + + if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Generator is currently under execution.")); + } + + if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED) + { + return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); + } + + arg = ecma_copy_value (arg); + + while (true) + { + if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD) + { + ecma_value_t iterator = executable_object_p->extended_object.u.class_prop.u.value; + + bool done = false; + ecma_value_t result = ecma_op_iterator_do (resume_mode, iterator, arg, &done); + ecma_free_value (arg); + + if (ECMA_IS_VALUE_ERROR (result)) + { + arg = result; + } + else if (done) + { + arg = ecma_op_iterator_value (result); + ecma_free_value (result); + if (resume_mode == ECMA_ITERATOR_THROW) + { + /* This part is changed in the newest ECMAScript standard. + * It was ECMA_ITERATOR_RETURN in ES2015, but I think it was a typo. */ + resume_mode = ECMA_ITERATOR_NEXT; + } + } + else + { + return result; + } + + executable_object_p->extended_object.u.class_prop.extra_info &= (uint16_t) ~ECMA_GENERATOR_ITERATE_AND_YIELD; + + if (ECMA_IS_VALUE_ERROR (arg)) + { + arg = jcontext_take_exception (); + resume_mode = ECMA_ITERATOR_THROW; + } + } + + if (resume_mode == ECMA_ITERATOR_RETURN) + { + executable_object_p->frame_ctx.byte_code_p = ecma_builtin_generator_prototype_return; + } + else if (resume_mode == ECMA_ITERATOR_THROW) + { + executable_object_p->frame_ctx.byte_code_p = ecma_builtin_generator_prototype_throw; + } + + ecma_value_t value = opfunc_resume_executable_object (executable_object_p, arg); + + if (ECMA_IS_VALUE_ERROR (value)) + { + return value; + } + + bool done = (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED); + + if (!done) + { + const uint8_t *byte_code_p = executable_object_p->frame_ctx.byte_code_p; + + JERRY_ASSERT (byte_code_p[-2] == CBC_EXT_OPCODE + && (byte_code_p[-1] == CBC_EXT_YIELD || byte_code_p[-1] == CBC_EXT_YIELD_ITERATOR)); + + if (byte_code_p[-1] == CBC_EXT_YIELD_ITERATOR) + { + ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_EMPTY); + ecma_free_value (value); + + if (ECMA_IS_VALUE_ERROR (iterator)) + { + resume_mode = ECMA_ITERATOR_THROW; + arg = jcontext_take_exception (); + continue; + } + + ecma_deref_object (ecma_get_object_from_value (iterator)); + executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_GENERATOR_ITERATE_AND_YIELD; + executable_object_p->extended_object.u.class_prop.u.value = iterator; + arg = ECMA_VALUE_UNDEFINED; + continue; + } + } + + ecma_value_t result = ecma_create_iter_result_object (value, ecma_make_boolean_value (done)); + ecma_fast_free_value (value); + return result; + } +} /* ecma_builtin_generator_prototype_object_do */ + +/** + * The Generator.prototype object's 'next' routine + * + * See also: + * ECMA-262 v6, 25.3.1.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_generator_prototype_object_next (ecma_value_t this_arg, /**< this argument */ + ecma_value_t next_arg) /**< next argument */ +{ + return ecma_builtin_generator_prototype_object_do (this_arg, next_arg, ECMA_ITERATOR_NEXT); +} /* ecma_builtin_generator_prototype_object_next */ + +/** + * The Generator.prototype object's 'return' routine + * + * See also: + * ECMA-262 v6, 25.3.1.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_generator_prototype_object_return (ecma_value_t this_arg, /**< this argument */ + ecma_value_t return_arg) /**< return argument */ +{ + return ecma_builtin_generator_prototype_object_do (this_arg, return_arg, ECMA_ITERATOR_RETURN); +} /* ecma_builtin_generator_prototype_object_return */ + +/** + * The Generator.prototype object's 'throw' routine + * + * See also: + * ECMA-262 v6, 25.3.1.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_generator_prototype_object_throw (ecma_value_t this_arg, /**< this argument */ + ecma_value_t throw_arg) /**< throw argument */ +{ + return ecma_builtin_generator_prototype_object_do (this_arg, throw_arg, ECMA_ITERATOR_THROW); +} /* ecma_builtin_generator_prototype_object_throw */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h new file mode 100644 index 00000000..e21878fe --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h @@ -0,0 +1,45 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Generator.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 25.3.1.5 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_GENERATOR_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.2.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_GENERATOR, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_NEXT, ecma_builtin_generator_prototype_object_next, 1, 1) +ROUTINE (LIT_MAGIC_STRING_RETURN, ecma_builtin_generator_prototype_object_return, 1, 1) +ROUTINE (LIT_MAGIC_STRING_THROW, ecma_builtin_generator_prototype_object_throw, 1, 1) + +#endif /* ENABLED (JERRY_ES2015) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.c new file mode 100644 index 00000000..663659b2 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.c @@ -0,0 +1,43 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-globals.h" + +#if ENABLED (JERRY_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator.inc.h" +#define BUILTIN_UNDERSCORED_ID generator +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup generator ECMA Generator object built-in + * @{ + */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h new file mode 100644 index 00000000..8d38bc0c --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h @@ -0,0 +1,41 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * %Generator% built-in description (GeneratorFunction.prototype) + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 25.3.2.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_GENERATOR_FUNCTION, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.3.2.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.3.2.3.3 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +#endif /* ENABLED (JERRY_ES2015) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c index 0b8ef283..76f5de37 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c @@ -100,386 +100,17 @@ ecma_builtin_global_object_eval (ecma_value_t x) /**< routine's first argument * parse_opts |= ECMA_PARSE_STRICT_MODE; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) if (vm_is_direct_eval_form_call ()) { - parse_opts |= ECMA_GET_SUPER_EVAL_PARSER_OPTS (); + parse_opts |= ECMA_GET_LOCAL_PARSE_OPTS (); } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ /* steps 2 to 8 */ return ecma_op_eval (ecma_get_string_from_value (x), parse_opts); } /* ecma_builtin_global_object_eval */ -/** - * The Global object's 'parseInt' routine - * - * See also: - * ECMA-262 v5, 15.1.2.2 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_global_object_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first argument's - * string buffer */ - lit_utf8_size_t string_buff_size, /**< routine's first argument's - * string buffer's size */ - ecma_value_t radix) /**< routine's second argument */ -{ - if (string_buff_size <= 0) - { - return ecma_make_nan_value (); - } - - const lit_utf8_byte_t *string_curr_p = string_buff; - - /* 2. Remove leading whitespace. */ - ecma_string_trim_helper (&string_curr_p, &string_buff_size); - - const lit_utf8_byte_t *string_end_p = string_curr_p + string_buff_size; - const lit_utf8_byte_t *start_p = string_curr_p; - const lit_utf8_byte_t *end_p = string_end_p; - - if (string_curr_p >= string_end_p) - { - return ecma_make_nan_value (); - } - - /* 3. */ - int sign = 1; - - /* 4. */ - ecma_char_t current = lit_utf8_read_next (&string_curr_p); - if (current == LIT_CHAR_MINUS) - { - sign = -1; - } - - /* 5. */ - if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) - { - start_p = string_curr_p; - if (string_curr_p < string_end_p) - { - current = lit_utf8_read_next (&string_curr_p); - } - } - - /* 6. */ - ecma_number_t radix_num; - radix = ecma_get_number (radix, &radix_num); - - if (!ecma_is_value_empty (radix)) - { - return radix; - } - - int32_t rad = ecma_number_to_int32 (radix_num); - - /* 7.*/ - bool strip_prefix = true; - - /* 8. */ - if (rad != 0) - { - /* 8.a */ - if (rad < 2 || rad > 36) - { - return ecma_make_nan_value (); - } - /* 8.b */ - else if (rad != 16) - { - strip_prefix = false; - } - } - /* 9. */ - else - { - rad = 10; - } - - /* 10. */ - if (strip_prefix - && ((end_p - start_p) >= 2) - && (current == LIT_CHAR_0)) - { - ecma_char_t next = *string_curr_p; - if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X) - { - /* Skip the 'x' or 'X' characters. */ - start_p = ++string_curr_p; - rad = 16; - } - } - - /* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */ - string_curr_p = start_p; - while (string_curr_p < string_end_p) - { - ecma_char_t current_char = *string_curr_p++; - int32_t current_number; - - if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) - { - current_number = current_char - LIT_CHAR_LOWERCASE_A + 10; - } - else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) - { - current_number = current_char - LIT_CHAR_UPPERCASE_A + 10; - } - else if (lit_char_is_decimal_digit (current_char)) - { - current_number = current_char - LIT_CHAR_0; - } - else - { - /* Not a valid number char, set value to radix so it fails to pass as a valid character. */ - current_number = rad; - } - - if (!(current_number < rad)) - { - end_p = --string_curr_p; - break; - } - } - - /* 12. */ - if (end_p == start_p) - { - return ecma_make_nan_value (); - } - - ecma_number_t value = ECMA_NUMBER_ZERO; - ecma_number_t multiplier = 1.0f; - - /* 13. and 14. */ - string_curr_p = end_p; - - while (string_curr_p > start_p) - { - ecma_char_t current_char = *(--string_curr_p); - ecma_number_t current_number = ECMA_NUMBER_MINUS_ONE; - - if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) - { - current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10; - } - else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) - { - current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10; - } - else - { - JERRY_ASSERT (lit_char_is_decimal_digit (current_char)); - current_number = (ecma_number_t) current_char - LIT_CHAR_0; - } - - value += current_number * multiplier; - multiplier *= (ecma_number_t) rad; - } - - /* 15. */ - if (sign < 0) - { - value *= (ecma_number_t) sign; - } - - return ecma_make_number_value (value); -} /* ecma_builtin_global_object_parse_int */ - -/** - * The Global object's 'parseFloat' routine - * - * See also: - * ECMA-262 v5, 15.1.2.3 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_global_object_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's first argument's - * string buffer */ - lit_utf8_size_t string_buff_size) /**< routine's first argument's - * string buffer's size */ -{ - if (string_buff_size <= 0) - { - return ecma_make_nan_value (); - } - - const lit_utf8_byte_t *str_curr_p = string_buff; - - /* 2. Remove leading whitespace. */ - ecma_string_trim_helper (&str_curr_p, &string_buff_size); - - const lit_utf8_byte_t *str_end_p = str_curr_p + string_buff_size; - const lit_utf8_byte_t *start_p = str_curr_p; - const lit_utf8_byte_t *end_p = str_end_p; - - bool sign = false; - ecma_char_t current; - - if (str_curr_p < str_end_p) - { - /* Check if sign is present. */ - current = *str_curr_p; - if (current == LIT_CHAR_MINUS) - { - sign = true; - } - - if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) - { - /* Set starting position to be after the sign character. */ - start_p = ++str_curr_p; - } - } - - const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL); - lit_utf8_byte_t *infinity_str_curr_p = (lit_utf8_byte_t *) infinity_str_p; - lit_utf8_byte_t *infinity_str_end_p = infinity_str_curr_p + sizeof (*infinity_str_p); - - /* Check if string is equal to "Infinity". */ - while (str_curr_p < str_end_p - && *str_curr_p++ == *infinity_str_curr_p++) - { - if (infinity_str_curr_p == infinity_str_end_p) - { - /* String matched Infinity. */ - return ecma_make_number_value (ecma_number_make_infinity (sign)); - } - } - - /* Reset to starting position. */ - str_curr_p = start_p; - - /* String ended after sign character, or was empty after removing leading whitespace. */ - if (str_curr_p >= str_end_p) - { - return ecma_make_nan_value (); - } - - /* Reset to starting position. */ - str_curr_p = start_p; - - current = *str_curr_p; - - bool has_whole_part = false; - bool has_fraction_part = false; - - /* Check digits of whole part. */ - if (lit_char_is_decimal_digit (current)) - { - has_whole_part = true; - str_curr_p++; - - while (str_curr_p < str_end_p) - { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } - } - } - - - /* Set end position to the end of whole part. */ - end_p = str_curr_p; - if (str_curr_p < str_end_p) - { - current = *str_curr_p; - - /* Check decimal point. */ - if (current == LIT_CHAR_DOT) - { - str_curr_p++; - - if (str_curr_p < str_end_p) - { - current = *str_curr_p; - - if (lit_char_is_decimal_digit (current)) - { - has_fraction_part = true; - - /* Check digits of fractional part. */ - while (str_curr_p < str_end_p) - { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } - } - - /* Set end position to end of fraction part. */ - end_p = str_curr_p; - } - } - } - } - - - if (str_curr_p < str_end_p) - { - current = *str_curr_p++; - } - - /* Check exponent. */ - if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E) - && (has_whole_part || has_fraction_part) - && str_curr_p < str_end_p) - { - current = *str_curr_p++; - - /* Check sign of exponent. */ - if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS) - && str_curr_p < str_end_p) - { - current = *str_curr_p++; - } - - if (lit_char_is_decimal_digit (current)) - { - /* Check digits of exponent part. */ - while (str_curr_p < str_end_p) - { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } - } - - /* Set end position to end of exponent part. */ - end_p = str_curr_p; - } - } - - /* String did not contain a valid number. */ - if (start_p == end_p) - { - return ecma_make_nan_value (); - } - - /* 5. */ - ecma_number_t ret_num = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (end_p - start_p)); - - if (sign) - { - ret_num *= ECMA_NUMBER_MINUS_ONE; - } - - return ecma_make_number_value (ret_num); -} /* ecma_builtin_global_object_parse_float */ - /** * The Global object's 'isNaN' routine * @@ -592,13 +223,13 @@ ecma_builtin_global_object_decode_uri_helper (lit_utf8_byte_t *input_start_p, /* continue; } - ecma_char_t decoded_byte; - - if (!lit_read_code_unit_from_hex (input_char_p + 1, 2, &decoded_byte)) + uint32_t hex_value = lit_char_hex_lookup (input_char_p + 1, input_end_p, 2); + if (hex_value == UINT32_MAX) { return ecma_raise_uri_error (ECMA_ERR_MSG ("Invalid hexadecimal value.")); } + ecma_char_t decoded_byte = (ecma_char_t) hex_value; input_char_p += URI_ENCODED_BYTE_SIZE; if (decoded_byte <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) @@ -641,20 +272,18 @@ ecma_builtin_global_object_decode_uri_helper (lit_utf8_byte_t *input_start_p, /* /* Input decode. */ if (*input_char_p != '%') { - *output_char_p = *input_char_p; - output_char_p++; - input_char_p++; + *output_char_p++ = *input_char_p++; continue; } - ecma_char_t decoded_byte; - - if (!lit_read_code_unit_from_hex (input_char_p + 1, 2, &decoded_byte)) + uint32_t hex_value = lit_char_hex_lookup (input_char_p + 1, input_end_p, 2); + if (hex_value == UINT32_MAX) { ret_value = ecma_raise_uri_error (ECMA_ERR_MSG ("Invalid hexadecimal value.")); break; } + ecma_char_t decoded_byte = (ecma_char_t) hex_value; input_char_p += URI_ENCODED_BYTE_SIZE; if (decoded_byte <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) @@ -706,17 +335,16 @@ ecma_builtin_global_object_decode_uri_helper (lit_utf8_byte_t *input_start_p, /* } else { - ecma_char_t chr; + hex_value = lit_char_hex_lookup (input_char_p + 1, input_end_p, 2); - if (!lit_read_code_unit_from_hex (input_char_p + 1, 2, &chr) - || ((chr & LIT_UTF8_EXTRA_BYTE_MASK) != LIT_UTF8_EXTRA_BYTE_MARKER)) + if (hex_value == UINT32_MAX || (hex_value & LIT_UTF8_EXTRA_BYTE_MASK) != LIT_UTF8_EXTRA_BYTE_MARKER) { is_valid = false; break; } - octets[i] = (lit_utf8_byte_t) chr; input_char_p += URI_ENCODED_BYTE_SIZE; + octets[i] = (lit_utf8_byte_t) hex_value; } } @@ -970,7 +598,7 @@ ecma_builtin_global_object_escape (lit_utf8_byte_t *input_start_p, /**< routine' while (input_curr_p < input_end_p) { - ecma_char_t chr = lit_utf8_read_next (&input_curr_p); + ecma_char_t chr = lit_cesu8_read_next (&input_curr_p); if (chr <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) { @@ -1005,7 +633,7 @@ ecma_builtin_global_object_escape (lit_utf8_byte_t *input_start_p, /**< routine' while (input_curr_p < input_end_p) { - ecma_char_t chr = lit_utf8_read_next (&input_curr_p); + ecma_char_t chr = lit_cesu8_read_next (&input_curr_p); if (chr <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) { @@ -1091,7 +719,7 @@ ecma_builtin_global_object_unescape (lit_utf8_byte_t *input_start_p, /**< routin while (input_curr_p < input_end_p) { /* 6. */ - ecma_char_t chr = lit_utf8_read_next (&input_curr_p); + ecma_char_t chr = lit_cesu8_read_next (&input_curr_p); /* 7-8. */ if (status == 0 && chr == LIT_CHAR_PERCENT) @@ -1185,15 +813,13 @@ ecma_builtin_global_dispatch_routine (uint16_t builtin_routine_id, /**< built-in return ecma_builtin_global_object_is_finite (arg_num); } - ecma_value_t string_value = ecma_op_to_string (routine_arg_1); + ecma_string_t *str_p = ecma_op_to_string (routine_arg_1); - if (ECMA_IS_VALUE_ERROR (string_value)) + if (JERRY_UNLIKELY (str_p == NULL)) { - return string_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *str_p = ecma_get_string_from_value (string_value); - ecma_value_t ret_value; if (builtin_routine_id <= ECMA_GLOBAL_PARSE_FLOAT) @@ -1202,15 +828,15 @@ ecma_builtin_global_dispatch_routine (uint16_t builtin_routine_id, /**< built-in if (builtin_routine_id == ECMA_GLOBAL_PARSE_INT) { - ret_value = ecma_builtin_global_object_parse_int (string_buff, - string_buff_size, - arguments_list_p[1]); + ret_value = ecma_number_parse_int (string_buff, + string_buff_size, + arguments_list_p[1]); } else { JERRY_ASSERT (builtin_routine_id == ECMA_GLOBAL_PARSE_FLOAT); - ret_value = ecma_builtin_global_object_parse_float (string_buff, - string_buff_size); + ret_value = ecma_number_parse_float (string_buff, + string_buff_size); } ECMA_FINALIZE_UTF8_STRING (string_buff, string_buff_size); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h index 4964887f..2d58eb1e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -139,6 +139,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_MATH_UL, ECMA_BUILTIN_ID_MATH, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_BUILTIN_MATH) */ +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +/* ECMA-262 v6, 26.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_REFLECT_UL, + ECMA_BUILTIN_ID_REFLECT, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ #if ENABLED (JERRY_BUILTIN_JSON) /* ECMA-262 v5, 15.1.5.2 */ @@ -212,12 +218,26 @@ OBJECT_VALUE (LIT_MAGIC_STRING_SET_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_BUILTIN_ID_WEAKMAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_BUILTIN_ID_WEAKSET, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 19.4.1.1 */ OBJECT_VALUE (LIT_MAGIC_STRING_SYMBOL_UL, ECMA_BUILTIN_ID_SYMBOL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) /* ECMA-262 v6, 23.1.1.1 */ @@ -226,19 +246,31 @@ OBJECT_VALUE (LIT_MAGIC_STRING_DATAVIEW_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/* ECMA-262 v6, 26.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROXY_UL, + ECMA_BUILTIN_ID_PROXY, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_EVAL, ECMA_GLOBAL_EVAL, 1, 1) -ROUTINE (LIT_MAGIC_STRING_PARSE_FLOAT, ECMA_GLOBAL_PARSE_FLOAT, 1, 1) ROUTINE (LIT_MAGIC_STRING_IS_NAN, ECMA_GLOBAL_IS_NAN, 1, 1) ROUTINE (LIT_MAGIC_STRING_IS_FINITE, ECMA_GLOBAL_IS_FINITE, 1, 1) ROUTINE (LIT_MAGIC_STRING_DECODE_URI, ECMA_GLOBAL_DECODE_URI, 1, 1) ROUTINE (LIT_MAGIC_STRING_DECODE_URI_COMPONENT, ECMA_GLOBAL_DECODE_URI_COMPONENT, 1, 1) ROUTINE (LIT_MAGIC_STRING_ENCODE_URI, ECMA_GLOBAL_ENCODE_URI, 1, 1) ROUTINE (LIT_MAGIC_STRING_ENCODE_URI_COMPONENT, ECMA_GLOBAL_ENCODE_URI_COMPONENT, 1, 1) -ROUTINE (LIT_MAGIC_STRING_PARSE_INT, ECMA_GLOBAL_PARSE_INT, 2, 2) +#if ENABLED (JERRY_ES2015) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_PARSE_FLOAT, LIT_MAGIC_STRING_PARSE_FLOAT, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_PARSE_INT, LIT_MAGIC_STRING_PARSE_INT, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#else /* !ENABLED (JERRY_ES2015) */ +ROUTINE (LIT_MAGIC_STRING_PARSE_FLOAT, ECMA_GLOBAL_PARSE_FLOAT, 1, 1) +ROUTINE (LIT_MAGIC_STRING_PARSE_INT, ECMA_GLOBAL_PARSE_INT, 2, 2) +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) ROUTINE (LIT_MAGIC_STRING_ESCAPE, ECMA_GLOBAL_ESCAPE, 1, 1) ROUTINE (LIT_MAGIC_STRING_UNESCAPE, ECMA_GLOBAL_UNESCAPE, 1, 1) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c index 8e48f5aa..467df302 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c @@ -33,6 +33,16 @@ * @{ */ +const char day_names_p[7][3] = +{ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +const char month_names_p[12][3] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + /** * Helper function to get day number from time value. * @@ -583,16 +593,6 @@ static ecma_value_t ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ const char *format_p) /**< format buffer */ { - static const char * const day_names_p[8] = - { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - - static const char * const month_names_p[13] = - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - const uint32_t date_buffer_length = 37; JERRY_VLA (lit_utf8_byte_t, date_buffer, date_buffer_length); @@ -702,7 +702,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ number_length = 3; break; } - case LIT_CHAR_LOWERCASE_Z: /* Time zone minutes part. */ + case LIT_CHAR_LOWERCASE_Z: /* Time zone hours part. */ { int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number); @@ -722,7 +722,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ } default: { - JERRY_ASSERT (*format_p == LIT_CHAR_UPPERCASE_Z); /* Time zone seconds part. */ + JERRY_ASSERT (*format_p == LIT_CHAR_UPPERCASE_Z); /* Time zone minutes part. */ int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number); @@ -731,7 +731,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ time_zone = -time_zone; } - number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR; + number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR / (int32_t) ECMA_DATE_MS_PER_MINUTE; number_length = 2; break; } @@ -741,13 +741,9 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ if (str_p != NULL) { - /* Print string values. */ - do - { - *dest_p++ = (lit_utf8_byte_t) *str_p++; - } - while (*str_p != LIT_CHAR_NULL); - + /* Print string values: month or day name which is always 3 characters */ + memcpy (dest_p, str_p, 3); + dest_p += 3; continue; } @@ -797,7 +793,7 @@ ecma_value_t ecma_date_value_to_string (ecma_number_t datetime_number) /**< datetime */ { datetime_number += ecma_date_local_time_zone_adjustment (datetime_number); - return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z:$Z"); + return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z$Z"); } /* ecma_date_value_to_string */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c index c97af8c3..52e87910 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c @@ -47,31 +47,26 @@ ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, /**< if (arguments_list_len != 0 && !ecma_is_value_undefined (arguments_list_p[0])) { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_string_t *message_string_p = ecma_op_to_string (arguments_list_p[0]); - ECMA_TRY_CATCH (msg_str_value, - ecma_op_to_string (arguments_list_p[0]), - ret_value); + if (JERRY_UNLIKELY (message_string_p == NULL)) + { + return ECMA_VALUE_ERROR; + } - ecma_string_t *message_string_p = ecma_get_string_from_value (msg_str_value); ecma_object_t *new_error_object_p = ecma_new_standard_error_with_message (error_type, message_string_p); - ret_value = ecma_make_object_value (new_error_object_p); - - ECMA_FINALIZE (msg_str_value); - - return ret_value; - } - else - { - ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type); + ecma_deref_ecma_string (message_string_p); return ecma_make_object_value (new_error_object_p); } + + ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type); + + return ecma_make_object_value (new_error_object_p); } /* ecma_builtin_helper_error_dispatch_call */ /** * @} * @} */ - diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-defines.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-defines.inc.h index 53ecd64e..40afcf95 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-defines.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-defines.inc.h @@ -25,11 +25,19 @@ #define STRING_VALUE(name, magic_string_id, prop_attributes) #endif /* !STRING_VALUE */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #ifndef SYMBOL_VALUE -#define SYMBOL_VALUE(name, desc_string_id) +#define SYMBOL_VALUE(symbol, desc_magic_string_id) #endif /* !SYMBOL_VALUE */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + +#ifndef INTRINSIC_PROPERTY +#define INTRINSIC_PROPERTY(name, magic_string_id, prop_attributes) +#endif /* !INTRINSIC_PROPERTY */ + +#ifndef ACCESSOR_BUILTIN_FUNCTION_OBJECT +#define ACCESSOR_BUILTIN_FUNCTION_OBJECT(name, getter_builtin_id, setter_builtin_id, prop_attributes) +#endif /* !ACCESSOR_BUILTIN_FUNCTION_OBJECT */ +#endif /* ENABLED (JERRY_ES2015) */ #ifndef OBJECT_VALUE #define OBJECT_VALUE(name, obj_builtin_id, prop_attributes) @@ -43,6 +51,10 @@ #define ROUTINE_CONFIGURABLE_ONLY(name, c_function_name, args_number, length_prop_value) #endif /* !ROUTINE_CONFIGURABLE_ONLY */ +#ifndef ROUTINE_WITH_FLAGS +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) +#endif /* !ROUTINE_WITH_FLAGS */ + #ifndef ACCESSOR_READ_WRITE #define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) #endif /* !ACCESSOR_READ_WRITE */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-undefs.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-undefs.inc.h index 8f725251..21616666 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-undefs.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-undefs.inc.h @@ -16,11 +16,14 @@ #undef SIMPLE_VALUE #undef NUMBER_VALUE #undef STRING_VALUE -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #undef SYMBOL_VALUE -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#undef INTRINSIC_PROPERTY +#undef ACCESSOR_BUILTIN_FUNCTION_OBJECT +#endif /* ENABLED (JERRY_ES2015) */ #undef OBJECT_VALUE #undef ROUTINE #undef ROUTINE_CONFIGURABLE_ONLY +#undef ROUTINE_WITH_FLAGS #undef ACCESSOR_READ_WRITE #undef ACCESSOR_READ_ONLY diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index 6cf9262b..eea19bf1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -18,6 +18,7 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" #include "ecma-builtins.h" +#include "ecma-builtin-object.h" #include "ecma-conversion.h" #include "ecma-function-object.h" #include "ecma-exceptions.h" @@ -27,6 +28,7 @@ #include "ecma-objects.h" #include "ecma-try-catch-macro.h" #include "lit-magic-strings.h" +#include "lit-char-helpers.h" /** \addtogroup ecma ECMA * @{ @@ -35,7 +37,7 @@ * @{ */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * Helper function for Object.prototype.toString routine when * the @@toStringTag property is present @@ -96,7 +98,7 @@ ecma_builtin_helper_object_to_string_tag_helper (ecma_value_t tag_value) /**< st return ecma_make_string_value (ret_string_p); } /* ecma_builtin_helper_object_to_string_tag_helper */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Common implementation of the Object.prototype.toString routine @@ -140,8 +142,8 @@ ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this arg type_string = ecma_object_get_class_name (obj_p); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_MAGIC_STRING_TO_STRING_TAG); +#if ENABLED (JERRY_ES2015) + ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG); if (ECMA_IS_VALUE_ERROR (tag_value)) { @@ -156,7 +158,7 @@ ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this arg } ecma_free_value (tag_value); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_deref_object (obj_p); } @@ -201,63 +203,68 @@ ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this arg * @return ecma value * Returned value must be freed with ecma_free_value. */ -ecma_value_t +ecma_string_t * ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /**< this object */ uint32_t index) /**< array index */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t index_value = ecma_op_object_get_by_uint32_index (obj_p, index); - ECMA_TRY_CATCH (index_value, - ecma_op_object_get (obj_p, index_string_p), - ret_value); + if (ECMA_IS_VALUE_ERROR (index_value)) + { + return NULL; + } if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) { - ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } - else + + ecma_value_t index_obj_value = ecma_op_to_object (index_value); + + if (ECMA_IS_VALUE_ERROR (index_obj_value)) { - ECMA_TRY_CATCH (index_obj_value, - ecma_op_to_object (index_value), - ret_value); - - ecma_object_t *index_obj_p = ecma_get_object_from_value (index_obj_value); - - ECMA_TRY_CATCH (to_locale_value, - ecma_op_object_get_by_magic_id (index_obj_p, LIT_MAGIC_STRING_TO_LOCALE_STRING_UL), - ret_value); - - if (ecma_op_is_callable (to_locale_value)) - { - ecma_object_t *locale_func_obj_p = ecma_get_object_from_value (to_locale_value); - ECMA_TRY_CATCH (call_value, - ecma_op_function_call (locale_func_obj_p, - ecma_make_object_value (index_obj_p), - NULL, - 0), - ret_value); - ret_value = ecma_op_to_string (call_value); - ECMA_FINALIZE (call_value); - - } - else - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("'toLocaleString' is missing or not a function.")); - } - - ECMA_FINALIZE (to_locale_value); - ECMA_FINALIZE (index_obj_value); + ecma_free_value (index_value); + return NULL; } - ECMA_FINALIZE (index_value); + ecma_string_t *ret_string_p = NULL; + ecma_object_t *index_obj_p = ecma_get_object_from_value (index_obj_value); + ecma_value_t to_locale_value = ecma_op_object_get_by_magic_id (index_obj_p, LIT_MAGIC_STRING_TO_LOCALE_STRING_UL); - ecma_deref_ecma_string (index_string_p); + if (ECMA_IS_VALUE_ERROR (to_locale_value)) + { + goto cleanup; + } - return ret_value; + if (!ecma_op_is_callable (to_locale_value)) + { + ecma_free_value (to_locale_value); + ecma_raise_type_error (ECMA_ERR_MSG ("'toLocaleString' is missing or not a function.")); + goto cleanup; + } + + ecma_object_t *locale_func_obj_p = ecma_get_object_from_value (to_locale_value); + ecma_value_t call_value = ecma_op_function_call (locale_func_obj_p, + index_obj_value, + NULL, + 0); + ecma_deref_object (locale_func_obj_p); + + if (ECMA_IS_VALUE_ERROR (call_value)) + { + goto cleanup; + } + + ret_string_p = ecma_op_to_string (call_value); + ecma_free_value (call_value); + +cleanup: + ecma_deref_object (index_obj_p); + ecma_free_value (index_value); + + return ret_string_p; } /* ecma_builtin_helper_get_to_locale_string_at_index */ - /** * The Object.keys and Object.getOwnPropertyNames routine's common part. * @@ -274,26 +281,23 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ { JERRY_ASSERT (obj_p != NULL); - ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); - ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, opts); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (props_p->item_count == 0) { ecma_collection_destroy (props_p); - return new_array; + return ecma_op_create_array_object (NULL, 0, false); } - JERRY_ASSERT (((ecma_extended_object_t *) new_array_p)->u.array.is_fast_mode); - - ecma_value_t *buffer_p = props_p->buffer_p; - ecma_value_t *values_p = ecma_fast_array_extend (new_array_p, props_p->item_count); - - memcpy (values_p, buffer_p, props_p->item_count * sizeof (ecma_value_t)); - - ecma_collection_free_objects (props_p); + ecma_value_t new_array = ecma_op_create_array_object (props_p->buffer_p, props_p->item_count, false); + ecma_collection_free (props_p); return new_array; } /* ecma_builtin_helper_object_get_properties */ @@ -301,93 +305,49 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ /** * Helper function to normalizing an array index * - * This function clamps the given index to the [0, length] range. - * If the index is negative, it is used as the offset from the end of the array, - * to compute normalized index. - * If the index is greater than the length of the array, the normalized index will be the length of the array. - * If is_last_index_of is true, then we use the method in ECMA-262 v6, 22.2.3.16 to compute the normalized index. * See also: - * ECMA-262 v5, 15.4.4.10 steps 5-6, 7 (part 2) and 8 - * ECMA-262 v5, 15.4.4.12 steps 5-6 - * ECMA-262 v5, 15.4.4.14 steps 5 - * ECMA-262 v5, 15.5.4.13 steps 4, 5 (part 2) and 6-7 + * ECMA-262 v5, 15.4.4.10 steps 5, 6, 7 part 2, 8 + * ECMA-262 v5, 15.4.4.12 steps 5, 6 + * ECMA-262 v5, 15.5.4.13 steps 4 - 7 + * ECMA-262 v6, 22.1.3.6 steps 5 - 7, 8 part 2, 9, 10 + * ECMA-262 v6, 22.1.3.3 steps 5 - 10, 11 part 2, 12, 13 + * ECMA-262 v6, 22.2.3.5 steps 5 - 10, 11 part 2, 12, 13 + * ECMA-262 v6, 22.2.3.23 steps 5 - 10 + * ECMA-262 v6, 24.1.4.3 steps 6 - 8, 9 part 2, 10, 11 + * ECMA-262 v6, 22.2.3.26 steps 7 - 9, 10 part 2, 11, 12 + * ECMA-262 v6, 22.2.3.8 steps 5 - 7, 8 part 2, 9, 10 * * Used by: * - The Array.prototype.slice routine. * - The Array.prototype.splice routine. - * - The Array.prototype.indexOf routine. * - The String.prototype.slice routine. - * - The TypedArray.prototype.indexOf routine. - * - The TypedArray.prototype.lastIndexOf routine + * - The Array.prototype.fill routine. + * - The Array.prototype.copyWithin routine. + * - The TypedArray.prototype.copyWithin routine. + * - The TypedArray.prototype.slice routine. + * - The ArrayBuffer.prototype.slice routine. + * - The TypedArray.prototype.subarray routine. + * - The TypedArray.prototype.fill routine. * - * @return uint32_t - the normalized value of the index + * @return ECMA_VALUE_EMPTY if successful + * conversion error otherwise */ uint32_t -ecma_builtin_helper_array_index_normalize (ecma_number_t index, /**< index */ +ecma_builtin_helper_array_index_normalize (ecma_value_t arg, /**< index */ uint32_t length, /**< array's length */ - bool is_last_index_of) /**< true - normalize for lastIndexOf method*/ + uint32_t *number_p) /**< [out] uint32_t */ { - uint32_t norm_index; + ecma_number_t to_int; - if (!ecma_number_is_nan (index)) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg, &to_int))) { - - if (ecma_number_is_zero (index)) - { - norm_index = 0; - } - else if (ecma_number_is_infinity (index)) - { - if (is_last_index_of) - { - norm_index = ecma_number_is_negative (index) ? (uint32_t) -1 : length - 1; - } - else - { - norm_index = ecma_number_is_negative (index) ? 0 : length; - } - } - else - { - if (ecma_number_is_negative (index)) - { - ecma_number_t index_neg = -index; - - if (is_last_index_of) - { - norm_index = length - ecma_number_to_uint32 (index_neg); - } - else - { - if (index_neg > length) - { - norm_index = 0; - } - else - { - norm_index = length - ecma_number_to_uint32 (index_neg); - } - } - } - else - { - if (index > length) - { - norm_index = is_last_index_of ? length - 1 : length; - } - else - { - norm_index = ecma_number_to_uint32 (index); - } - } - } - } - else - { - norm_index = 0; + return ECMA_VALUE_ERROR; } - return norm_index; + *number_p = ((to_int < 0) ? (uint32_t) JERRY_MAX ((length + to_int), 0) + : (uint32_t) JERRY_MIN (to_int, length)); + + return ECMA_VALUE_EMPTY; } /* ecma_builtin_helper_array_index_normalize */ /** @@ -403,80 +363,80 @@ ecma_builtin_helper_array_index_normalize (ecma_number_t index, /**< index */ * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, /**< array */ +ecma_builtin_helper_array_concat_value (ecma_object_t *array_obj_p, /**< array */ uint32_t *length_p, /**< [in,out] array's length */ ecma_value_t value) /**< value to concat */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - /* 5.b */ - if (ecma_is_value_object (value) - && (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)) +#if ENABLED (JERRY_ES2015) + ecma_value_t is_spreadable = ecma_op_is_concat_spreadable (value); + + if (ECMA_IS_VALUE_ERROR (is_spreadable)) { - /* 5.b.ii */ - ECMA_TRY_CATCH (arg_len_value, - ecma_op_object_get_by_magic_id (ecma_get_object_from_value (value), - LIT_MAGIC_STRING_LENGTH), - ret_value); - ECMA_OP_TO_NUMBER_TRY_CATCH (arg_len_number, arg_len_value, ret_value); + return is_spreadable; + } - uint32_t arg_len = ecma_number_to_uint32 (arg_len_number); + bool spread_object = is_spreadable == ECMA_VALUE_TRUE; +#else /* !ENABLED (JERRY_ES2015) */ + bool spread_object = ecma_is_value_true (ecma_is_value_array (value)); +#endif /* ENABLED (JERRY_ES2015) */ - /* 5.b.iii */ - for (uint32_t array_index = 0; - array_index < arg_len && ecma_is_value_empty (ret_value); - array_index++) + if (spread_object) + { + ecma_object_t *obj_p = ecma_get_object_from_value (value); + +#if ENABLED (JERRY_ES2015) + uint32_t arg_len; + ecma_value_t error = ecma_op_object_get_length (obj_p, &arg_len); + + if (ECMA_IS_VALUE_ERROR (error)) + { + return error; + } +#else /* !ENABLED (JERRY_ES2015) */ + /* 5.b.ii */ + uint32_t arg_len = ecma_array_get_length (obj_p); +#endif /* ENABLED (JERRY_ES2015) */ + /* 5.b.iii */ + for (uint32_t array_index = 0; array_index < arg_len; array_index++) { - ecma_string_t *array_index_string_p = ecma_new_ecma_string_from_uint32 (array_index); - /* 5.b.iii.2 */ - ECMA_TRY_CATCH (get_value, - ecma_op_object_find (ecma_get_object_from_value (value), - array_index_string_p), - ret_value); + ecma_value_t get_value = ecma_op_object_find_by_uint32_index (obj_p, array_index); - if (ecma_is_value_found (get_value)) + if (ECMA_IS_VALUE_ERROR (get_value)) { - /* 5.b.iii.3.a */ - ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 (*length_p + array_index); - - /* 5.b.iii.3.b */ - /* This will always be a simple value since 'is_throw' is false, so no need to free. */ - ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p, - new_array_index_string_p, - get_value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - ecma_deref_ecma_string (new_array_index_string_p); + return get_value; } - ECMA_FINALIZE (get_value); + if (!ecma_is_value_found (get_value)) + { + continue; + } - ecma_deref_ecma_string (array_index_string_p); + /* 5.b.iii.3.b */ + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, + *length_p + array_index, + get_value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + + JERRY_ASSERT (ecma_is_value_true (put_comp)); + ecma_free_value (get_value); } *length_p += arg_len; - - ECMA_OP_TO_NUMBER_FINALIZE (arg_len_number); - ECMA_FINALIZE (arg_len_value); - } - else - { - ecma_string_t *new_array_index_string_p = ecma_new_ecma_string_from_uint32 ((*length_p)++); - - /* 5.c.i */ - /* This will always be a simple value since 'is_throw' is false, so no need to free. */ - ecma_value_t put_comp = ecma_builtin_helper_def_prop (obj_p, - new_array_index_string_p, - value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - ecma_deref_ecma_string (new_array_index_string_p); + return ECMA_VALUE_EMPTY; } - return ret_value; + /* 5.c.i */ + /* This will always be a simple value since 'is_throw' is false, so no need to free. */ + ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, + (*length_p)++, + value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (put_comp)); + + return ECMA_VALUE_EMPTY; } /* ecma_builtin_helper_array_concat_value */ /** @@ -559,31 +519,48 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_string_t *original_st /* 5 (indexOf) -- 6 (lastIndexOf) */ const ecma_length_t original_len = ecma_string_get_length (original_str_p); -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) /* 4, 6 (startsWith, includes, endsWith) */ - if (mode >= ECMA_STRING_STARTS_WITH - && (ecma_is_value_object (arg1) - && ecma_object_class_is (ecma_get_object_from_value (arg1), LIT_MAGIC_STRING_REGEXP_UL))) + if (mode >= ECMA_STRING_STARTS_WITH) { - JERRY_ASSERT (ECMA_STRING_LAST_INDEX_OF < mode && mode <= ECMA_STRING_ENDS_WITH); - return ecma_raise_type_error (ECMA_ERR_MSG ("Search string can't be of type: RegExp")); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + ecma_value_t regexp = ecma_op_is_regexp (arg1); - /* 3 */ - ecma_value_t search_str_val = ecma_op_to_string (arg1); + if (ECMA_IS_VALUE_ERROR (regexp)) + { + return regexp; + } - if (ECMA_IS_VALUE_ERROR (search_str_val)) - { - return search_str_val; + if (regexp == ECMA_VALUE_TRUE) + { + JERRY_ASSERT (ECMA_STRING_LAST_INDEX_OF < mode && mode <= ECMA_STRING_ENDS_WITH); + return ecma_raise_type_error (ECMA_ERR_MSG ("Search string can't be of type: RegExp")); + } } +#endif /* ENABLED (JERRY_ES2015) */ /* 7, 8 */ - ecma_string_t *search_str_p = ecma_get_string_from_value (search_str_val); + ecma_string_t *search_str_p = ecma_op_to_string (arg1); + + if (JERRY_UNLIKELY (search_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } /* 4 (indexOf, lastIndexOf), 9 (startsWith, includes), 10 (endsWith) */ ecma_number_t pos_num; - ecma_value_t ret_value = ecma_get_number (arg2, &pos_num); + ecma_value_t ret_value; +#if ENABLED (JERRY_ES2015) + if (mode > ECMA_STRING_LAST_INDEX_OF) + { + ret_value = ecma_op_to_integer (arg2, &pos_num); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + ret_value = ecma_get_number (arg2, &pos_num); +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ /* 10 (startsWith, includes), 11 (endsWith) */ if (ECMA_IS_VALUE_ERROR (ret_value)) @@ -605,10 +582,12 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_string_t *original_st switch (mode) { -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) case ECMA_STRING_STARTS_WITH: { - if (pos_num + start > original_len) + const ecma_length_t search_len = ecma_string_get_length (search_str_p); + + if (search_len + start > original_len) { break; } @@ -656,7 +635,7 @@ ecma_builtin_helper_string_prototype_object_index_of (ecma_string_t *original_st } break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +#endif /* ENABLED (JERRY_ES2015) */ case ECMA_STRING_INDEX_OF: case ECMA_STRING_LAST_INDEX_OF: @@ -710,7 +689,7 @@ ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index if (!search_len) { match_found = true; - *ret_index_p = first_index ? 0 : original_len; + *ret_index_p = first_index ? start_pos : original_len; } else { @@ -732,7 +711,7 @@ ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index /* iterate original string and try to match at each position */ bool searching = true; - ecma_char_t first_char = lit_utf8_read_next (&search_str_curr_p); + ecma_char_t first_char = lit_cesu8_read_next (&search_str_curr_p); while (searching) { /* match as long as possible */ @@ -741,14 +720,14 @@ ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index if (match_len < search_len && index + match_len < original_len && - lit_utf8_read_next (&original_str_curr_p) == first_char) + lit_cesu8_read_next (&original_str_curr_p) == first_char) { const lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p; match_len++; while (match_len < search_len && index + match_len < original_len && - lit_utf8_read_next (&original_str_curr_p) == lit_utf8_read_next (&nested_search_str_curr_p)) + lit_cesu8_read_next (&original_str_curr_p) == lit_cesu8_read_next (&nested_search_str_curr_p)) { match_len++; } @@ -838,7 +817,7 @@ ecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, /**< object */ */ ecma_value_t ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ - ecma_string_t *index_p, /**< index string */ + ecma_string_t *name_p, /**< name string */ ecma_value_t value, /**< value */ uint32_t opts) /**< any combination of ecma_property_flag_t bits * with the optional ECMA_IS_THROW flag */ @@ -850,10 +829,189 @@ ecma_builtin_helper_def_prop (ecma_object_t *obj_p, /**< object */ prop_desc.value = value; return ecma_op_object_define_own_property (obj_p, - index_p, + name_p, &prop_desc); } /* ecma_builtin_helper_def_prop */ +/** + * GetSubstitution abstract operation + * + * See: + * ECMA-262 v6.0 21.1.3.14.1 + */ +void +ecma_builtin_replace_substitute (ecma_replace_context_t *ctx_p) /**< replace context */ +{ + JERRY_ASSERT (ctx_p->string_p != NULL); + JERRY_ASSERT (ctx_p->matched_p == NULL + || (ctx_p->matched_p >= ctx_p->string_p + && ctx_p->matched_p <= ctx_p->string_p + ctx_p->string_size)); + + lit_utf8_size_t replace_size; + uint8_t replace_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *replace_buf_p = ecma_string_get_chars (ctx_p->replace_str_p, + &replace_size, + NULL, + NULL, + &replace_flags); + + const lit_utf8_byte_t *const replace_end_p = replace_buf_p + replace_size; + const lit_utf8_byte_t *curr_p = replace_buf_p; + const lit_utf8_byte_t *last_inserted_end_p = replace_buf_p; + + while (curr_p < replace_end_p) + { + if (*curr_p++ == LIT_CHAR_DOLLAR_SIGN) + { + ecma_stringbuilder_append_raw (&(ctx_p->builder), + last_inserted_end_p, + (lit_utf8_size_t) (curr_p - last_inserted_end_p - 1)); + if (curr_p >= replace_end_p) + { + last_inserted_end_p = curr_p - 1; + break; + } + + const lit_utf8_byte_t c = *curr_p++; + + switch (c) + { + case LIT_CHAR_DOLLAR_SIGN: + { + ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN); + break; + } + case LIT_CHAR_AMPERSAND: + { +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (ctx_p->matched_p == NULL)) + { + JERRY_ASSERT (ctx_p->capture_count == 0); + JERRY_ASSERT (ctx_p->u.collection_p != NULL); + JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0); + const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0]; + + JERRY_ASSERT (ecma_is_value_string (match_value)); + ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (match_value)); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (ctx_p->matched_p != NULL); + ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->matched_p, ctx_p->matched_size); + break; + } + case LIT_CHAR_GRAVE_ACCENT: + { + ecma_stringbuilder_append_raw (&(ctx_p->builder), ctx_p->string_p, ctx_p->match_byte_pos); + break; + } + case LIT_CHAR_SINGLE_QUOTE: + { +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (ctx_p->matched_p == NULL)) + { + JERRY_ASSERT (ctx_p->capture_count == 0); + JERRY_ASSERT (ctx_p->u.collection_p != NULL); + JERRY_ASSERT (ctx_p->u.collection_p->item_count > 0); + const ecma_value_t match_value = ctx_p->u.collection_p->buffer_p[0]; + + JERRY_ASSERT (ecma_is_value_string (match_value)); + const ecma_string_t *const matched_p = ecma_get_string_from_value (match_value); + const lit_utf8_size_t match_size = ecma_string_get_size (matched_p); + const lit_utf8_byte_t *const begin_p = ctx_p->string_p + ctx_p->match_byte_pos + match_size; + + ecma_stringbuilder_append_raw (&(ctx_p->builder), + begin_p, + (lit_utf8_size_t) (ctx_p->string_p + ctx_p->string_size - begin_p)); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (ctx_p->matched_p != NULL); + ecma_stringbuilder_append_raw (&(ctx_p->builder), + ctx_p->matched_p + ctx_p->matched_size, + ctx_p->string_size - ctx_p->match_byte_pos - ctx_p->matched_size); + break; + } + default: + { + const lit_utf8_byte_t *const number_begin_p = curr_p - 1; + + if (lit_char_is_decimal_digit (c)) + { + uint32_t capture_count = ctx_p->capture_count; +#if ENABLED (JERRY_ES2015) + if (capture_count == 0 && ctx_p->u.collection_p != NULL) + { + capture_count = ctx_p->u.collection_p->item_count; + } +#endif /* ENABLED (JERRY_ES2015) */ + + uint8_t idx = (uint8_t) (c - LIT_CHAR_0); + if (curr_p < replace_end_p && lit_char_is_decimal_digit (*(curr_p))) + { + uint8_t two_digit_index = (uint8_t) (idx * 10 + (uint8_t) (*(curr_p) - LIT_CHAR_0)); + if (two_digit_index < capture_count) + { + idx = two_digit_index; + curr_p++; + } + } + + if (idx > 0 && idx < capture_count) + { + if (ctx_p->capture_count > 0) + { +#if ENABLED (JERRY_BUILTIN_REGEXP) + JERRY_ASSERT (ctx_p->u.captures_p != NULL); + const ecma_regexp_capture_t *const capture_p = ctx_p->u.captures_p + idx; + + if (ECMA_RE_IS_CAPTURE_DEFINED (capture_p)) + { + ecma_stringbuilder_append_raw (&(ctx_p->builder), + capture_p->begin_p, + (lit_utf8_size_t) (capture_p->end_p - capture_p->begin_p)); + } + + break; +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ + } +#if ENABLED (JERRY_ES2015) + else if (ctx_p->u.collection_p != NULL) + { + const ecma_value_t capture_value = ctx_p->u.collection_p->buffer_p[idx]; + if (!ecma_is_value_undefined (capture_value)) + { + ecma_stringbuilder_append (&(ctx_p->builder), ecma_get_string_from_value (capture_value)); + } + + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + } + + ecma_stringbuilder_append_byte (&(ctx_p->builder), LIT_CHAR_DOLLAR_SIGN); + curr_p = number_begin_p; + break; + } + } + + last_inserted_end_p = curr_p; + } + } + + ecma_stringbuilder_append_raw (&(ctx_p->builder), + last_inserted_end_p, + (lit_utf8_size_t) (replace_end_p - last_inserted_end_p)); + + if (replace_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) replace_buf_p, replace_size); + } +} /* ecma_builtin_replace_substitute */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index 319811a8..e9f815b3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -18,6 +18,8 @@ #include "ecma-globals.h" #include "ecma-exceptions.h" +#include "ecma-helpers.h" +#include "ecma-regexp-object.h" /** \addtogroup ecma ECMA * @{ @@ -32,8 +34,8 @@ typedef enum { /** These routines must be in this order */ - ECMA_STRING_INDEX_OF, /**< String.indexOf: ECMA-262 v5, 15.5.4.7 */ ECMA_STRING_LAST_INDEX_OF, /**< String.lastIndexOf: ECMA-262 v5, 15.5.4.8 */ + ECMA_STRING_INDEX_OF, /**< String.indexOf: ECMA-262 v5, 15.5.4.7 */ ECMA_STRING_STARTS_WITH, /**< String.startsWith: ECMA-262 v6, 21.1.3.18 */ ECMA_STRING_INCLUDES, /**< String.includes: ECMA-262 v6, 21.1.3.7 */ ECMA_STRING_ENDS_WITH /**< String.includes: ECMA-262 v6, 21.1.3.6 */ @@ -41,14 +43,14 @@ typedef enum ecma_value_t ecma_builtin_helper_object_to_string (const ecma_value_t this_arg); -ecma_value_t +ecma_string_t * ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, uint32_t index); ecma_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, uint32_t opts); ecma_value_t ecma_builtin_helper_array_concat_value (ecma_object_t *obj_p, uint32_t *length_p, ecma_value_t value); uint32_t -ecma_builtin_helper_array_index_normalize (ecma_number_t index, uint32_t length, bool last_index_of); +ecma_builtin_helper_array_index_normalize (ecma_value_t arg, uint32_t length, uint32_t *number_p); uint32_t ecma_builtin_helper_string_index_normalize (ecma_number_t index, uint32_t length, bool nan_to_zero); ecma_value_t @@ -58,11 +60,47 @@ bool ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, ecma_string_t *search_str_p, bool first_index, ecma_length_t start_pos, ecma_length_t *ret_index_p); ecma_value_t -ecma_builtin_helper_def_prop (ecma_object_t *obj_p, ecma_string_t *index_p, ecma_value_t value, uint32_t opts); +ecma_builtin_helper_def_prop (ecma_object_t *obj_p, ecma_string_t *name_p, ecma_value_t value, uint32_t opts); ecma_value_t ecma_builtin_helper_def_prop_by_index (ecma_object_t *obj_p, uint32_t index, ecma_value_t value, uint32_t opts); +/** + * Context for replace substitutions + */ +typedef struct +{ + ecma_stringbuilder_t builder; /**< result string builder */ + const lit_utf8_byte_t *string_p; /**< source string */ + lit_utf8_size_t string_size; /**< source string size */ + const lit_utf8_byte_t *matched_p; /**< matched string */ + lit_utf8_size_t matched_size; /**< matcehd string size */ + lit_utf8_size_t match_byte_pos; /**< byte position of the match in the source string */ + ecma_length_t index; /**< current match index */ + + /** + * Capture results + */ + union + { +#if ENABLED (JERRY_BUILTIN_REGEXP) + const ecma_regexp_capture_t *captures_p; /**< array of regexp capturing groups */ +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ + const ecma_collection_t *collection_p; /**< collection of captured substrings */ + } u; + + uint32_t capture_count; /**< number of captures in the capturing group array */ + ecma_string_t *replace_str_p; /**< replacement string */ +} ecma_replace_context_t; + +void +ecma_builtin_replace_substitute (ecma_replace_context_t *ctx_p); + +#if ENABLED (JERRY_ES2015) +bool +ecma_builtin_is_regexp_exec (ecma_extended_object_t *obj_p); +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_BUILTIN_DATE) /** @@ -109,6 +147,9 @@ typedef enum } ecma_date_timezone_t; /* ecma-builtin-helpers-date.c */ +extern const char day_names_p[7][3]; +extern const char month_names_p[12][3]; + ecma_number_t ecma_date_day (ecma_number_t time); ecma_number_t ecma_date_time_within_day (ecma_number_t time); ecma_number_t ecma_date_year_from_time (ecma_number_t time); @@ -193,9 +234,9 @@ ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, const /** * Comparison callback function header for sorting helper routines. */ -typedef ecma_value_t (*ecma_builtin_helper_sort_compare_fn_t)(ecma_value_t lhs, /**< left value */ - ecma_value_t rhs, /**< right value */ - ecma_value_t compare_func); /**< compare function */ +typedef ecma_value_t (*ecma_builtin_helper_sort_compare_fn_t) (ecma_value_t lhs, /**< left value */ + ecma_value_t rhs, /**< right value */ + ecma_value_t compare_func); /**< compare function */ ecma_value_t ecma_builtin_helper_array_heap_sort_helper (ecma_value_t *array_p, uint32_t right, diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h index 06a10fb6..ec082e8f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h @@ -45,6 +45,8 @@ static ecma_value_t c_function_name (ROUTINE_ARG_LIST_ ## args_number); #define ROUTINE_CONFIGURABLE_ONLY(name, c_function_name, args_number, length_prop_value) \ static ecma_value_t c_function_name (ROUTINE_ARG_LIST_ ## args_number); +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) \ + static ecma_value_t c_function_name (ROUTINE_ARG_LIST_ ## args_number); #define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) \ static ecma_value_t c_getter_func_name (ROUTINE_ARG_LIST_0); \ static ecma_value_t c_setter_func_name (ROUTINE_ARG_LIST_1); @@ -68,6 +70,8 @@ enum ECMA_ROUTINE_ ## name ## c_function_name, #define ROUTINE_CONFIGURABLE_ONLY(name, c_function_name, args_number, length_prop_value) \ ECMA_ROUTINE_ ## name ## c_function_name, +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) \ + ECMA_ROUTINE_ ## name ## c_function_name, #define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) \ ECMA_ACCESSOR_ ## name ## c_getter_func_name, \ ECMA_ACCESSOR_ ## name ## c_setter_func_name, @@ -98,6 +102,13 @@ const ecma_builtin_property_descriptor_t PROPERTY_DESCRIPTOR_LIST_NAME[] = ECMA_PROPERTY_FLAG_CONFIGURABLE, \ ECMA_ROUTINE_VALUE (ECMA_ROUTINE_ ## name ## c_function_name, length_prop_value) \ }, +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) \ + { \ + name, \ + ECMA_BUILTIN_PROPERTY_ROUTINE, \ + flags, \ + ECMA_ROUTINE_VALUE (ECMA_ROUTINE_ ## name ## c_function_name, length_prop_value) \ + }, #define ACCESSOR_READ_ONLY(name, c_getter_func_name, prop_attributes) \ { \ name, \ @@ -105,6 +116,14 @@ const ecma_builtin_property_descriptor_t PROPERTY_DESCRIPTOR_LIST_NAME[] = prop_attributes, \ ECMA_ACCESSOR_ ## name ## c_getter_func_name \ }, +#define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) \ + { \ + name, \ + ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_WRITE, \ + prop_attributes, \ + ECMA_ACCESSOR_READ_WRITE (ECMA_ACCESSOR_ ## name ## c_getter_func_name, \ + ECMA_ACCESSOR_ ## name ## c_setter_func_name) \ + }, #else /* BUILTIN_CUSTOM_DISPATCH */ #define ROUTINE(name, c_function_name, args_number, length_prop_value) \ { \ @@ -120,6 +139,13 @@ const ecma_builtin_property_descriptor_t PROPERTY_DESCRIPTOR_LIST_NAME[] = ECMA_PROPERTY_FLAG_CONFIGURABLE, \ ECMA_ROUTINE_VALUE (c_function_name, length_prop_value) \ }, +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) \ + { \ + name, \ + ECMA_BUILTIN_PROPERTY_ROUTINE, \ + flags, \ + ECMA_ROUTINE_VALUE (c_function_name, length_prop_value) \ + }, #define ACCESSOR_READ_ONLY(name, c_getter_func_name, prop_attributes) \ { \ name, \ @@ -127,6 +153,13 @@ const ecma_builtin_property_descriptor_t PROPERTY_DESCRIPTOR_LIST_NAME[] = prop_attributes, \ c_getter_func_name \ }, +#define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) \ + { \ + name, \ + ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_WRITE, \ + prop_attributes, \ + ECMA_ACCESSOR_READ_WRITE (c_getter_func_name, c_setter_func_name) \ + }, #endif /* !BUILTIN_CUSTOM_DISPATCH */ #define OBJECT_VALUE(name, obj_builtin_id, prop_attributes) \ { \ @@ -156,22 +189,29 @@ const ecma_builtin_property_descriptor_t PROPERTY_DESCRIPTOR_LIST_NAME[] = prop_attributes, \ magic_string_id \ }, -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) -#define SYMBOL_VALUE(name, desc_string_id) \ +#if ENABLED (JERRY_ES2015) +#define SYMBOL_VALUE(symbol, desc_magic_string_id) \ { \ - name, \ + symbol, \ ECMA_BUILTIN_PROPERTY_SYMBOL, \ ECMA_PROPERTY_FIXED, \ - desc_string_id \ + desc_magic_string_id \ }, -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ -#define ACCESSOR_READ_WRITE(name, c_getter_name, c_setter_name, prop_attributes) \ +#define INTRINSIC_PROPERTY(name, magic_string_id, prop_attributes) \ { \ name, \ - ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_WRITE, \ + ECMA_BUILTIN_PROPERTY_INTRINSIC_PROPERTY, \ prop_attributes, \ - ECMA_ACCESSOR_READ_WRITE (ECMA_ACCESSOR_ ## name ## c_getter_name, ECMA_ACCESSOR_ ## name ## c_setter_name) \ + magic_string_id \ }, +#define ACCESSOR_BUILTIN_FUNCTION(name, getter_builtin_id, setter_builtin_id, prop_attributes) \ + { \ + name, \ + ECMA_BUILTIN_PROPERTY_ACCESSOR_BUILTIN_FUNCTION, \ + prop_attributes, \ + ECMA_ACCESSOR_READ_WRITE (getter_builtin_id, setter_builtin_id) \ + }, +#endif /* ENABLED (JERRY_ES2015) */ #include BUILTIN_INC_HEADER_NAME { LIT_MAGIC_STRING__COUNT, @@ -222,6 +262,11 @@ DISPATCH_ROUTINE_ROUTINE_NAME (uint16_t builtin_routine_id, /**< built-in wide r { \ return c_function_name (this_arg_value ROUTINE_ARG_LIST_ ## args_number); \ } +#define ROUTINE_WITH_FLAGS(name, c_function_name, args_number, length_prop_value, flags) \ + case ECMA_ROUTINE_ ## name ## c_function_name: \ + { \ + return c_function_name (this_arg_value ROUTINE_ARG_LIST_ ## args_number); \ + } #define ACCESSOR_READ_WRITE(name, c_getter_func_name, c_setter_func_name, prop_attributes) \ case ECMA_ACCESSOR_ ## name ## c_getter_func_name: \ { \ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.c b/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.c new file mode 100644 index 00000000..bd73ec77 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.c @@ -0,0 +1,143 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-array-object.h" +#include "ecma-gc.h" +#include "lit-char-helpers.h" + +#if ENABLED (JERRY_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +/** + * This object has a custom dispatch function. + */ +#define BUILTIN_CUSTOM_DISPATCH + +/** + * List of built-in routine identifiers. + */ +enum +{ + ECMA_INTRINSIC_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1, + ECMA_INTRINSIC_PARSE_FLOAT, + ECMA_INTRINSIC_PARSE_INT, + ECMA_INTRINSIC_ARRAY_PROTOTYPE_VALUES +}; + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-intrinsic.inc.h" +#define BUILTIN_UNDERSCORED_ID intrinsic +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup intrinsic ECMA Intrinsic object built-in + * @{ + */ + +/** + * The %ArrayProto_values% intrinsic routine + * + * See also: + * ECMA-262 v5, 15.4.4.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_intrinsic_array_prototype_values (ecma_value_t this_value) /**< this argument */ +{ + ecma_value_t this_obj = ecma_op_to_object (this_value); + + if (ECMA_IS_VALUE_ERROR (this_obj)) + { + return this_obj; + } + + ecma_object_t *this_obj_p = ecma_get_object_from_value (this_obj); + + ecma_value_t ret_value = ecma_op_create_array_iterator (this_obj_p, ECMA_ITERATOR_VALUES); + + ecma_deref_object (this_obj_p); + + return ret_value; +} /* ecma_builtin_intrinsic_array_prototype_values */ + +/** + * Dispatcher of the built-in's routines + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_intrinsic_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine identifier */ + ecma_value_t this_arg, /**< 'this' argument value */ + const ecma_value_t arguments_list_p[], /**< list of arguments + * passed to routine */ + ecma_length_t arguments_number) /**< length of arguments' list */ +{ + JERRY_UNUSED (arguments_number); + + ecma_value_t routine_arg_1 = arguments_list_p[0]; + ecma_value_t routine_arg_2 = arguments_list_p[1]; + + if (builtin_routine_id == ECMA_INTRINSIC_ARRAY_PROTOTYPE_VALUES) + { + return ecma_builtin_intrinsic_array_prototype_values (this_arg); + } + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + if (builtin_routine_id <= ECMA_INTRINSIC_PARSE_INT) + { + ecma_string_t *str_p = ecma_op_to_string (routine_arg_1); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ECMA_STRING_TO_UTF8_STRING (str_p, string_buff, string_buff_size); + + if (builtin_routine_id == ECMA_INTRINSIC_PARSE_INT) + { + ret_value = ecma_number_parse_int (string_buff, + string_buff_size, + routine_arg_2); + } + else + { + JERRY_ASSERT (builtin_routine_id == ECMA_INTRINSIC_PARSE_FLOAT); + ret_value = ecma_number_parse_float (string_buff, + string_buff_size); + } + ECMA_FINALIZE_UTF8_STRING (string_buff, string_buff_size); + ecma_deref_ecma_string (str_p); + } + + return ret_value; +} /* ecma_builtin_intrinsic_dispatch_routine */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.inc.h new file mode 100644 index 00000000..8fb9152d --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-intrinsic.inc.h @@ -0,0 +1,73 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Intrinsic built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 19.4.2.2 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_HAS_INSTANCE, + LIT_MAGIC_STRING_HAS_INSTANCE) + +/* ECMA-262 v6, 19.4.2.3 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, + LIT_MAGIC_STRING_IS_CONCAT_SPREADABLE) + +/* ECMA-262 v6, 19.4.2.4 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_ITERATOR, + LIT_MAGIC_STRING_ITERATOR) + +/* ECMA-262 v6, 19.4.2.6 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_MATCH, + LIT_MAGIC_STRING_MATCH) + +/* ECMA-262 v6, 19.4.2.8 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_REPLACE, + LIT_MAGIC_STRING_REPLACE) + +/* ECMA-262 v6, 19.4.2.9 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_SEARCH, + LIT_MAGIC_STRING_SEARCH) + +/* ECMA-262 v6, 19.4.2.10 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_SPECIES, + LIT_MAGIC_STRING_SPECIES) + +/* ECMA-262 v6, 19.4.2.11 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_SPLIT, + LIT_MAGIC_STRING_SPLIT) + +/* ECMA-262 v6, 19.4.2.12 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_TO_PRIMITIVE, + LIT_MAGIC_STRING_TO_PRIMITIVE) + +/* ECMA-262 v6, 19.4.2.13 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_TO_STRING_TAG) + +/* ECMA-262 v6, 19.4.2.14 */ +SYMBOL_VALUE (LIT_GLOBAL_SYMBOL_UNSCOPABLES, + LIT_MAGIC_STRING_UNSCOPABLES) +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_PARSE_FLOAT, ECMA_INTRINSIC_PARSE_FLOAT, 1, 1) +ROUTINE (LIT_MAGIC_STRING_PARSE_INT, ECMA_INTRINSIC_PARSE_INT, 2, 2) +ROUTINE (LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, ECMA_INTRINSIC_ARRAY_PROTOTYPE_VALUES, 0, 0) +#endif /* ENABLED (JERRY_ES2015) */ +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.c index aef5702d..b50b348a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.c @@ -17,7 +17,7 @@ #include "ecma-builtins.h" #include "ecma-iterator-object.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -60,4 +60,4 @@ ecma_builtin_iterator_prototype_object_iterator (ecma_value_t this_val) /**< thi * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.inc.h index 50702627..8ae27b9f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-iterator-prototype.inc.h @@ -19,12 +19,12 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ecma_builtin_iterator_prototype_object_iterator, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index 494a6161..15350bae 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -174,18 +174,13 @@ ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument } case LIT_CHAR_LOWERCASE_U: { - if ((end_p - current_p <= ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH)) + uint32_t hex_value = lit_char_hex_lookup (current_p + 1, end_p, ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH); + if (hex_value == UINT32_MAX) { goto invalid_string; } - ecma_char_t code_unit; - if (!(lit_read_code_unit_from_hex (current_p + 1, ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH, &code_unit))) - { - goto invalid_string; - } - - ecma_stringbuilder_append_char (&result_builder, code_unit); + ecma_stringbuilder_append_char (&result_builder, (ecma_char_t) hex_value); current_p += ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH + 1; break; } @@ -204,7 +199,7 @@ ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument ecma_stringbuilder_append_raw (&result_builder, unappended_p, - (lit_utf8_size_t)(current_p - unappended_p)); + (lit_utf8_size_t) (current_p - unappended_p)); token_p->u.string_p = ecma_stringbuilder_finalize (&result_builder); token_p->current_p = current_p + 1; token_p->type = TOKEN_STRING; @@ -571,13 +566,12 @@ ecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument * break; } - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (length); - ecma_value_t completion = ecma_builtin_helper_def_prop (array_p, - index_str_p, - value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + ecma_value_t completion; + completion = ecma_builtin_helper_def_prop_by_index (array_p, + length, + value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); JERRY_ASSERT (ecma_is_value_true (completion)); - ecma_deref_ecma_string (index_str_p); ecma_free_value (value); ecma_builtin_json_parse_next_token (token_p, false); @@ -738,15 +732,13 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */ { JERRY_UNUSED (this_arg); - ecma_value_t text_value = ecma_op_to_string (arg1); + ecma_string_t *text_string_p = ecma_op_to_string (arg1); - if (ECMA_IS_VALUE_ERROR (text_value)) + if (JERRY_UNLIKELY (text_string_p == NULL)) { - return text_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *text_string_p = ecma_get_string_from_value (text_value); - ECMA_STRING_TO_UTF8_STRING (text_string_p, str_start_p, string_size); ecma_value_t result = ecma_builtin_json_parse_buffer (str_start_p, string_size); ECMA_FINALIZE_UTF8_STRING (str_start_p, string_size); @@ -907,6 +899,13 @@ ecma_builtin_json_serialize_object (ecma_json_stringify_context_t *context_p, /* else { property_keys_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (property_keys_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ } /* 8. */ @@ -1001,7 +1000,12 @@ static ecma_value_t ecma_builtin_json_serialize_array (ecma_json_stringify_context_t *context_p, /**< context*/ ecma_object_t *obj_p) /**< the array object*/ { - JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); +#ifndef JERRY_NDEBUG + ecma_value_t obj_value = ecma_make_object_value (obj_p); + ecma_value_t is_array = ecma_is_value_array (obj_value); + + JERRY_ASSERT (ecma_is_value_true (is_array)); +#endif /* !JERRY_NDEBUG */ /* 1. */ if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) @@ -1023,7 +1027,23 @@ ecma_builtin_json_serialize_array (ecma_json_stringify_context_t *context_p, /** const bool has_gap = !ecma_compare_ecma_string_to_magic_id (context_p->gap_str_p, LIT_MAGIC_STRING__EMPTY); /* 6. */ - uint32_t array_length = ((ecma_extended_object_t *) obj_p)->u.array.length; + uint32_t array_length; + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t length_value = ecma_op_object_get_length (obj_p, &array_length); + + if (ECMA_IS_VALUE_ERROR (length_value)) + { + return length_value; + } + } + else +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + { + array_length = ((ecma_extended_object_t *) obj_p)->u.array.length; + } ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_LEFT_SQUARE); @@ -1166,35 +1186,36 @@ ecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p, ecma_object_t *obj_p = ecma_get_object_from_value (value); lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p); - ecma_value_t result = ECMA_VALUE_EMPTY; - /* 5.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL) { - result = ecma_op_to_number (value); + value = ecma_op_to_number (value); + ecma_deref_object (obj_p); + + if (ECMA_IS_VALUE_ERROR (value)) + { + return value; + } } /* 5.b */ else if (class_name == LIT_MAGIC_STRING_STRING_UL) { - result = ecma_op_to_string (value); + ecma_string_t *str_p = ecma_op_to_string (value); + ecma_deref_object (obj_p); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + value = ecma_make_string_value (str_p); } /* 5.c */ else if (class_name == LIT_MAGIC_STRING_BOOLEAN_UL) { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - result = ext_object_p->u.class_prop.u.value; - } - - if (!ecma_is_value_empty (result)) - { + value = ext_object_p->u.class_prop.u.value; ecma_deref_object (obj_p); - - if (ECMA_IS_VALUE_ERROR (result)) - { - return result; - } - - value = result; } } @@ -1236,9 +1257,8 @@ ecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p, /* 10.a */ if (!ecma_number_is_nan (num_value) && !ecma_number_is_infinity (num_value)) { - ecma_value_t result_value = ecma_op_to_string (value); - JERRY_ASSERT (ecma_is_value_string (result_value)); - ecma_string_t *result_string_p = ecma_get_string_from_value (result_value); + ecma_string_t *result_string_p = ecma_op_to_string (value); + JERRY_ASSERT (result_string_p != NULL); ecma_stringbuilder_append (&context_p->result_builder, result_string_p); ecma_deref_ecma_string (result_string_p); @@ -1256,12 +1276,21 @@ ecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p, /* 11. */ if (ecma_is_value_object (value) && !ecma_op_is_callable (value)) { + ecma_value_t is_array = ecma_is_value_array (value); + +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (is_array)) + { + ecma_free_value (value); + return is_array; + } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_object_t *obj_p = ecma_get_object_from_value (value); - lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p); ecma_value_t ret_value; /* 10.a */ - if (class_name == LIT_MAGIC_STRING_ARRAY_UL) + if (ecma_is_value_true (is_array)) { ret_value = ecma_builtin_json_serialize_array (context_p, obj_p); } @@ -1375,7 +1404,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ context.replacer_function_p = obj_p; } /* 4.b */ - else if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_ARRAY_UL) + else if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY) { ecma_extended_object_t *array_object_p = (ecma_extended_object_t *) obj_p; uint32_t array_length = array_object_p->u.array.length; @@ -1384,9 +1413,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ /* 4.b.iii.5 */ while (index < array_length) { - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t value = ecma_op_object_get (obj_p, index_str_p); - ecma_deref_ecma_string (index_str_p); + ecma_value_t value = ecma_op_object_get_by_uint32_index (obj_p, index); if (ECMA_IS_VALUE_ERROR (value)) { @@ -1406,25 +1433,29 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ /* 4.b.iii.5.e */ else if (ecma_is_value_number (value)) { - ecma_value_t number_str_value = ecma_op_to_string (value); - JERRY_ASSERT (ecma_is_value_string (number_str_value)); - item = number_str_value; + ecma_string_t *number_str_p = ecma_op_to_string (value); + JERRY_ASSERT (number_str_p != NULL); + item = ecma_make_string_value (number_str_p); } /* 4.b.iii.5.f */ - else if (ecma_is_value_object (value) - && (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_NUMBER_UL - || ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_STRING_UL)) + else if (ecma_is_value_object (value)) { - ecma_value_t str_val = ecma_op_to_string (value); + ecma_object_t *value_obj_p = ecma_get_object_from_value (value); + lit_magic_string_id_t class_id = ecma_object_get_class_name (value_obj_p); - if (ECMA_IS_VALUE_ERROR (str_val)) + if (class_id == LIT_MAGIC_STRING_NUMBER_UL || class_id == LIT_MAGIC_STRING_STRING_UL) { - ecma_collection_free (context.property_list_p); - ecma_free_value (value); - return str_val; - } + ecma_string_t *str_p = ecma_op_to_string (value); - item = str_val; + if (JERRY_UNLIKELY (str_p == NULL)) + { + ecma_collection_free (context.property_list_p); + ecma_free_value (value); + return ECMA_VALUE_ERROR; + } + + item = ecma_make_string_value (str_p); + } } ecma_free_value (value); @@ -1474,15 +1505,15 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ /* 5.b */ else if (class_name == LIT_MAGIC_STRING_STRING_UL) { - ecma_value_t value = ecma_op_to_string (arg3); + ecma_string_t *value_str_p = ecma_op_to_string (arg3); - if (ECMA_IS_VALUE_ERROR (value)) + if (JERRY_UNLIKELY (value_str_p == NULL)) { ecma_collection_free (context.property_list_p); - return value; + return ECMA_VALUE_ERROR; } - space = value; + space = ecma_make_string_value (value_str_p); } else { @@ -1497,9 +1528,10 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ /* 6. */ if (ecma_is_value_number (space)) { - ecma_number_t number = ecma_get_number_from_value (space); /* 6.a */ - int32_t num_of_spaces = ecma_number_to_int32 (number); + ecma_number_t num_of_spaces; + ecma_op_to_integer (space, &num_of_spaces); + num_of_spaces = JERRY_MIN (10, num_of_spaces); /* 6.b */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-json.inc.h index 11446b83..bc1a21e1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.inc.h @@ -21,12 +21,12 @@ #if ENABLED (JERRY_BUILTIN_JSON) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 24.3.3 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_JSON_U, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c index aea9071b..b2e89321 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-iterator-prototype.c @@ -19,10 +19,6 @@ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) -#if !ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) -#error "Map iterator builtin requires ES2015 iterator builtin" -#endif /* !ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ - #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c index 31266bd7..20f7429b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c @@ -96,7 +96,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_get (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg) /**< key argument */ { - return ecma_op_container_get (this_arg, key_arg); + return ecma_op_container_get (this_arg, key_arg, LIT_MAGIC_STRING_MAP_UL); } /* ecma_builtin_map_prototype_object_get */ /** @@ -147,7 +147,8 @@ ecma_builtin_map_prototype_object_size_getter (ecma_value_t this_arg) /**< this return ecma_op_container_size (this_arg, LIT_MAGIC_STRING_MAP_UL); } /* ecma_builtin_map_prototype_object_size_getter */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * The Map.prototype object's 'entries' routine * @@ -205,7 +206,7 @@ ecma_builtin_map_prototype_object_values (ecma_value_t this_arg) /**< this argum ECMA_PSEUDO_MAP_ITERATOR); } /* ecma_builtin_map_prototype_object_values */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h index c7d7bc7c..a8c25e14 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h @@ -29,12 +29,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_MAP, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 23.1.3.13 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_MAP_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -44,17 +44,17 @@ ROUTINE (LIT_MAGIC_STRING_FOR_EACH_UL, ecma_builtin_map_prototype_object_foreach ROUTINE (LIT_MAGIC_STRING_GET, ecma_builtin_map_prototype_object_get, 1, 1) ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_map_prototype_object_has, 1, 1) ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_map_prototype_object_set, 2, 2) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_ENTRIES, ecma_builtin_map_prototype_object_entries, 0, 0) ROUTINE (LIT_MAGIC_STRING_VALUES, ecma_builtin_map_prototype_object_values, 0, 0) ROUTINE (LIT_MAGIC_STRING_KEYS, ecma_builtin_map_prototype_object_keys, 0, 0) -ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ecma_builtin_map_prototype_object_values, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ecma_builtin_map_prototype_object_entries, 0, 0) +#endif /* ENABLED (JERRY_ES2015) */ /* ECMA-262 v6, 23.1.3.10 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SIZE, ecma_builtin_map_prototype_object_size_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c index 644753c8..33b5fb57 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c @@ -65,6 +65,18 @@ ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**< ECMA_BUILTIN_ID_MAP_PROTOTYPE); } /* ecma_builtin_map_dispatch_construct */ +/** + * 23.1.2.2 get Map [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_map_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_map_species_get */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h index 2c4ca3d2..2b09c9c0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h @@ -27,7 +27,7 @@ /* ECMA-262 v6, 23.1.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 0, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ECMA-262 v6, 23.1 */ STRING_VALUE (LIT_MAGIC_STRING_NAME, @@ -42,6 +42,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_BUILTIN_ID_MAP_PROTOTYPE, ECMA_PROPERTY_FIXED) +/* ECMA-262 v6, 23.1.2.2 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_map_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c index ebc10b1c..649f9f77 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c @@ -29,6 +29,10 @@ #include "jrt.h" #include "jrt-libc-includes.h" +#if defined (WIN32) +#include +#endif + #if ENABLED (JERRY_BUILTIN_MATH) #define ECMA_BUILTINS_INTERNAL @@ -55,21 +59,37 @@ enum ECMA_MATH_OBJECT_EXP, /* ECMA-262 v5, 15.8.2.8 */ ECMA_MATH_OBJECT_FLOOR, /* ECMA-262 v5, 15.8.2.9 */ ECMA_MATH_OBJECT_LOG, /* ECMA-262 v5, 15.8.2.10 */ -#if ENABLED (JERRY_ES2015_BUILTIN) - ECMA_MATH_OBJECT_TRUNC, /* ECMA-262 v6, 20.2.2.35 */ - ECMA_MATH_OBJECT_SIGN, /* ECMA-262 v6, 20.2.2.29 */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ ECMA_MATH_OBJECT_ROUND, /* ECMA-262 v5, 15.8.2.15 */ ECMA_MATH_OBJECT_SIN, /* ECMA-262 v5, 15.8.2.16 */ ECMA_MATH_OBJECT_SQRT, /* ECMA-262 v5, 15.8.2.17 */ ECMA_MATH_OBJECT_TAN, /* ECMA-262 v5, 15.8.2.18 */ - - ECMA_MATH_OBJECT_ATAN2, /* ECMA-262 v5, 15.8.2.5 */ - ECMA_MATH_OBJECT_POW, /* ECMA-262 v5, 15.8.2.13 */ - +#if ENABLED (JERRY_ES2015) + ECMA_MATH_OBJECT_ACOSH, /* ECMA-262 v6, 20.2.2.3 */ + ECMA_MATH_OBJECT_ASINH, /* ECMA-262 v6, 20.2.2.5 */ + ECMA_MATH_OBJECT_ATANH, /* ECMA-262 v6, 20.2.2.7 */ + ECMA_MATH_OBJECT_CBRT, /* ECMA-262 v6, 20.2.2.9 */ + ECMA_MATH_OBJECT_CLZ32, /* ECMA-262 v6, 20.2.2.11 */ + ECMA_MATH_OBJECT_COSH, /* ECMA-262 v6, 20.2.2.13 */ + ECMA_MATH_OBJECT_EXPM1, /* ECMA-262 v6, 20.2.2.15 */ + ECMA_MATH_OBJECT_FROUND, /* ECMA-262 v6, 20.2.2.17 */ + ECMA_MATH_OBJECT_LOG1P, /* ECMA-262 v6, 20.2.2.21 */ + ECMA_MATH_OBJECT_LOG10, /* ECMA-262 v6, 20.2.2.22 */ + ECMA_MATH_OBJECT_LOG2, /* ECMA-262 v6, 20.2.2.23 */ + ECMA_MATH_OBJECT_SIGN, /* ECMA-262 v6, 20.2.2.29 */ + ECMA_MATH_OBJECT_SINH, /* ECMA-262 v6, 20.2.2.31 */ + ECMA_MATH_OBJECT_TANH, /* ECMA-262 v6, 20.2.2.34 */ + ECMA_MATH_OBJECT_TRUNC, /* ECMA-262 v6, 20.2.2.35 */ +#endif /* ENABLED (JERRY_ES2015) */ + ECMA_MATH_OBJECT_ATAN2, /* ECMA-262 v5, 15.8.2.5 */ /* first routine with 2 arguments */ +#if ENABLED (JERRY_ES2015) + ECMA_MATH_OBJECT_IMUL, /* ECMA-262 v6, 20.2.2.19 */ +#endif /* ENABLED (JERRY_ES2015) */ + ECMA_MATH_OBJECT_POW, /* ECMA-262 v5, 15.8.2.13 */ /* last routine with 1 or 2 arguments*/ ECMA_MATH_OBJECT_MAX, /* ECMA-262 v5, 15.8.2.11 */ ECMA_MATH_OBJECT_MIN, /* ECMA-262 v5, 15.8.2.12 */ - +#if ENABLED (JERRY_ES2015) + ECMA_MATH_OBJECT_HYPOT, /* ECMA-262 v6, 20.2.2.18 */ +#endif /* ENABLED (JERRY_ES2015) */ ECMA_MATH_OBJECT_RANDOM, /* ECMA-262 v5, 15.8.2.14 */ }; @@ -103,6 +123,7 @@ ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */ ecma_length_t args_number) /**< number of arguments */ { ecma_number_t result_num = ecma_number_make_infinity (is_max); + bool nan_found = false; while (args_number > 0) { @@ -126,10 +147,13 @@ ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */ ecma_fast_free_value (value); } - if (JERRY_UNLIKELY (ecma_number_is_nan (arg_num))) + arg++; + args_number--; + + if (JERRY_UNLIKELY (nan_found || ecma_number_is_nan (arg_num))) { - result_num = arg_num; - break; + nan_found = true; + continue; } if (ecma_number_is_zero (arg_num) @@ -149,15 +173,88 @@ ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */ result_num = arg_num; } } + } - arg++; - args_number--; + if (JERRY_UNLIKELY (nan_found)) + { + result_num = ecma_number_make_nan (); } return ecma_make_number_value (result_num); } /* ecma_builtin_math_object_max_min */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) +/** + * The Math object's 'hypot' routine + * + * See also: + * ECMA-262 v6, 20.2.2.18 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_math_object_hypot (const ecma_value_t *arg, /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + if (args_number == 0) + { + return ecma_make_number_value (0.0); + } + + bool nan_found = false; + bool inf_found = false; + ecma_number_t result_num = 0; + + while (args_number > 0) + { + ecma_number_t arg_num; + if (ecma_is_value_number (*arg)) + { + arg_num = ecma_get_number_from_value (*arg); + } + else + { + ecma_value_t value = ecma_op_to_number (*arg); + if (ECMA_IS_VALUE_ERROR (value)) + { + return value; + } + arg_num = ecma_get_number_from_value (value); + ecma_fast_free_value (value); + } + + arg++; + args_number--; + + if (JERRY_UNLIKELY (inf_found || ecma_number_is_infinity (arg_num))) + { + inf_found = true; + continue; + } + + if (JERRY_UNLIKELY (nan_found || ecma_number_is_nan (arg_num))) + { + nan_found = true; + continue; + } + + result_num += arg_num * arg_num; + } + + if (JERRY_UNLIKELY (inf_found)) + { + return ecma_make_number_value (ecma_number_make_infinity (false)); + } + + if (JERRY_UNLIKELY (nan_found)) + { + return ecma_make_nan_value (); + } + + return ecma_make_number_value (sqrt (result_num)); +} /* ecma_builtin_math_object_hypot */ + /** * The Math object's 'trunc' routine * @@ -176,12 +273,12 @@ ecma_builtin_math_object_trunc (ecma_number_t arg) if ((arg > 0) && (arg < 1)) { - return (ecma_number_t) 0; + return (ecma_number_t) 0.0; } if ((arg < 0) && (arg > -1)) { - return (ecma_number_t) -0; + return (ecma_number_t) -0.0; } return (ecma_number_t) arg - fmod (arg, 1); @@ -210,7 +307,8 @@ ecma_builtin_math_object_sign (ecma_number_t arg) return (ecma_number_t) 1.0; } /* ecma_builtin_math_object_sign */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * The Math object's 'random' routine. @@ -341,7 +439,7 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w x = DOUBLE_TO_ECMA_NUMBER_T (log (x)); break; } -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) case ECMA_MATH_OBJECT_TRUNC: { x = ecma_builtin_math_object_trunc (x); @@ -352,12 +450,13 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w x = ecma_builtin_math_object_sign (x); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +#endif /* ENABLED (JERRY_ES2015) */ case ECMA_MATH_OBJECT_ROUND: { if (ecma_number_is_nan (x) || ecma_number_is_zero (x) - || ecma_number_is_infinity (x)) + || ecma_number_is_infinity (x) + || fmod (x, 1.0) == 0) { /* Do nothing. */ } @@ -406,27 +505,100 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w } case ECMA_MATH_OBJECT_POW: { - if (ecma_number_is_nan (y) || - (ecma_number_is_infinity (y) && (x == 1.0 || x == -1.0))) - { - /* Handle differences between ES5.1 and ISO C standards for pow. */ - x = ecma_number_make_nan (); - } - else if (ecma_number_is_zero (y)) - { - /* Handle differences between ES5.1 and ISO C standards for pow. */ - x = (ecma_number_t) 1.0; - } - else - { - x = DOUBLE_TO_ECMA_NUMBER_T (pow (x, y)); - } + x = ecma_number_pow (x, y); break; } +#if ENABLED (JERRY_ES2015) + case ECMA_MATH_OBJECT_ACOSH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (acosh (x)); + break; + } + case ECMA_MATH_OBJECT_ASINH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (asinh (x)); + break; + } + case ECMA_MATH_OBJECT_ATANH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (atanh (x)); + break; + } + case ECMA_MATH_OBJECT_CBRT: + { + x = DOUBLE_TO_ECMA_NUMBER_T (cbrt (x)); + break; + } + case ECMA_MATH_OBJECT_COSH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (cosh (x)); + break; + } + case ECMA_MATH_OBJECT_EXPM1: + { + x = DOUBLE_TO_ECMA_NUMBER_T (expm1 (x)); + break; + } + case ECMA_MATH_OBJECT_LOG1P: + { + x = DOUBLE_TO_ECMA_NUMBER_T (log1p (x)); + break; + } + case ECMA_MATH_OBJECT_LOG10: + { + x = DOUBLE_TO_ECMA_NUMBER_T (log10 (x)); + break; + } + case ECMA_MATH_OBJECT_LOG2: + { + x = DOUBLE_TO_ECMA_NUMBER_T (log2 (x)); + break; + } + case ECMA_MATH_OBJECT_SINH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (sinh (x)); + break; + } + case ECMA_MATH_OBJECT_TANH: + { + x = DOUBLE_TO_ECMA_NUMBER_T (tanh (x)); + break; + } + case ECMA_MATH_OBJECT_CLZ32: + { + uint32_t n = ecma_number_to_uint32 (x); +#if defined (__GNUC__) || defined (__clang__) + x = n ? __builtin_clz (n) : 32; +#elif defined (WIN32) + unsigned long ret; + x = _BitScanReverse (&ret, n) ? 31 - ret : 32; +#else + x = 32; + for (int i = 31; i >= 0; i--) + { + if (n >> i) + { + x = 31 - i; + break; + } + } +#endif + break; + } + case ECMA_MATH_OBJECT_FROUND: + { + x = (float) x; + break; + } + case ECMA_MATH_OBJECT_IMUL: + { + x = (int32_t) (ecma_number_to_uint32 (x) * ecma_number_to_uint32 (y)); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } - return ecma_make_number_value (x); - } + } /* if (builtin_routine_id <= ECMA_MATH_OBJECT_POW) */ if (builtin_routine_id <= ECMA_MATH_OBJECT_MIN) { @@ -435,6 +607,12 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w arguments_number); } +#if ENABLED (JERRY_ES2015) + if (builtin_routine_id == ECMA_MATH_OBJECT_HYPOT) + { + return ecma_builtin_math_object_hypot (arguments_list, arguments_number); + } +#endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (builtin_routine_id == ECMA_MATH_OBJECT_RANDOM); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-math.inc.h index f889b547..e49bf1d9 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.inc.h @@ -64,12 +64,12 @@ NUMBER_VALUE (LIT_MAGIC_STRING_SQRT2_U, ECMA_BUILTIN_NUMBER_SQRT2, ECMA_PROPERTY_FIXED) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 20.2.1.9 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_MATH_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -91,10 +91,25 @@ ROUTINE (LIT_MAGIC_STRING_ROUND, ECMA_MATH_OBJECT_ROUND, 1, 1) ROUTINE (LIT_MAGIC_STRING_SIN, ECMA_MATH_OBJECT_SIN, 1, 1) ROUTINE (LIT_MAGIC_STRING_SQRT, ECMA_MATH_OBJECT_SQRT, 1, 1) ROUTINE (LIT_MAGIC_STRING_TAN, ECMA_MATH_OBJECT_TAN, 1, 1) -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) +ROUTINE (LIT_MAGIC_STRING_ACOSH, ECMA_MATH_OBJECT_ACOSH, 1, 1) +ROUTINE (LIT_MAGIC_STRING_ASINH, ECMA_MATH_OBJECT_ASINH, 1, 1) +ROUTINE (LIT_MAGIC_STRING_ATANH, ECMA_MATH_OBJECT_ATANH, 1, 1) +ROUTINE (LIT_MAGIC_STRING_CBRT, ECMA_MATH_OBJECT_CBRT, 1, 1) +ROUTINE (LIT_MAGIC_STRING_CLZ32, ECMA_MATH_OBJECT_CLZ32, 1, 1) +ROUTINE (LIT_MAGIC_STRING_COSH, ECMA_MATH_OBJECT_COSH, 1, 1) +ROUTINE (LIT_MAGIC_STRING_EXPM1, ECMA_MATH_OBJECT_EXPM1, 1, 1) +ROUTINE (LIT_MAGIC_STRING_FROUND, ECMA_MATH_OBJECT_FROUND, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HYPOT, ECMA_MATH_OBJECT_HYPOT, NON_FIXED, 2) +ROUTINE (LIT_MAGIC_STRING_IMUL, ECMA_MATH_OBJECT_IMUL, 2, 2) +ROUTINE (LIT_MAGIC_STRING_LOG1P, ECMA_MATH_OBJECT_LOG1P, 1, 1) +ROUTINE (LIT_MAGIC_STRING_LOG10, ECMA_MATH_OBJECT_LOG10, 1, 1) +ROUTINE (LIT_MAGIC_STRING_LOG2, ECMA_MATH_OBJECT_LOG2, 1, 1) ROUTINE (LIT_MAGIC_STRING_SIGN, ECMA_MATH_OBJECT_SIGN, 1, 1) +ROUTINE (LIT_MAGIC_STRING_SINH, ECMA_MATH_OBJECT_SINH, 1, 1) +ROUTINE (LIT_MAGIC_STRING_TANH, ECMA_MATH_OBJECT_TANH, 1, 1) ROUTINE (LIT_MAGIC_STRING_TRUNC, ECMA_MATH_OBJECT_TRUNC, 1, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_BUILTIN_MATH) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c index 16dfb2e7..aaeecb67 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c @@ -249,16 +249,6 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, / const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { - - if (arguments_list_len == 0 - || ecma_number_is_nan (this_arg_number) - || ecma_number_is_infinity (this_arg_number) - || ecma_number_is_zero (this_arg_number) - || (arguments_list_len > 0 && ecma_is_value_undefined (arguments_list_p[0]))) - { - ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); - return ecma_make_string_value (ret_str_p); - } static const lit_utf8_byte_t digit_chars[36] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -267,27 +257,33 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, / 'u', 'v', 'w', 'x', 'y', 'z' }; - ecma_number_t arg_num; - ecma_value_t radix_num = ecma_get_number (arguments_list_p[0], &arg_num); - - if (!ecma_is_value_empty (radix_num)) + uint32_t radix = 10; + if (arguments_list_len > 0 && !ecma_is_value_undefined (arguments_list_p[0])) { - return radix_num; + ecma_number_t arg_num; + + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arguments_list_p[0], &arg_num))) + { + return ECMA_VALUE_ERROR; + } + + radix = ecma_number_to_uint32 (arg_num); + + if (radix < 2 || radix > 36) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Radix must be between 2 and 36.")); + } } - uint32_t radix = ecma_number_to_uint32 (arg_num); - - if (radix < 2 || radix > 36) - { - return ecma_raise_range_error (ECMA_ERR_MSG ("Radix must be between 2 and 36.")); - } - - if (radix == 10) + if (ecma_number_is_nan (this_arg_number) + || ecma_number_is_infinity (this_arg_number) + || ecma_number_is_zero (this_arg_number) + || radix == 10) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); - return ecma_make_string_value (ret_str_p); } + int buff_size = 0; bool is_number_negative = false; @@ -373,14 +369,14 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, / { for (int i = 0; i < magnitude; i++) { - this_arg_number /= (ecma_number_t) radix; + this_arg_number /= radix; } } else if (exponent < 0) { for (int i = 0; i < magnitude; i++) { - this_arg_number *= (ecma_number_t) radix; + this_arg_number *= radix; } } @@ -443,7 +439,7 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, / /* Calculate digits for fractional part. */ while (buff_index < required_digits) { - fraction *= (ecma_number_t) radix; + fraction *= radix; lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction); buff[buff_index++] = digit; @@ -596,9 +592,9 @@ ecma_builtin_number_prepare_conversion (ecma_number_t *this_num_p, /**< [out] th JERRY_ASSERT (mode < NUMBER_ROUTINE__COUNT); ecma_number_t arg_num; - arg_1 = ecma_get_number (arg_1, &arg_num); + arg_1 = ecma_op_to_integer (arg_1, &arg_num); - if (!ecma_is_value_empty (arg_1)) + if (ECMA_IS_VALUE_ERROR (arg_1)) { return arg_1; } @@ -677,6 +673,7 @@ ecma_builtin_number_prototype_object_to_fixed (ecma_number_t this_num, /**< this if (!ecma_number_is_zero (this_num)) { num_digits = ecma_number_to_binary_floating_point_number (this_num, digits, &exponent); + JERRY_ASSERT (exponent >= 0); } else { @@ -696,7 +693,7 @@ ecma_builtin_number_prototype_object_to_fixed (ecma_number_t this_num, /**< this /* 8. */ num_digits = ecma_builtin_number_prototype_helper_round (digits, - num_digits + 1, + num_digits + (lit_utf8_size_t) exponent, exponent + frac_digits, &exponent, ecma_number_is_zero (this_num)); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c index 77caf896..ad1478d8 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c @@ -93,7 +93,8 @@ ecma_builtin_number_dispatch_construct (const ecma_value_t *arguments_list_p, /* } } /* ecma_builtin_number_dispatch_construct */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) + /** * The Number object 'isFinite' routine * @@ -173,7 +174,8 @@ ecma_builtin_number_object_is_integer (ecma_value_t this_arg, /**< this argument return ECMA_VALUE_FALSE; } - ecma_number_t int_num = ecma_number_trunc (num); + ecma_number_t int_num; + ecma_op_to_integer (arg, &int_num); if (int_num != num) { @@ -219,7 +221,8 @@ ecma_builtin_number_object_is_safe_integer (ecma_value_t this_arg, /**< this arg return ECMA_VALUE_FALSE; } /* ecma_builtin_number_object_is_safe_integer */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-number.inc.h index 695f9cb9..11191355 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.7.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* ECMA-262 v5, 15.7.3.4 */ NUMBER_VALUE (LIT_MAGIC_STRING_NAN, @@ -54,6 +53,25 @@ NUMBER_VALUE (LIT_MAGIC_STRING_NEGATIVE_INFINITY_U, ECMA_BUILTIN_NUMBER_NEGATIVE_INFINITY, ECMA_PROPERTY_FIXED) +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 20.1.2.1 */ +NUMBER_VALUE (LIT_MAGIC_STRING_EPSILON_U, + ECMA_BUILTIN_NUMBER_EPSILON, + ECMA_PROPERTY_FIXED) + +/* ECMA-262 v6, 20.1.2.6 */ +NUMBER_VALUE (LIT_MAGIC_STRING_MAX_SAFE_INTEGER_U, + ECMA_BUILTIN_NUMBER_MAX_SAFE_INTEGER, + ECMA_PROPERTY_FIXED) + +/* ECMA-262 v6, 20.1.2.8 */ +NUMBER_VALUE (LIT_MAGIC_STRING_MIN_SAFE_INTEGER_U, + ECMA_BUILTIN_NUMBER_MIN_SAFE_INTEGER, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015) */ + /* Object properties: * (property name, object pointer getter) */ @@ -66,10 +84,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_IS_FINITE, ecma_builtin_number_object_is_finite, 1, 1) ROUTINE (LIT_MAGIC_STRING_IS_NAN, ecma_builtin_number_object_is_nan, 1, 1) ROUTINE (LIT_MAGIC_STRING_IS_INTEGER, ecma_builtin_number_object_is_integer, 1, 1) ROUTINE (LIT_MAGIC_STRING_IS_SAFE_INTEGER, ecma_builtin_number_object_is_safe_integer, 1, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_PARSE_FLOAT, LIT_MAGIC_STRING_PARSE_FLOAT, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_PARSE_INT, LIT_MAGIC_STRING_PARSE_INT, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c index 2898fd53..86f70e1d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c @@ -16,6 +16,7 @@ #include "ecma-alloc.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" +#include "ecma-builtin-object.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" @@ -23,6 +24,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-string-object.h" #include "ecma-try-catch-macro.h" #include "jrt.h" @@ -45,12 +47,13 @@ enum ECMA_OBJECT_PROTOTYPE_TO_STRING, ECMA_OBJECT_PROTOTYPE_VALUE_OF, ECMA_OBJECT_PROTOTYPE_TO_LOCALE_STRING, + ECMA_OBJECT_PROTOTYPE_GET_PROTO, ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF, ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY, ECMA_OBJECT_PROTOTYPE_PROPERTY_IS_ENUMERABLE, + ECMA_OBJECT_PROTOTYPE_SET_PROTO }; - #define BUILTIN_INC_HEADER_NAME "ecma-builtin-object-prototype.inc.h" #define BUILTIN_UNDERSCORED_ID object_prototype #include "ecma-builtin-internal-routines-template.inc.h" @@ -144,7 +147,23 @@ static ecma_value_t ecma_builtin_object_prototype_object_has_own_property (ecma_object_t *obj_p, /**< this argument */ ecma_string_t *prop_name_p) /**< first argument */ { - return ecma_make_boolean_value (ecma_op_object_has_own_property (obj_p, prop_name_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_property_descriptor_t prop_desc; + + ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + } + + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p)); } /* ecma_builtin_object_prototype_object_has_own_property */ /** @@ -170,7 +189,7 @@ ecma_builtin_object_prototype_object_is_prototype_of (ecma_object_t *obj_p, /**< ecma_object_t *v_obj_p = ecma_get_object_from_value (v_obj_value); - ecma_value_t ret_value = ecma_make_boolean_value (ecma_op_object_is_prototype_of (obj_p, v_obj_p)); + ecma_value_t ret_value = ecma_op_object_is_prototype_of (obj_p, v_obj_p); ecma_deref_object (v_obj_p); @@ -190,19 +209,19 @@ static ecma_value_t ecma_builtin_object_prototype_object_property_is_enumerable (ecma_object_t *obj_p, /**< this argument */ ecma_string_t *prop_name_p) /**< first argument */ { - /* 3. */ - ecma_property_t property = ecma_op_object_get_own_property (obj_p, - prop_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); - /* 4. */ - if (property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) + if (!ecma_is_value_true (status)) { - return ecma_make_boolean_value (ecma_is_property_enumerable (property)); + return status; } - return ECMA_VALUE_FALSE; + bool is_enumerable = (prop_desc.flags & ECMA_PROP_IS_ENUMERABLE); + + ecma_free_property_descriptor (&prop_desc); + + return ecma_make_boolean_value (is_enumerable); } /* ecma_builtin_object_prototype_object_property_is_enumerable */ /** @@ -260,6 +279,14 @@ ecma_builtin_object_prototype_dispatch_routine (uint16_t builtin_routine_id, /** { ret_value = ecma_builtin_object_prototype_object_is_prototype_of (obj_p, arguments_list_p[0]); } + +#if ENABLED (JERRY_ES2015) + else if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_GET_PROTO) + { + ret_value = ecma_builtin_object_object_get_prototype_of (obj_p); + } +#endif /* ENABLED (JERRY_ES2015)*/ + else { ret_value = ecma_builtin_object_prototype_object_to_locale_string (obj_p); @@ -272,6 +299,13 @@ ecma_builtin_object_prototype_dispatch_routine (uint16_t builtin_routine_id, /** JERRY_ASSERT (builtin_routine_id >= ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY); +#if ENABLED (JERRY_ES2015) + if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_SET_PROTO) + { + return ecma_builtin_object_object_set_proto (this_arg, arguments_list_p[0]); + } +#endif /* ENABLED (JERRY_ES2015)*/ + ecma_string_t *prop_name_p = ecma_op_to_prop_name (arguments_list_p[0]); if (prop_name_p == NULL) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.inc.h index 5da1290b..fccab0ff 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.inc.h @@ -27,6 +27,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_OBJECT, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +ACCESSOR_READ_WRITE (LIT_MAGIC_STRING__PROTO__, + ECMA_OBJECT_PROTOTYPE_GET_PROTO, + ECMA_OBJECT_PROTOTYPE_SET_PROTO, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ECMA_OBJECT_PROTOTYPE_TO_STRING, 0, 0) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index e7e4dc33..249ea287 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -22,8 +22,10 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-objects-general.h" #include "jrt.h" +#include "ecma-builtin-object.h" #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -39,22 +41,32 @@ enum { ECMA_OBJECT_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1, - ECMA_OBJECT_ROUTINE_DEFINE_PROPERTY, - ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR, - ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES, + ECMA_OBJECT_ROUTINE_CREATE, - ECMA_OBJECT_ROUTINE_SEAL, - ECMA_OBJECT_ROUTINE_FREEZE, - ECMA_OBJECT_ROUTINE_PREVENT_EXTENSIONS, - ECMA_OBJECT_ROUTINE_IS_SEALED, - ECMA_OBJECT_ROUTINE_IS_FROZEN, - ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE, + ECMA_OBJECT_ROUTINE_IS, + ECMA_OBJECT_ROUTINE_SET_PROTOTYPE_OF, + + /* These should be in this order. */ + ECMA_OBJECT_ROUTINE_DEFINE_PROPERTY, + ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES, + + /* These should be in this order. */ + ECMA_OBJECT_ROUTINE_ASSIGN, + ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_NAMES, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_SYMBOLS, - ECMA_OBJECT_ROUTINE_KEYS, ECMA_OBJECT_ROUTINE_GET_PROTOTYPE_OF, - ECMA_OBJECT_ROUTINE_SET_PROTOTYPE_OF, - ECMA_OBJECT_ROUTINE_ASSIGN, + ECMA_OBJECT_ROUTINE_KEYS, + + /* These should be in this order. */ + ECMA_OBJECT_ROUTINE_FREEZE, + ECMA_OBJECT_ROUTINE_PREVENT_EXTENSIONS, + ECMA_OBJECT_ROUTINE_SEAL, + + /* These should be in this order. */ + ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE, + ECMA_OBJECT_ROUTINE_IS_FROZEN, + ECMA_OBJECT_ROUTINE_IS_SEALED, }; #define BUILTIN_INC_HEADER_NAME "ecma-builtin-object.inc.h" @@ -122,122 +134,29 @@ ecma_builtin_object_dispatch_construct (const ecma_value_t *arguments_list_p, /* * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t -ecma_builtin_object_object_get_prototype_of (ecma_value_t arg) /**< routine's argument */ +ecma_value_t +ecma_builtin_object_object_get_prototype_of (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - bool was_object = ecma_is_value_object (arg); - - /* 1. */ - if (!was_object) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) { -#if ENABLED (JERRY_ES2015_BUILTIN) - arg = ecma_op_to_object (arg); - if (ECMA_IS_VALUE_ERROR (arg)) - { - return arg; - } -#else /* !ENABLED (JERRY_ES2015_BUILTIN) */ - return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + return ecma_proxy_object_get_prototype_of (obj_p); } - /* 2. */ - ecma_object_t *obj_p = ecma_get_object_from_value (arg); - jmem_cpointer_t prototype_cp = obj_p->u2.prototype_cp; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - if (prototype_cp != JMEM_CP_NULL) + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (obj_p); + + if (proto_cp != JMEM_CP_NULL) { - ecma_object_t *prototype_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, prototype_cp); - ret_value = ecma_make_object_value (prototype_p); + ecma_object_t *prototype_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); ecma_ref_object (prototype_p); - } - else - { - ret_value = ECMA_VALUE_NULL; + return ecma_make_object_value (prototype_p); } -#if ENABLED (JERRY_ES2015_BUILTIN) - if (!was_object) - { - ecma_deref_object (obj_p); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ - - return ret_value; + return ECMA_VALUE_NULL; } /* ecma_builtin_object_object_get_prototype_of */ -#if ENABLED (JERRY_ES2015_BUILTIN) -/** - * [[SetPrototypeOf]] - * - * See also: - * ES2015 9.1.2 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_set_prototype_of (ecma_value_t o_value, /**< O */ - ecma_value_t v_value) /**< V */ -{ - /* 1. */ - JERRY_ASSERT (ecma_is_value_object (o_value)); - JERRY_ASSERT (ecma_is_value_object (v_value) || ecma_is_value_null (v_value)); - - ecma_object_t *o_p = ecma_get_object_from_value (o_value); - - jmem_cpointer_t v_cp; - - if (ecma_is_value_null (v_value)) - { - v_cp = JMEM_CP_NULL; - } - else - { - ECMA_SET_NON_NULL_POINTER (v_cp, ecma_get_object_from_value (v_value)); - } - - - /* 3., 4. */ - if (v_cp == o_p->u2.prototype_cp) - { - ecma_ref_object (o_p); - return ecma_make_object_value (o_p); - } - - /* 2., 5. */ - if (!ecma_get_object_extensible (o_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("cannot set prototype.")); - } - - /* 6., 7., 8. */ - jmem_cpointer_t p_cp = v_cp; - while (p_cp != JMEM_CP_NULL) - { - ecma_object_t *p_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, p_cp); - - /* b. */ - if (p_p == o_p) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("cannot set prototype.")); - } - - /* c.i. TODO: es2015-subset profile does not support having a different - * [[GetPrototypeOf]] internal method */ - - /* c.ii. */ - p_cp = p_p->u2.prototype_cp; - } - - /* 9. */ - o_p->u2.prototype_cp = v_cp; - - /* 10. */ - ecma_ref_object (o_p); - return ecma_make_object_value (o_p); -} /* ecma_set_prototype_of */ - +#if ENABLED (JERRY_ES2015) /** * The Object object's 'setPrototypeOf' routine * @@ -247,7 +166,7 @@ ecma_set_prototype_of (ecma_value_t o_value, /**< O */ * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_object_object_set_prototype_of (ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { @@ -269,13 +188,102 @@ ecma_builtin_object_object_set_prototype_of (ecma_value_t arg1, /**< routine's f return ecma_copy_value (arg1); } - /* 6. TODO: es2015-subset profile does not support having a different - * [[SetPrototypeOf]] internal method */ + ecma_object_t *obj_p = ecma_get_object_from_value (arg1); + ecma_value_t status; - /* 5-8. */ - return ecma_set_prototype_of (arg1, arg2); + /* 5. */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + status = ecma_proxy_object_set_prototype_of (obj_p, arg2); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + status = ecma_op_ordinary_object_set_prototype_of (obj_p, arg2); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot set [[Prototype]].")); + } + + JERRY_ASSERT (ecma_is_value_true (status)); + ecma_ref_object (obj_p); + + return arg1; } /* ecma_builtin_object_object_set_prototype_of */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + +/** + * The Object object's set __proto__ routine + * + * See also: + * ECMA-262 v6, B.2.2.1.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_object_object_set_proto (ecma_value_t arg1, /**< routine's first argument */ + ecma_value_t arg2) /**< routine's second argument */ +{ + /* 1., 2. */ + if (ECMA_IS_VALUE_ERROR (ecma_op_check_object_coercible (arg1))) + { + return ECMA_VALUE_ERROR; + } + + /* 3. */ + if (!ecma_is_value_object (arg2) && !ecma_is_value_null (arg2)) + { + return ECMA_VALUE_UNDEFINED; + } + + /* 4. */ + if (!ecma_is_value_object (arg1)) + { + return ECMA_VALUE_UNDEFINED; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (arg1); + ecma_value_t status; + + /* 5. */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + status = ecma_proxy_object_set_prototype_of (obj_p, arg2); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + status = ecma_op_ordinary_object_set_prototype_of (obj_p, arg2); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot set [[Prototype]].")); + } + + JERRY_ASSERT (ecma_is_value_true (status)); + + return ECMA_VALUE_UNDEFINED; +} /* ecma_builtin_object_object_set_proto */ +#endif /* ENABLED (JERRY_ES2015) */ /** * The Object object's 'getOwnPropertyNames' routine @@ -292,7 +300,8 @@ ecma_builtin_object_object_get_own_property_names (ecma_object_t *obj_p) /**< ro return ecma_builtin_helper_object_get_properties (obj_p, ECMA_LIST_NO_OPTS); } /* ecma_builtin_object_object_get_own_property_names */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) + /** * The Object object's 'getOwnPropertySymbols' routine * @@ -305,9 +314,159 @@ ecma_builtin_object_object_get_own_property_names (ecma_object_t *obj_p) /**< ro static ecma_value_t ecma_builtin_object_object_get_own_property_symbols (ecma_object_t *obj_p) /**< routine's argument */ { - return ecma_builtin_helper_object_get_properties (obj_p, ECMA_LIST_SYMBOLS); + return ecma_builtin_helper_object_get_properties (obj_p, ECMA_LIST_SYMBOLS_ONLY); } /* ecma_builtin_object_object_get_own_property_symbols */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * SetIntegrityLevel operation + * + * See also: + * ECMA-262 v6, 7.3.14 + * + * @return ECMA_VALUE_ERROR - if the operation raised an error + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the integrity level has been set sucessfully + */ +static ecma_value_t +ecma_builtin_object_set_integrity_level (ecma_object_t *obj_p, /**< object */ + bool is_seal) /**< true - set "sealed" + * false - set "frozen" */ +{ + /* 3. */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_prevent_extensions (obj_p); + + if (!ecma_is_value_true (status)) + { + return status; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_op_ordinary_object_prevent_extensions (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 6. */ + uint32_t opts = ECMA_LIST_CONVERT_FAST_ARRAYS; +#if ENABLED (JERRY_ES2015) + opts |= ECMA_LIST_SYMBOLS; +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, opts); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + ecma_value_t *buffer_p = props_p->buffer_p; + + if (is_seal) + { + /* 8.a */ + for (uint32_t i = 0; i < props_p->item_count; i++) + { + ecma_string_t *property_name_p = ecma_get_prop_name_from_value (buffer_p[i]); + + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + continue; + } + + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; + prop_desc.flags |= ECMA_PROP_IS_THROW; + + /* 8.a.i */ + ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, + property_name_p, + &prop_desc); + + ecma_free_property_descriptor (&prop_desc); + + /* 8.a.ii */ + if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) + { + ecma_collection_free (props_p); + return define_own_prop_ret; + } + + ecma_free_value (define_own_prop_ret); + } + } + else + { + /* 9.a */ + for (uint32_t i = 0; i < props_p->item_count; i++) + { + ecma_string_t *property_name_p = ecma_get_prop_name_from_value (buffer_p[i]); + + /* 9.1 */ + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + continue; + } + + /* 9.2 */ + if ((prop_desc.flags & (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) + == (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) + { + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_WRITABLE; + } + + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; + prop_desc.flags |= ECMA_PROP_IS_THROW; + + /* 9.3 */ + ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, + property_name_p, + &prop_desc); + + ecma_free_property_descriptor (&prop_desc); + + /* 9.4 */ + if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) + { + ecma_collection_free (props_p); + return define_own_prop_ret; + } + + ecma_free_value (define_own_prop_ret); + } + + } + + ecma_collection_free (props_p); + + return ECMA_VALUE_TRUE; +} /* ecma_builtin_object_set_integrity_level */ /** * The Object object's 'seal' routine @@ -321,46 +480,19 @@ ecma_builtin_object_object_get_own_property_symbols (ecma_object_t *obj_p) /**< static ecma_value_t ecma_builtin_object_object_seal (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS); + ecma_value_t status = ecma_builtin_object_set_integrity_level (obj_p, true); - ecma_value_t *buffer_p = props_p->buffer_p; - - for (uint32_t i = 0; i < props_p->item_count; i++) + if (ECMA_IS_VALUE_ERROR (status)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); - - /* 2.a */ - ecma_property_descriptor_t prop_desc; - - if (!ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc)) - { - continue; - } - - /* 2.b */ - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; - prop_desc.flags |= ECMA_PROP_IS_THROW; - - /* 2.c */ - ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, - property_name_p, - &prop_desc); - - ecma_free_property_descriptor (&prop_desc); - - if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) - { - ecma_collection_free (props_p); - return define_own_prop_ret; - } - - ecma_free_value (define_own_prop_ret); + return status; } - ecma_collection_free (props_p); - - /* 3. */ - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Object cannot be sealed.")); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /* 4. */ ecma_ref_object (obj_p); @@ -379,53 +511,19 @@ ecma_builtin_object_object_seal (ecma_object_t *obj_p) /**< routine's argument * static ecma_value_t ecma_builtin_object_object_freeze (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS); + ecma_value_t status = ecma_builtin_object_set_integrity_level (obj_p, false); - ecma_value_t *buffer_p = props_p->buffer_p; - - for (uint32_t i = 0; i < props_p->item_count; i++) + if (ECMA_IS_VALUE_ERROR (status)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); - - /* 2.a */ - ecma_property_descriptor_t prop_desc; - - if (!ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc)) - { - continue; - } - - /* 2.b */ - if ((prop_desc.flags & (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) - == (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) - { - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_WRITABLE; - } - - /* 2.c */ - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; - prop_desc.flags |= ECMA_PROP_IS_THROW; - - /* 2.d */ - ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, - property_name_p, - &prop_desc); - - ecma_free_property_descriptor (&prop_desc); - - if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) - { - ecma_collection_free (props_p); - return define_own_prop_ret; - } - - ecma_free_value (define_own_prop_ret); + return status; } - ecma_collection_free (props_p); - - /* 3. */ - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Object cannot be frozen.")); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /* 4. */ ecma_ref_object (obj_p); @@ -441,10 +539,33 @@ ecma_builtin_object_object_freeze (ecma_object_t *obj_p) /**< routine's argument * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_object_object_prevent_extensions (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_prevent_extensions (obj_p); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot set [[Extensible]] property of the object.")); + } + + JERRY_ASSERT (ecma_is_value_true (status)); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_op_ordinary_object_prevent_extensions (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_ref_object (obj_p); return ecma_make_object_value (obj_p); @@ -461,13 +582,34 @@ ecma_builtin_object_object_prevent_extensions (ecma_object_t *obj_p) /**< routin * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine's argument */ - int mode) /**< routine mode */ +ecma_builtin_object_test_integrity_level (ecma_object_t *obj_p, /**< routine's argument */ + int mode) /**< routine mode */ { JERRY_ASSERT (mode == ECMA_OBJECT_ROUTINE_IS_FROZEN || mode == ECMA_OBJECT_ROUTINE_IS_SEALED); /* 3. */ - if (ecma_get_object_extensible (obj_p)) + bool is_extensible; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_is_extensible (obj_p); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + is_extensible = ecma_is_value_true (status); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + is_extensible = ecma_op_ordinary_object_is_extensible (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (is_extensible) { return ECMA_VALUE_FALSE; } @@ -478,6 +620,13 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' /* 2. */ ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_NO_OPTS); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = props_p->buffer_p; for (uint32_t i = 0; i < props_p->item_count; i++) @@ -485,22 +634,32 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); /* 2.a */ - ecma_property_t property = ecma_op_object_get_own_property (obj_p, - property_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); - /* 2.b for isFrozen */ - if (mode == ECMA_OBJECT_ROUTINE_IS_FROZEN - && ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR - && ecma_is_property_writable (property)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) { - ret_value = ECMA_VALUE_FALSE; + ret_value = status; break; } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (ecma_is_value_false (status)) + { + continue; + } + + bool is_writable_data = ((prop_desc.flags & (ECMA_PROP_IS_VALUE_DEFINED | ECMA_PROP_IS_WRITABLE)) + == (ECMA_PROP_IS_VALUE_DEFINED | ECMA_PROP_IS_WRITABLE)); + bool is_configurable = (prop_desc.flags & ECMA_PROP_IS_CONFIGURABLE); + + ecma_free_property_descriptor (&prop_desc); + + /* 2.b for isFrozen */ /* 2.b for isSealed, 2.c for isFrozen */ - if (ecma_is_property_configurable (property)) + if ((mode == ECMA_OBJECT_ROUTINE_IS_FROZEN && is_writable_data) + || is_configurable) { ret_value = ECMA_VALUE_FALSE; break; @@ -510,7 +669,7 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' ecma_collection_free (props_p); return ret_value; -} /* ecma_builtin_object_frozen_or_sealed_helper */ +} /* ecma_builtin_object_test_integrity_level */ /** * The Object object's 'isExtensible' routine @@ -521,10 +680,17 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_object_object_is_extensible (ecma_object_t *obj_p) /**< routine's argument */ { - return ecma_make_boolean_value (ecma_get_object_extensible (obj_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_is_extensible (obj_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_is_extensible (obj_p)); } /* ecma_builtin_object_object_is_extensible */ /** @@ -551,14 +717,23 @@ ecma_builtin_object_object_keys (ecma_object_t *obj_p) /**< routine's argument * * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_object_object_get_own_property_descriptor (ecma_object_t *obj_p, /**< routine's first argument */ ecma_string_t *name_str_p) /**< routine's second argument */ { /* 3. */ ecma_property_descriptor_t prop_desc; - if (ecma_op_object_get_own_property_descriptor (obj_p, name_str_p, &prop_desc)) + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, name_str_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (status)) { /* 4. */ ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc); @@ -598,6 +773,14 @@ ecma_builtin_object_object_define_properties (ecma_object_t *obj_p, /**< routine | ECMA_LIST_ENUMERABLE); ecma_value_t ret_value = ECMA_VALUE_ERROR; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (prop_names_p == NULL) + { + ecma_deref_object (props_p); + return ret_value; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = prop_names_p->buffer_p; /* 4. */ @@ -724,7 +907,7 @@ ecma_builtin_object_object_create (ecma_value_t arg1, /**< routine's first argum * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t +ecma_value_t ecma_builtin_object_object_define_property (ecma_object_t *obj_p, /**< routine's first argument */ ecma_string_t *name_str_p, /**< routine's second argument */ ecma_value_t arg3) /**< routine's third argument */ @@ -758,8 +941,8 @@ ecma_builtin_object_object_define_property (ecma_object_t *obj_p, /**< routine's return ecma_make_object_value (obj_p); } /* ecma_builtin_object_object_define_property */ +#if ENABLED (JERRY_ES2015) -#if ENABLED (JERRY_ES2015_BUILTIN) /** * The Object object's 'assign' routine * @@ -770,31 +953,14 @@ ecma_builtin_object_object_define_property (ecma_object_t *obj_p, /**< routine's * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_object_object_assign (const ecma_value_t arguments_list_p[], /**< arguments list */ +ecma_builtin_object_object_assign (ecma_object_t *target_p, /**< target object */ + const ecma_value_t arguments_list_p[], /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { - ecma_value_t target = arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED; - - /* 1. */ - ecma_value_t to_value = ecma_op_to_object (target); - - if (ECMA_IS_VALUE_ERROR (to_value)) - { - return to_value; - } - - ecma_object_t *to_obj_p = ecma_get_object_from_value (to_value); - - /* 2. */ - if (arguments_list_len == 1) - { - return to_value; - } - ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 4-5. */ - for (uint32_t i = 1; i < arguments_list_len && ecma_is_value_empty (ret_value); i++) + for (uint32_t i = 0; i < arguments_list_len && ecma_is_value_empty (ret_value); i++) { ecma_value_t next_source = arguments_list_p[i]; @@ -812,20 +978,36 @@ ecma_builtin_object_object_assign (const ecma_value_t arguments_list_p[], /**< a ecma_object_t *from_obj_p = ecma_get_object_from_value (from_value); /* 5.b.iii */ - /* TODO: extends this collection if symbols will be supported */ ecma_collection_t *props_p = ecma_op_object_get_property_names (from_obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS - | ECMA_LIST_ENUMERABLE); + | ECMA_LIST_ENUMERABLE + | ECMA_LIST_SYMBOLS); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + ecma_deref_object (from_obj_p); + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_value_t *buffer_p = props_p->buffer_p; for (uint32_t j = 0; (j < props_p->item_count) && ecma_is_value_empty (ret_value); j++) { - ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[j]); + ecma_string_t *property_name_p = ecma_get_prop_name_from_value (buffer_p[j]); /* 5.c.i-ii */ ecma_property_descriptor_t prop_desc; + ecma_value_t desc_status = ecma_op_object_get_own_property_descriptor (from_obj_p, property_name_p, &prop_desc); - if (!ecma_op_object_get_own_property_descriptor (from_obj_p, property_name_p, &prop_desc)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (desc_status)) + { + ret_value = desc_status; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (desc_status)) { continue; } @@ -846,7 +1028,7 @@ ecma_builtin_object_object_assign (const ecma_value_t arguments_list_p[], /**< a else { /* 5.c.iii.3 */ - ecma_value_t status = ecma_op_object_put (to_obj_p, property_name_p, prop_value, true); + ecma_value_t status = ecma_op_object_put (target_p, property_name_p, prop_value, true); /* 5.c.iii.4 */ if (ECMA_IS_VALUE_ERROR (status)) @@ -867,13 +1049,30 @@ ecma_builtin_object_object_assign (const ecma_value_t arguments_list_p[], /**< a /* 6. */ if (ecma_is_value_empty (ret_value)) { - return to_value; + ecma_ref_object (target_p); + return ecma_make_object_value (target_p); } - ecma_deref_object (to_obj_p); return ret_value; } /* ecma_builtin_object_object_assign */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + +/** + * The Object object's 'is' routine + * + * See also: + * ECMA-262 v6, 19.1.2.10 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_object_object_is (ecma_value_t arg1, /**< routine's first argument */ + ecma_value_t arg2) /**< routine's second argument */ +{ + return ecma_op_same_value (arg1, arg2) ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE; +} /* ecma_builtin_object_object_is */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Dispatcher of the built-in's routines @@ -903,103 +1102,184 @@ ecma_builtin_object_dispatch_routine (uint16_t builtin_routine_id, /**< built-in { return ecma_builtin_object_object_create (arg1, arg2); } - case ECMA_OBJECT_ROUTINE_GET_PROTOTYPE_OF: - { - return ecma_builtin_object_object_get_prototype_of (arg1); - } -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) case ECMA_OBJECT_ROUTINE_SET_PROTOTYPE_OF: { return ecma_builtin_object_object_set_prototype_of (arg1, arg2); } - case ECMA_OBJECT_ROUTINE_ASSIGN: + case ECMA_OBJECT_ROUTINE_IS: { - return ecma_builtin_object_object_assign (arguments_list_p, arguments_number); + return ecma_builtin_object_object_is (arg1, arg2); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { break; } } + ecma_object_t *obj_p; +#if !ENABLED (JERRY_ES2015) if (!ecma_is_value_object (arg1)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); } +#endif /* !ENABLED (JERRY_ES2015) */ - ecma_object_t *obj_p = ecma_get_object_from_value (arg1); - - if (builtin_routine_id <= ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR) + if (builtin_routine_id <= ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES) { - ecma_string_t *prop_name_p = ecma_op_to_prop_name (arg2); - - if (prop_name_p == NULL) +#if ENABLED (JERRY_ES2015) + if (!ecma_is_value_object (arg1)) { - return ECMA_VALUE_ERROR; + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); } +#endif /* ENABLED (JERRY_ES2015) */ - ecma_value_t ret_value; + obj_p = ecma_get_object_from_value (arg1); if (builtin_routine_id == ECMA_OBJECT_ROUTINE_DEFINE_PROPERTY) { - ret_value = ecma_builtin_object_object_define_property (obj_p, prop_name_p, arguments_list_p[2]); - } - else - { - JERRY_ASSERT (builtin_routine_id == ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR); - ret_value = ecma_builtin_object_object_get_own_property_descriptor (obj_p, prop_name_p); + ecma_string_t *prop_name_p = ecma_op_to_prop_name (arg2); + + if (prop_name_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ecma_builtin_object_object_define_property (obj_p, prop_name_p, arguments_list_p[2]); + + ecma_deref_ecma_string (prop_name_p); + return result; } - ecma_deref_ecma_string (prop_name_p); - return ret_value; + JERRY_ASSERT (builtin_routine_id == ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES); + return ecma_builtin_object_object_define_properties (obj_p, arg2); } - - switch (builtin_routine_id) + else if (builtin_routine_id <= ECMA_OBJECT_ROUTINE_KEYS) { - case ECMA_OBJECT_ROUTINE_SEAL: +#if ENABLED (JERRY_ES2015) + ecma_value_t object = ecma_op_to_object (arg1); + if (ECMA_IS_VALUE_ERROR (object)) { - return ecma_builtin_object_object_seal (obj_p); + return object; } - case ECMA_OBJECT_ROUTINE_FREEZE: + + obj_p = ecma_get_object_from_value (object); +#else /* !ENABLED (JERRY_ES2015) */ + obj_p = ecma_get_object_from_value (arg1); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t result; + switch (builtin_routine_id) { - return ecma_builtin_object_object_freeze (obj_p); + case ECMA_OBJECT_ROUTINE_GET_PROTOTYPE_OF: + { + result = ecma_builtin_object_object_get_prototype_of (obj_p); + break; + } + case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_NAMES: + { + result = ecma_builtin_object_object_get_own_property_names (obj_p); + break; + } +#if ENABLED (JERRY_ES2015) + case ECMA_OBJECT_ROUTINE_ASSIGN: + { + result = ecma_builtin_object_object_assign (obj_p, arguments_list_p + 1, arguments_number - 1); + break; + } + case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_SYMBOLS: + { + result = ecma_builtin_object_object_get_own_property_symbols (obj_p); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + case ECMA_OBJECT_ROUTINE_KEYS: + { + result = ecma_builtin_object_object_keys (obj_p); + break; + } + case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR: + { + ecma_string_t *prop_name_p = ecma_op_to_prop_name (arg2); + + if (prop_name_p == NULL) + { + result = ECMA_VALUE_ERROR; + break; + } + + result = ecma_builtin_object_object_get_own_property_descriptor (obj_p, prop_name_p); + ecma_deref_ecma_string (prop_name_p); + break; + } + default: + { + JERRY_UNREACHABLE (); + } } - case ECMA_OBJECT_ROUTINE_PREVENT_EXTENSIONS: + +#if ENABLED (JERRY_ES2015) + ecma_deref_object (obj_p); +#endif /* ENABLED (JERRY_ES2015) */ + return result; + } + else if (builtin_routine_id <= ECMA_OBJECT_ROUTINE_SEAL) + { +#if ENABLED (JERRY_ES2015) + if (!ecma_is_value_object (arg1)) { - return ecma_builtin_object_object_prevent_extensions (obj_p); + return ecma_copy_value (arg1); } - case ECMA_OBJECT_ROUTINE_IS_SEALED: - case ECMA_OBJECT_ROUTINE_IS_FROZEN: +#endif /* ENABLED (JERRY_ES2015) */ + + obj_p = ecma_get_object_from_value (arg1); + switch (builtin_routine_id) { - return ecma_builtin_object_frozen_or_sealed_helper (obj_p, - builtin_routine_id); + case ECMA_OBJECT_ROUTINE_SEAL: + { + return ecma_builtin_object_object_seal (obj_p); + } + case ECMA_OBJECT_ROUTINE_FREEZE: + { + return ecma_builtin_object_object_freeze (obj_p); + } + case ECMA_OBJECT_ROUTINE_PREVENT_EXTENSIONS: + { + return ecma_builtin_object_object_prevent_extensions (obj_p); + } + default: + { + JERRY_UNREACHABLE (); + } } - case ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE: + } + else + { + JERRY_ASSERT (builtin_routine_id <= ECMA_OBJECT_ROUTINE_IS_SEALED); +#if ENABLED (JERRY_ES2015) + if (!ecma_is_value_object (arg1)) { - return ecma_builtin_object_object_is_extensible (obj_p); + return ecma_make_boolean_value (builtin_routine_id != ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE); } - case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_NAMES: +#endif /* ENABLED (JERRY_ES2015) */ + + obj_p = ecma_get_object_from_value (arg1); + switch (builtin_routine_id) { - return ecma_builtin_object_object_get_own_property_names (obj_p); - } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_SYMBOLS: - { - return ecma_builtin_object_object_get_own_property_symbols (obj_p); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - case ECMA_OBJECT_ROUTINE_KEYS: - { - return ecma_builtin_object_object_keys (obj_p); - } - case ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES: - { - return ecma_builtin_object_object_define_properties (obj_p, arg2); - } - default: - { - JERRY_UNREACHABLE (); + case ECMA_OBJECT_ROUTINE_IS_SEALED: + case ECMA_OBJECT_ROUTINE_IS_FROZEN: + { + return ecma_builtin_object_test_integrity_level (obj_p, builtin_routine_id); + } + case ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE: + { + return ecma_builtin_object_object_is_extensible (obj_p); + } + default: + { + JERRY_UNREACHABLE (); + } } } } /* ecma_builtin_object_dispatch_routine */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.h b/jerry-core/ecma/builtin-objects/ecma-builtin-object.h new file mode 100644 index 00000000..489e9831 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.h @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ECMA_BUILTIN_OBJECT_H +#define ECMA_BUILTIN_OBJECT_H + +ecma_value_t ecma_builtin_object_object_get_prototype_of (ecma_object_t *obj_p); + +ecma_value_t ecma_builtin_object_object_set_prototype_of (ecma_value_t arg1, + ecma_value_t arg2); + +ecma_value_t ecma_builtin_object_object_set_proto (ecma_value_t arg1, + ecma_value_t arg2); + +ecma_value_t ecma_builtin_object_object_prevent_extensions (ecma_object_t *obj_p); + +ecma_value_t ecma_builtin_object_object_is_extensible (ecma_object_t *obj_p); + +ecma_value_t ecma_builtin_object_object_get_own_property_descriptor (ecma_object_t *obj_p, + ecma_string_t *name_str_p); +ecma_value_t ecma_builtin_object_object_define_property (ecma_object_t *obj_p, + ecma_string_t *name_str_p, + ecma_value_t arg3); + +#endif /* !ECMA_BUILTIN_OBJECT_H */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h index 457a2823..fde4c7ec 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h @@ -22,10 +22,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.2.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ @@ -39,9 +38,9 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL, ECMA_OBJECT_ROUTINE_GET_PROTOTYPE_OF, 1, 1) ROUTINE (LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_NAMES, 1, 1) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_SYMBOLS, 1, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ROUTINE (LIT_MAGIC_STRING_SEAL, ECMA_OBJECT_ROUTINE_SEAL, 1, 1) ROUTINE (LIT_MAGIC_STRING_FREEZE, ECMA_OBJECT_ROUTINE_FREEZE, 1, 1) ROUTINE (LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL, ECMA_OBJECT_ROUTINE_PREVENT_EXTENSIONS, 1, 1) @@ -54,9 +53,10 @@ ROUTINE (LIT_MAGIC_STRING_CREATE, ECMA_OBJECT_ROUTINE_CREATE, 2, 2) ROUTINE (LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL, ECMA_OBJECT_ROUTINE_DEFINE_PROPERTIES, 2, 2) ROUTINE (LIT_MAGIC_STRING_DEFINE_PROPERTY_UL, ECMA_OBJECT_ROUTINE_DEFINE_PROPERTY, 3, 3) -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_SET_PROTOTYPE_OF_UL, ECMA_OBJECT_ROUTINE_SET_PROTOTYPE_OF, 2, 2) ROUTINE (LIT_MAGIC_STRING_ASSIGN, ECMA_OBJECT_ROUTINE_ASSIGN, NON_FIXED, 2) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +ROUTINE (LIT_MAGIC_STRING_IS, ECMA_OBJECT_ROUTINE_IS, 2, 2) +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h index 872fab5d..555caf64 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h @@ -24,16 +24,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_PROMISE, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, - 1, - ECMA_PROPERTY_FLAG_WRITABLE) - -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 25.4.5.4 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_PROMISE_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ROUTINE (LIT_MAGIC_STRING_THEN, ecma_builtin_promise_prototype_then, 2, 2) ROUTINE (LIT_MAGIC_STRING_CATCH, ecma_builtin_promise_prototype_catch, 1, 1) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 5d0bf04a..ca9e5675 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -19,6 +19,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-iterator-object.h" #include "ecma-number-object.h" #include "ecma-promise-object.h" #include "jcontext.h" @@ -42,78 +43,6 @@ * @{ */ -/** - * The common function for 'reject' and 'resolve'. - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ - ecma_value_t argument, /**< argument for reject or resolve */ - bool is_resolve) /**< whether it is for resolve routine */ -{ - if (!ecma_is_value_object (this_arg)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); - } - - uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg)); - - if (builtin_id != ECMA_BUILTIN_ID_PROMISE) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor.")); - } - - if (is_resolve - && ecma_is_value_object (argument) - && ecma_is_promise (ecma_get_object_from_value (argument))) - { - return ecma_copy_value (argument); - } - - - ecma_value_t capability = ecma_promise_new_capability (); - - if (ECMA_IS_VALUE_ERROR (capability)) - { - return capability; - } - - ecma_string_t *property_str_p; - - if (is_resolve) - { - property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); - } - else - { - property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); - } - - ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); - - ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), - ECMA_VALUE_UNDEFINED, - &argument, - 1); - - ecma_free_value (func); - - if (ECMA_IS_VALUE_ERROR (call_ret)) - { - return call_ret; - } - - ecma_free_value (call_ret); - - ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); - ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); - ecma_free_value (capability); - - return promise_new; -} /* ecma_builtin_promise_reject_or_resolve */ - /** * Reject the promise if the value is error. * @@ -124,12 +53,17 @@ ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argum * Returned value must be freed with ecma_free_value. */ inline static ecma_value_t -ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */ +ecma_builtin_promise_reject_abrupt (ecma_value_t value, /**< value */ + ecma_value_t capability) /**< capability */ { - ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array.")); - ecma_value_t reason = JERRY_CONTEXT (error_value); - ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); + if (!ECMA_IS_VALUE_ERROR (value)) + { + return value; + } + + ecma_value_t reason = jcontext_take_exception (); + ecma_value_t reject = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability), + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), ECMA_VALUE_UNDEFINED, @@ -145,10 +79,8 @@ ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject descrip ecma_free_value (call_ret); - ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); - ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); - - return promise_new; + return ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability), + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); } /* ecma_builtin_promise_reject_abrupt */ /** @@ -164,7 +96,7 @@ static ecma_value_t ecma_builtin_promise_reject (ecma_value_t this_arg, /**< 'this' argument */ ecma_value_t reason) /**< the reason for reject */ { - return ecma_builtin_promise_reject_or_resolve (this_arg, reason, false); + return ecma_promise_reject_or_resolve (this_arg, reason, false); } /* ecma_builtin_promise_reject */ /** @@ -180,7 +112,7 @@ static ecma_value_t ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */ ecma_value_t argument) /**< the argument for resolve */ { - return ecma_builtin_promise_reject_or_resolve (this_arg, argument, true); + return ecma_promise_reject_or_resolve (this_arg, argument, true); } /* ecma_builtin_promise_resolve */ /** @@ -193,84 +125,80 @@ ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */ * Returned value must be freed with ecma_free_value. */ inline static ecma_value_t -ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */ - ecma_value_t capability, /**< PromiseCapability record */ - ecma_value_t ctor) /**< the caller of Promise.race */ +ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for race */ + ecma_value_t capability, /**< PromiseCapability record */ + ecma_value_t ctor, /**< Constructor value */ + bool *done_p) /**< [out] iteratorRecord[[done]] */ { - JERRY_ASSERT (ecma_is_value_object (capability) - && ecma_is_value_object (array) - && ecma_is_value_object (ctor)); - JERRY_ASSERT (ecma_get_object_builtin_id (ecma_get_object_from_value (ctor)) == ECMA_BUILTIN_ID_PROMISE); - JERRY_ASSERT (ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_is_value_object (iterator) + && ecma_is_value_object (capability)); - ecma_value_t ret = ECMA_VALUE_EMPTY; - ecma_object_t *array_p = ecma_get_object_from_value (array); - ecma_extended_object_t *ext_array_p = (ecma_extended_object_t *) array_p; - - ecma_length_t len = ext_array_p->u.array.length; - - ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); - ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); - - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), - resolve_str_p); - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), - reject_str_p); - - for (ecma_length_t index = 0; index <= len; index++) + ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); + /* 1. */ + while (true) { - /* b-d. */ - if (index == len) + /* a. */ + ecma_value_t next = ecma_op_iterator_step (iterator); + /* b, c. */ + if (ECMA_IS_VALUE_ERROR (next)) { - ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); - break; + *done_p = true; + return next; + } + + /* d. */ + if (ecma_is_value_false (next)) + { + /* i. */ + *done_p = true; + /* ii. */ + return ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); } /* e. */ - ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p); - ecma_deref_ecma_string (index_to_str_p); + ecma_value_t next_val = ecma_op_iterator_value (next); + ecma_free_value (next); - /* f. */ - if (ECMA_IS_VALUE_ERROR (array_item)) + /* f, g. */ + if (ECMA_IS_VALUE_ERROR (next_val)) { - ret = array_item; - break; + *done_p = true; + return next_val; } /* h. */ - ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); - ecma_free_value (array_item); + ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_val, 1); + ecma_free_value (next_val); /* i. */ if (ECMA_IS_VALUE_ERROR (next_promise)) { - ret = next_promise; - break; + return next_promise; } /* j. */ - ecma_value_t then_result = ecma_promise_then (next_promise, resolve, reject); + ecma_value_t args[2]; + args[0] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2); ecma_free_value (next_promise); - /* k. */ - if (ECMA_IS_VALUE_ERROR (then_result)) + for (uint8_t i = 0; i < 2; i++) { - ret = then_result; - break; + ecma_free_value (args[i]); } - ecma_free_value (then_result); + /* k. */ + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_free_value (result); } - ecma_free_value (reject); - ecma_free_value (resolve); - - JERRY_ASSERT (!ecma_is_value_empty (ret)); - - return ret; -} /* ecma_builtin_promise_do_race */ + JERRY_UNREACHABLE (); +} /* ecma_builtin_promise_perform_race */ /** * Helper function for increase or decrease the remaining count. @@ -300,7 +228,6 @@ ecma_builtin_promise_remaining_inc_or_dec (ecma_value_t remaining, /**< the rema { current--; } - ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current); return current; @@ -323,7 +250,6 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function JERRY_UNUSED (this); JERRY_UNUSED (argc); - ecma_value_t ret = ECMA_VALUE_UNDEFINED; /* 1. */ ecma_object_t *function_p = ecma_get_object_from_value (function); ecma_string_t *already_called_str_p; @@ -335,8 +261,7 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function /* 2. */ if (ecma_is_value_true (already_called)) { - ecma_fast_free_value (already_called); - return ret; + return ECMA_VALUE_UNDEFINED; } /* 3. */ @@ -352,39 +277,35 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function /* 4-7. */ ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p); - ecma_value_t value_array = ecma_op_object_get (function_p, str_value_p); + ecma_value_t values_array = ecma_op_object_get (function_p, str_value_p); ecma_value_t capability = ecma_op_object_get (function_p, str_capability_p); ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p); JERRY_ASSERT (ecma_is_value_integer_number (index_val)); /* 8. */ - ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 ((uint32_t) ecma_get_integer_from_value (index_val)); - - ecma_op_object_put (ecma_get_object_from_value (value_array), - index_to_str_p, - argv[0], - false); - ecma_deref_ecma_string (index_to_str_p); + ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (values_array), + (uint32_t) ecma_get_integer_from_value (index_val), + argv[0], + false); /* 9-10. */ + ecma_value_t ret = ECMA_VALUE_UNDEFINED; if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) { - ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); - + ecma_value_t resolve = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability), + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); ret = ecma_op_function_call (ecma_get_object_from_value (resolve), ECMA_VALUE_UNDEFINED, - &value_array, + &values_array, 1); ecma_free_value (resolve); } ecma_free_value (remaining); ecma_free_value (capability); - ecma_free_value (value_array); - ecma_fast_free_value (index_val); - ecma_fast_free_value (already_called); + ecma_free_value (values_array); + ecma_free_value (index_val); return ret; } /* ecma_builtin_promise_all_handler */ @@ -399,25 +320,25 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function * Returned value must be freed with ecma_free_value. */ inline static ecma_value_t -ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ - ecma_value_t capability, /**< PromiseCapability record */ - ecma_value_t ctor) /**< the caller of Promise.race */ +ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */ + ecma_value_t ctor, /**< the caller of Promise.race */ + ecma_value_t capability, /**< PromiseCapability record */ + bool *done_p) /**< [out] iteratorRecord[[done]] */ { - JERRY_ASSERT (ecma_is_value_object (capability) - && ecma_is_value_object (array) - && ecma_is_value_object (ctor)); - JERRY_ASSERT (ecma_get_object_builtin_id (ecma_get_object_from_value (ctor)) == ECMA_BUILTIN_ID_PROMISE); - JERRY_ASSERT (ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY); + /* 1. - 2. */ + JERRY_ASSERT (ecma_is_value_object (capability) && ecma_is_constructor (ctor)); - ecma_value_t ret = ECMA_VALUE_EMPTY; - ecma_object_t *array_p = ecma_get_object_from_value (array); - ecma_extended_object_t *ext_array_p = (ecma_extended_object_t *) array_p; + /* 3. */ + ecma_object_t *values_array_obj_p = ecma_op_new_fast_array_object (0); + ecma_value_t values_array = ecma_make_object_value (values_array_obj_p); + /* 4. */ + ecma_value_t remaining = ecma_op_create_number_object (ecma_make_integer_value (1)); + /* 5. */ + uint32_t idx = 0; - ecma_length_t len = ext_array_p->u.array.length; + ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); - ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); - ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); ecma_string_t *already_called_str_p; already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED); ecma_string_t *index_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX); @@ -425,81 +346,75 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *remaining_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT); - ecma_value_t undefined_val = ECMA_VALUE_UNDEFINED; - /* String '1' indicates [[Resolve]] and '2' indicates [[Reject]]. */ - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), - resolve_str_p); - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), - reject_str_p); - /* 3. */ - ecma_value_t result_array_length_val = ecma_make_uint32_value (0); - ecma_value_t value_array = ecma_op_create_array_object (&result_array_length_val, 1, true); - ecma_free_value (result_array_length_val); - /* 4. */ - ecma_value_t remaining = ecma_op_create_number_object (ecma_make_integer_value (1)); - /* 5. */ - ecma_length_t index = 0; - - /* 6 */ + /* 6. */ while (true) { - JERRY_ASSERT (index <= len); - /* d. */ - if (index == len) + /* a. */ + ecma_value_t next = ecma_op_iterator_step (iterator); + /* b. - c. */ + if (ECMA_IS_VALUE_ERROR (next)) { - /* ii. */ + *done_p = true; + break; + } + + /* d. */ + if (ecma_is_value_false (next)) + { + /* i. */ + *done_p = true; + + /* ii. - iii. */ if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) { - /* iii. */ - ecma_value_t resolve_ret = ecma_op_function_call (ecma_get_object_from_value (resolve), - ECMA_VALUE_UNDEFINED, - &value_array, - 1); + /* 2. */ + ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + ecma_value_t resolve_result = ecma_op_function_call (ecma_get_object_from_value (resolve), + ECMA_VALUE_UNDEFINED, + &values_array, + 1); + ecma_free_value (resolve); - if (ECMA_IS_VALUE_ERROR (resolve_ret)) + /* 3. */ + if (ECMA_IS_VALUE_ERROR (resolve_result)) { - ret = resolve_ret; break; } + + ecma_free_value (resolve_result); } /* iv. */ - ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); + ret_value = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); break; } - /* e. h. */ - ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p); + /* e. */ + ecma_value_t next_value = ecma_op_iterator_value (next); + ecma_free_value (next); - if (ECMA_IS_VALUE_ERROR (array_item)) + /* f. - g. */ + if (ECMA_IS_VALUE_ERROR (next_value)) { - ecma_deref_ecma_string (index_to_str_p); - ret = array_item; + *done_p = true; break; } - ecma_value_t put_ret = ecma_builtin_helper_def_prop (ecma_get_object_from_value (value_array), - index_to_str_p, - undefined_val, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - ecma_deref_ecma_string (index_to_str_p); - - if (ECMA_IS_VALUE_ERROR (put_ret)) - { - ecma_free_value (array_item); - ret = put_ret; - break; - } + /* h. */ + ecma_builtin_helper_def_prop_by_index (values_array_obj_p, + idx, + ECMA_VALUE_UNDEFINED, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); /* i. */ - ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); - ecma_free_value (array_item); + ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_value, 1); + ecma_free_value (next_value); /* j. */ if (ECMA_IS_VALUE_ERROR (next_promise)) { - ret = next_promise; break; } @@ -512,15 +427,19 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ ECMA_VALUE_FALSE, false); /* m. */ + ecma_value_t idx_value = ecma_make_uint32_value (idx); ecma_op_object_put (res_ele_p, index_str_p, - ecma_make_uint32_value (index), + idx_value, false); + ecma_free_value (idx_value); + /* n. */ ecma_op_object_put (res_ele_p, value_str_p, - value_array, + values_array, false); + /* o. */ ecma_op_object_put (res_ele_p, capability_str_p, @@ -534,33 +453,35 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ /* q. */ ecma_builtin_promise_remaining_inc_or_dec (remaining, true); + /* r. */ - ecma_value_t then_result = ecma_promise_then (next_promise, - ecma_make_object_value (res_ele_p), - reject); - ecma_deref_object (res_ele_p); + ecma_value_t args[2]; + args[0] = ecma_make_object_value (res_ele_p); + args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2); ecma_free_value (next_promise); - /* s. */ - if (ECMA_IS_VALUE_ERROR (then_result)) + for (uint8_t i = 0; i < 2; i++) + { + ecma_free_value (args[i]); + } + + /* s. */ + if (ECMA_IS_VALUE_ERROR (result)) { - ret = then_result; break; } - ecma_free_value (then_result); - index ++; + ecma_free_value (result); + + /* t. */ + idx++; } - ecma_free_value (reject); - ecma_free_value (resolve); ecma_free_value (remaining); - ecma_free_value (value_array); - - JERRY_ASSERT (!ecma_is_value_empty (ret)); - - return ret; -} /* ecma_builtin_promise_do_all */ + ecma_deref_object (values_array_obj_p); + return ret_value; +} /* ecma_builtin_promise_perform_all */ /** * The common function for both Promise.race and Promise.all. @@ -570,7 +491,7 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ */ static ecma_value_t ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ - ecma_value_t array, /**< the items to be resolved */ + ecma_value_t iterable, /**< the items to be resolved */ bool is_race) /**< indicates whether it is race function */ { if (!ecma_is_value_object (this_arg)) @@ -578,44 +499,69 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); } - uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg)); + ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); + ecma_value_t species_symbol = ecma_op_object_get_by_magic_id (this_obj_p, + LIT_MAGIC_STRING_SYMBOL); - if (builtin_id != ECMA_BUILTIN_ID_PROMISE) + if (ECMA_IS_VALUE_ERROR (species_symbol)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor.")); + return species_symbol; } - ecma_value_t capability = ecma_promise_new_capability (); + ecma_value_t constructor_value = this_arg; - if (ECMA_IS_VALUE_ERROR (capability)) + if (!ecma_is_value_null (species_symbol) && !ecma_is_value_undefined (species_symbol)) { - return capability; - } - - ecma_value_t ret = ECMA_VALUE_EMPTY; - - if (!ecma_is_value_object (array) - || ecma_get_object_type (ecma_get_object_from_value (array)) != ECMA_OBJECT_TYPE_ARRAY) - { - ret = ecma_builtin_promise_reject_abrupt (capability); - ecma_free_value (capability); - return ret; - } - - if (is_race) - { - ret = ecma_builtin_promise_do_race (array, capability, this_arg); + constructor_value = species_symbol; } else { - ret = ecma_builtin_promise_do_all (array, capability, this_arg); + ecma_ref_object (this_obj_p); } + ecma_value_t capability = ecma_promise_new_capability (constructor_value); + + if (ECMA_IS_VALUE_ERROR (capability)) + { + ecma_free_value (constructor_value); + return capability; + } + + ecma_value_t iterator = ecma_builtin_promise_reject_abrupt (ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY), + capability); + + if (ECMA_IS_VALUE_ERROR (iterator)) + { + ecma_free_value (constructor_value); + ecma_free_value (capability); + return iterator; + } + + ecma_value_t ret = ECMA_VALUE_EMPTY; + bool is_done = false; + + if (is_race) + { + ret = ecma_builtin_promise_perform_race (iterator, capability, constructor_value, &is_done); + } + else + { + ret = ecma_builtin_promise_perform_all (iterator, constructor_value, capability, &is_done); + } + + ecma_free_value (constructor_value); + if (ECMA_IS_VALUE_ERROR (ret)) { - ret = JERRY_CONTEXT (error_value); + if (!is_done) + { + ret = ecma_op_iterator_close (iterator); + } + + ret = ecma_builtin_promise_reject_abrupt (ret, capability); } + ecma_free_value (iterator); ecma_free_value (capability); return ret; @@ -690,6 +636,18 @@ ecma_builtin_promise_dispatch_construct (const ecma_value_t *arguments_list_p, / return ecma_op_create_promise_object (arguments_list_p[0], ECMA_PROMISE_EXECUTOR_FUNCTION); } /* ecma_builtin_promise_dispatch_construct */ +/** + * 25.4.4.6 get Promise [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_promise_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_promise_species_get */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h index 3135ac70..117e50bf 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h @@ -26,7 +26,7 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* Object properties: * (property name, object pointer getter) */ @@ -42,6 +42,11 @@ ROUTINE (LIT_MAGIC_STRING_RESOLVE, ecma_builtin_promise_resolve, 1, 1) ROUTINE (LIT_MAGIC_STRING_RACE, ecma_builtin_promise_race, 1, 1) ROUTINE (LIT_MAGIC_STRING_ALL, ecma_builtin_promise_all, 1, 1) +/* ES2015 25.4.4.6 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_promise_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c new file mode 100644 index 00000000..73875eab --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c @@ -0,0 +1,120 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-proxy-object.h" +#include "jrt.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-proxy.inc.h" +#define BUILTIN_UNDERSCORED_ID proxy +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup proxy ECMA Proxy object built-in + * @{ + */ + +/** + * The Proxy object's 'revocable' routine + * + * See also: + * ES2015 26.2.2.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_proxy_object_revocable (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t target, /**< target argument */ + ecma_value_t handler) /**< handler argument */ +{ + JERRY_UNUSED (this_arg); + + ecma_object_t *rev_proxy_p = ecma_proxy_create_revocable (target, handler); + + if (JERRY_UNLIKELY (rev_proxy_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_object_value (rev_proxy_p); +} /* ecma_builtin_proxy_object_revocable */ + +/** + * Handle calling [[Call]] of built-in Proxy object + * + * See also: + * ES2015 26.2.2 + * + * @return raised error + */ +ecma_value_t +ecma_builtin_proxy_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + /* 1. */ + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor Proxy requires 'new'")); +} /* ecma_builtin_proxy_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in proxy object + * + * See also: + * ES2015 26.2.2 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * new proxy object - otherwise + */ +ecma_value_t +ecma_builtin_proxy_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + /* 2. */ + ecma_object_t *proxy_p = ecma_proxy_create (arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED, + arguments_list_len > 1 ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED); + + if (JERRY_UNLIKELY (proxy_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_object_value (proxy_p); +} /* ecma_builtin_proxy_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h new file mode 100644 index 00000000..cfe4be57 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h @@ -0,0 +1,38 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Proxy object built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 2, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ + +ROUTINE (LIT_MAGIC_STRING_REVOCABLE, ecma_builtin_proxy_object_revocable, 2, 2) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror.inc.h index b1da135d..f29b8250 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-rangeerror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror.inc.h index 077a93d3..ff0638f3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-referenceerror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c new file mode 100644 index 00000000..9758b69c --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c @@ -0,0 +1,341 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-array-object.h" +#include "ecma-builtins.h" +#include "ecma-builtin-function-prototype.h" +#include "ecma-iterator-object.h" +#include "ecma-builtin-helpers.h" +#include "ecma-builtin-object.h" +#include "ecma-exceptions.h" +#include "ecma-function-object.h" +#include "ecma-gc.h" +#include "ecma-proxy-object.h" +#include "jcontext.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +/** + * This object has a custom dispatch function. + */ +#define BUILTIN_CUSTOM_DISPATCH + +/** + * List of built-in routine identifiers. + */ +enum +{ + ECMA_REFLECT_OBJECT_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1, + ECMA_REFLECT_OBJECT_GET, /* ECMA-262 v6, 26.1.6 */ + ECMA_REFLECT_OBJECT_SET, /* ECMA-262 v6, 26.1.13 */ + ECMA_REFLECT_OBJECT_HAS, /* ECMA-262 v6, 26.1.9 */ + ECMA_REFLECT_OBJECT_DELETE_PROPERTY, /* ECMA-262 v6, 26.1.4 */ + ECMA_REFLECT_OBJECT_CONSTRUCT, /* ECMA-262, 26.1.2 */ + ECMA_REFLECT_OBJECT_OWN_KEYS, /* ECMA-262 v6, 26.1.11 */ + ECMA_REFLECT_OBJECT_GET_PROTOTYPE_OF, /* ECMA-262 v6, 26.1.8 */ + ECMA_REFLECT_OBJECT_SET_PROTOTYPE_OF, /* ECMA-262 v6, 26.1.14 */ + ECMA_REFLECT_OBJECT_APPLY, /* ECMA-262 v6, 26.1.1 */ + ECMA_REFLECT_OBJECT_DEFINE_PROPERTY, /* ECMA-262 v6, 26.1.3 */ + ECMA_REFLECT_OBJECT_GET_OWN_PROPERTY_DESCRIPTOR, /* ECMA-262 v6, 26.1.7 */ + ECMA_REFLECT_OBJECT_IS_EXTENSIBLE, /* ECMA-262 v6, 26.1.10 */ + ECMA_REFLECT_OBJECT_PREVENT_EXTENSIONS, /* ECMA-262 v6, 26.1.12 */ +}; + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-reflect.inc.h" +#define BUILTIN_UNDERSCORED_ID reflect +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup object ECMA Reflect object built-in + * @{ + */ + +/** + * Dispatcher for the built-in's routines. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine + * identifier */ + ecma_value_t this_arg, /**< 'this' argument value */ + const ecma_value_t arguments_list[], /**< list of arguments + * passed to routine */ + ecma_length_t arguments_number) /**< length of arguments' list */ +{ + JERRY_UNUSED (this_arg); + JERRY_UNUSED (arguments_number); + + if (builtin_routine_id < ECMA_REFLECT_OBJECT_CONSTRUCT) + { + /* 1. */ + if (arguments_number == 0 || !ecma_is_value_object (arguments_list[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an Object.")); + } + + /* 2. */ + ecma_string_t *name_str_p = ecma_op_to_prop_name (((arguments_number > 1) ? arguments_list[1] + : ECMA_VALUE_UNDEFINED)); + + /* 3. */ + if (name_str_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t ret_value; + ecma_object_t *target_p = ecma_get_object_from_value (arguments_list[0]); + switch (builtin_routine_id) + { + case ECMA_REFLECT_OBJECT_GET: + { + ecma_value_t receiver = arguments_list[0]; + + /* 4. */ + if (arguments_number > 2) + { + receiver = arguments_list[2]; + } + + ret_value = ecma_op_object_get_with_receiver (target_p, name_str_p, receiver); + break; + } + + case ECMA_REFLECT_OBJECT_HAS: + { + ret_value = ecma_op_object_has_property (target_p, name_str_p); + break; + } + + case ECMA_REFLECT_OBJECT_DELETE_PROPERTY: + { + ret_value = ecma_op_object_delete (target_p, name_str_p, false); + break; + } + + default: + { + JERRY_ASSERT (builtin_routine_id == ECMA_REFLECT_OBJECT_SET); + + ecma_value_t receiver = arguments_list[0]; + + if (arguments_number > 3) + { + receiver = arguments_list[3]; + } + + ret_value = ecma_op_object_put_with_receiver (target_p, name_str_p, arguments_list[2], receiver, false); + break; + } + } + + ecma_deref_ecma_string (name_str_p); + return ret_value; + } + + if (builtin_routine_id == ECMA_REFLECT_OBJECT_OWN_KEYS) + { + /* 1. */ + if (arguments_number == 0 || !ecma_is_value_object (arguments_list[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an Object.")); + } + + ecma_object_t *target_p = ecma_get_object_from_value (arguments_list[0]); + + /* 2. 3. */ + return ecma_builtin_helper_object_get_properties (target_p, ECMA_LIST_SYMBOLS); + } + + if (builtin_routine_id == ECMA_REFLECT_OBJECT_CONSTRUCT) + { + /* 1. */ + if (arguments_number < 1 || !ecma_is_constructor (arguments_list[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Target is not a constructor")); + } + + ecma_object_t *target_p = ecma_get_object_from_value (arguments_list[0]); + + /* 2. */ + ecma_object_t *new_target_p = target_p; + + if (arguments_number > 2) + { + /* 3. */ + if (!ecma_is_constructor (arguments_list[2])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Target is not a constructor")); + } + + new_target_p = ecma_get_object_from_value (arguments_list[2]); + } + + /* 4. */ + if (arguments_number < 2) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Reflect.construct requires the second argument be an object")); + } + + ecma_collection_t *coll_p = ecma_op_create_list_from_array_like (arguments_list[1], false); + + if (coll_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t ret_value = ecma_op_function_construct (target_p, + new_target_p, + coll_p->buffer_p, + coll_p->item_count); + + ecma_collection_free (coll_p); + return ret_value; + } + + if (!ecma_is_value_object (arguments_list[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an Object.")); + } + + switch (builtin_routine_id) + { + case ECMA_REFLECT_OBJECT_GET_PROTOTYPE_OF: + { + return ecma_builtin_object_object_get_prototype_of (ecma_get_object_from_value (arguments_list[0])); + } + case ECMA_REFLECT_OBJECT_SET_PROTOTYPE_OF: + { + if (!ecma_is_value_object (arguments_list[1]) && !ecma_is_value_null (arguments_list[1])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("proto is neither Object nor Null.")); + } + + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); + ecma_value_t status; + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + status = ecma_proxy_object_set_prototype_of (obj_p, arguments_list[1]); + } + else +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + { + status = ecma_op_ordinary_object_set_prototype_of (obj_p, arguments_list[1]); + } + + return status; + } + case ECMA_REFLECT_OBJECT_APPLY: + { + if (!ecma_op_is_callable (arguments_list[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function.")); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (arguments_list[0]); + return ecma_builtin_function_prototype_object_apply (func_obj_p, arguments_list[1], arguments_list[2]); + } + case ECMA_REFLECT_OBJECT_DEFINE_PROPERTY: + { + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); + ecma_string_t *name_str_p = ecma_op_to_prop_name (arguments_list[1]); + + if (name_str_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_property_descriptor_t prop_desc; + ecma_value_t conv_result = ecma_op_to_property_descriptor (arguments_list[2], &prop_desc); + + if (ECMA_IS_VALUE_ERROR (conv_result)) + { + ecma_deref_ecma_string (name_str_p); + return conv_result; + } + + ecma_value_t result = ecma_op_object_define_own_property (obj_p, + name_str_p, + &prop_desc); + + ecma_deref_ecma_string (name_str_p); + ecma_free_property_descriptor (&prop_desc); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + bool boolean_result = ecma_op_to_boolean (result); + + return ecma_make_boolean_value (boolean_result); + } + case ECMA_REFLECT_OBJECT_GET_OWN_PROPERTY_DESCRIPTOR: + { + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); + ecma_string_t *name_str_p = ecma_op_to_prop_name (arguments_list[1]); + + if (name_str_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t ret_val = ecma_builtin_object_object_get_own_property_descriptor (obj_p, name_str_p); + ecma_deref_ecma_string (name_str_p); + return ret_val; + } + case ECMA_REFLECT_OBJECT_IS_EXTENSIBLE: + { + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); + return ecma_builtin_object_object_is_extensible (obj_p); + } + default: + { + JERRY_ASSERT (builtin_routine_id == ECMA_REFLECT_OBJECT_PREVENT_EXTENSIONS); + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_prevent_extensions (obj_p); + } +#endif /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + ecma_op_ordinary_object_prevent_extensions (obj_p); + + return ECMA_VALUE_TRUE; + } + } +} /* ecma_builtin_reflect_dispatch_routine */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.inc.h new file mode 100644 index 00000000..3527b0ee --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.inc.h @@ -0,0 +1,38 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_APPLY, ECMA_REFLECT_OBJECT_APPLY, 3, 3) +ROUTINE (LIT_MAGIC_STRING_DEFINE_PROPERTY_UL, ECMA_REFLECT_OBJECT_DEFINE_PROPERTY, 3, 3) +ROUTINE (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL, ECMA_REFLECT_OBJECT_GET_OWN_PROPERTY_DESCRIPTOR, 2, 2) +ROUTINE (LIT_MAGIC_STRING_GET, ECMA_REFLECT_OBJECT_GET, NON_FIXED, 2) +ROUTINE (LIT_MAGIC_STRING_SET, ECMA_REFLECT_OBJECT_SET, NON_FIXED, 3) +ROUTINE (LIT_MAGIC_STRING_HAS, ECMA_REFLECT_OBJECT_HAS, 2, 2) +ROUTINE (LIT_MAGIC_STRING_DELETE_PROPERTY_UL, ECMA_REFLECT_OBJECT_DELETE_PROPERTY, 2, 2) +ROUTINE (LIT_MAGIC_STRING_OWN_KEYS_UL, ECMA_REFLECT_OBJECT_OWN_KEYS, NON_FIXED, 1) +ROUTINE (LIT_MAGIC_STRING_CONSTRUCT, ECMA_REFLECT_OBJECT_CONSTRUCT, NON_FIXED, 2) +ROUTINE (LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL, ECMA_REFLECT_OBJECT_GET_PROTOTYPE_OF, 1, 1) +ROUTINE (LIT_MAGIC_STRING_IS_EXTENSIBLE, ECMA_REFLECT_OBJECT_IS_EXTENSIBLE, 1, 1) +ROUTINE (LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL, ECMA_REFLECT_OBJECT_PREVENT_EXTENSIONS, 1, 1) +ROUTINE (LIT_MAGIC_STRING_SET_PROTOTYPE_OF_UL, ECMA_REFLECT_OBJECT_SET_PROTOTYPE_OF, 2, 2) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c index 74de58d7..a78d72a4 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c @@ -16,11 +16,15 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" #include "ecma-builtins.h" +#include "ecma-builtin-helpers.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" +#include "ecma-function-object.h" #include "ecma-globals.h" +#include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-regexp-object.h" #include "ecma-try-catch-macro.h" #include "lit-char-helpers.h" @@ -56,21 +60,16 @@ static ecma_value_t ecma_builtin_regexp_prototype_flags_helper (ecma_value_t this, /**< this value */ uint16_t *flags_p) /**< [out] flags */ { - if (!ecma_is_value_object (this) - || !ecma_object_class_is (ecma_get_object_from_value (this), LIT_MAGIC_STRING_REGEXP_UL)) + if (!ecma_object_is_regexp_object (this)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a RegExp object")); } ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (this); - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - re_obj_p->u.class_prop.u.value); - - if (bc_p != NULL) - { - *flags_p = bc_p->header.status_flags; - } + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + re_obj_p->u.class_prop.u.value); + *flags_p = bc_p->header.status_flags; return ECMA_VALUE_EMPTY; } /* ecma_builtin_regexp_prototype_flags_helper */ @@ -88,33 +87,121 @@ ecma_builtin_regexp_prototype_flags_helper (ecma_value_t this, /**< this value * static ecma_value_t ecma_builtin_regexp_prototype_get_flags (ecma_value_t this_arg) /**< this argument */ { - uint16_t flags = RE_FLAG_EMPTY; - ecma_value_t ret_value = ecma_builtin_regexp_prototype_flags_helper (this_arg, &flags); - if (ECMA_IS_VALUE_ERROR (ret_value)) + static const lit_magic_string_id_t flag_lit_ids[] = { - return ret_value; + LIT_MAGIC_STRING_GLOBAL, + LIT_MAGIC_STRING_IGNORECASE_UL, + LIT_MAGIC_STRING_MULTILINE, + LIT_MAGIC_STRING_UNICODE, + LIT_MAGIC_STRING_STICKY + }; + + static const lit_utf8_byte_t flag_chars[] = + { + LIT_CHAR_LOWERCASE_G, + LIT_CHAR_LOWERCASE_I, + LIT_CHAR_LOWERCASE_M, + LIT_CHAR_LOWERCASE_U, + LIT_CHAR_LOWERCASE_Y + }; + + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' value is not an object.")); } - ecma_stringbuilder_t result = ecma_stringbuilder_create (); + ecma_object_t *object_p = ecma_get_object_from_value (this_arg); - if (flags & RE_FLAG_GLOBAL) + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); + for (uint32_t i = 0; i < sizeof (flag_lit_ids) / sizeof (lit_magic_string_id_t); i++) { - ecma_stringbuilder_append_byte (&result, LIT_CHAR_LOWERCASE_G); + ecma_value_t result = ecma_op_object_get_by_magic_id (object_p, flag_lit_ids[i]); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_stringbuilder_destroy (&builder); + return result; + } + + if (ecma_op_to_boolean (result)) + { + ecma_stringbuilder_append_byte (&builder, flag_chars[i]); + } + + ecma_free_value (result); } - if (flags & RE_FLAG_IGNORE_CASE) - { - ecma_stringbuilder_append_byte (&result, LIT_CHAR_LOWERCASE_I); - } - - if (flags & RE_FLAG_MULTILINE) - { - ecma_stringbuilder_append_byte (&result, LIT_CHAR_LOWERCASE_M); - } - - return ecma_make_string_value (ecma_stringbuilder_finalize (&result)); + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_builtin_regexp_prototype_get_flags */ +/** + * The EscapeRegExpPattern method. + * + * See also: + * ECMA-262 v6, 21.2.3.2.4 + * + * @return ecma_value_t + */ +static ecma_value_t +ecma_op_escape_regexp_pattern (ecma_string_t *pattern_str_p) /**< RegExp pattern */ +{ + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); + + ECMA_STRING_TO_UTF8_STRING (pattern_str_p, pattern_start_p, pattern_start_size); + + const lit_utf8_byte_t *pattern_str_curr_p = pattern_start_p; + const lit_utf8_byte_t *pattern_str_end_p = pattern_start_p + pattern_start_size; + + while (pattern_str_curr_p < pattern_str_end_p) + { + ecma_char_t c = lit_cesu8_read_next (&pattern_str_curr_p); + + switch (c) + { + case LIT_CHAR_SLASH: + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\\/", 2); + break; + } + case LIT_CHAR_LF: + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\\n", 2); + break; + } + case LIT_CHAR_CR: + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\\r", 2); + break; + } + case LIT_CHAR_LS: + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\\u2028", 6); + break; + } + case LIT_CHAR_PS: + { + ecma_stringbuilder_append_raw (&builder, (const lit_utf8_byte_t *) "\\u2029", 6); + break; + } + case LIT_CHAR_BACKSLASH: + { + JERRY_ASSERT (pattern_str_curr_p < pattern_str_end_p); + ecma_stringbuilder_append_char (&builder, LIT_CHAR_BACKSLASH); + ecma_stringbuilder_append_char (&builder, lit_cesu8_read_next (&pattern_str_curr_p)); + break; + } + default: + { + ecma_stringbuilder_append_char (&builder, c); + break; + } + } + } + + ECMA_FINALIZE_UTF8_STRING (pattern_start_p, pattern_start_size); + + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); +} /* ecma_op_escape_regexp_pattern */ + /** * The RegExp.prototype object's 'source' accessor property * @@ -129,23 +216,16 @@ ecma_builtin_regexp_prototype_get_flags (ecma_value_t this_arg) /**< this argume static ecma_value_t ecma_builtin_regexp_prototype_get_source (ecma_value_t this_arg) /**< this argument */ { - if (!ecma_is_value_object (this_arg) - || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_REGEXP_UL)) + if (!ecma_object_is_regexp_object (this_arg)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a RegExp object")); } ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - re_obj_p->u.class_prop.u.value); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + re_obj_p->u.class_prop.u.value); - if (bc_p != NULL) - { - ecma_ref_ecma_string (ecma_get_string_from_value (bc_p->source)); - return bc_p->source; - } - - return ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP)); + return ecma_op_escape_regexp_pattern (ecma_get_string_from_value (bc_p->source)); } /* ecma_builtin_regexp_prototype_get_source */ /** @@ -222,6 +302,56 @@ ecma_builtin_regexp_prototype_get_multiline (ecma_value_t this_arg) /**< this ar return ecma_make_boolean_value (flags & RE_FLAG_MULTILINE); } /* ecma_builtin_regexp_prototype_get_multiline */ + +/** + * The RegExp.prototype object's 'sticky' accessor property + * + * See also: + * ECMA-262 v6, 21.2.5.12 + * + * @return ECMA_VALUE_ERROR - if 'this' is not a RegExp object + * ECMA_VALUE_TRUE - if 'sticky' flag is set + * ECMA_VALUE_FALSE - otherwise + * + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_get_sticky (ecma_value_t this_arg) /**< this argument */ +{ + uint16_t flags = RE_FLAG_EMPTY; + ecma_value_t ret_value = ecma_builtin_regexp_prototype_flags_helper (this_arg, &flags); + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + return ecma_make_boolean_value (flags & RE_FLAG_STICKY); +} /* ecma_builtin_regexp_prototype_get_sticky */ + +/** + * The RegExp.prototype object's 'unicode' accessor property + * + * See also: + * ECMA-262 v6, 21.2.5.15 + * + * @return ECMA_VALUE_ERROR - if 'this' is not a RegExp object + * ECMA_VALUE_TRUE - if 'unicode' flag is set + * ECMA_VALUE_FALSE - otherwise + * + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_get_unicode (ecma_value_t this_arg) /**< this argument */ +{ + uint16_t flags = RE_FLAG_EMPTY; + ecma_value_t ret_value = ecma_builtin_regexp_prototype_flags_helper (this_arg, &flags); + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + return ecma_make_boolean_value (flags & RE_FLAG_UNICODE); +} /* ecma_builtin_regexp_prototype_get_unicode */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -242,100 +372,54 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument ecma_value_t pattern_arg, /**< pattern or RegExp object */ ecma_value_t flags_arg) /**< flags */ { - if (!ecma_is_value_object (this_arg) - || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_REGEXP_UL) - /* The builtin RegExp.prototype object does not have [[RegExpMatcher]] internal slot */ - || ecma_get_object_from_value (this_arg) == ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE)) + if (!ecma_object_is_regexp_object (this_arg) +#if !ENABLED (JERRY_ES2015) + || ecma_get_object_from_value (this_arg) == ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE) +#endif /* !ENABLED (JERRY_ES2015) */ + ) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a RegExp object")); } - uint16_t flags = 0; + ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); + ecma_extended_object_t *regexp_obj_p = (ecma_extended_object_t *) this_obj_p; + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + regexp_obj_p->u.class_prop.u.value); - if (ecma_is_value_object (pattern_arg) - && ecma_object_class_is (ecma_get_object_from_value (pattern_arg), LIT_MAGIC_STRING_REGEXP_UL) - && ecma_get_object_from_value (pattern_arg) != ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE)) + ecma_value_t status = ecma_builtin_helper_def_prop (this_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROP_IS_THROW); + + JERRY_ASSERT (ecma_is_value_true (status)); + + if (ecma_object_is_regexp_object (pattern_arg)) { if (!ecma_is_value_undefined (flags_arg)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument")); } - /* Compile from existing RegExp object. */ - ecma_extended_object_t *target_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_arg); - re_compiled_code_t *target_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - target_p->u.class_prop.u.value); + ecma_extended_object_t *pattern_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_arg); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + pattern_obj_p->u.class_prop.u.value); - ecma_object_t *this_object_p = ecma_get_object_from_value (this_arg); - ecma_extended_object_t *current_p = (ecma_extended_object_t *) this_object_p; - - re_compiled_code_t *current_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - current_p->u.class_prop.u.value); - - JERRY_ASSERT (current_bc_p != NULL); - ecma_bytecode_deref ((ecma_compiled_code_t *) current_bc_p); - - JERRY_ASSERT (target_bc_p != NULL); - ecma_bytecode_ref ((ecma_compiled_code_t *) target_bc_p); - ECMA_SET_INTERNAL_VALUE_POINTER (current_p->u.class_prop.u.value, target_bc_p); - ecma_regexp_initialize_props (this_object_p, - ecma_get_string_from_value (target_bc_p->source), - target_bc_p->header.status_flags); - return ecma_copy_value (this_arg); + ecma_ref_object (this_obj_p); + /* ecma_op_create_regexp_from_bytecode will never throw an error while re-initalizing the regexp object, so we + * can deref the old bytecode without leaving a dangling pointer. */ + ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); + return ecma_op_create_regexp_from_bytecode (this_obj_p, bc_p); } - ecma_string_t *pattern_string_p = NULL; + ecma_value_t ret_value = ecma_op_create_regexp_from_pattern (this_obj_p, pattern_arg, flags_arg); - /* Get source string. */ - ecma_value_t ret_value = ecma_regexp_read_pattern_str_helper (pattern_arg, &pattern_string_p); - if (ECMA_IS_VALUE_ERROR (ret_value)) + if (!ECMA_IS_VALUE_ERROR (ret_value)) { - JERRY_ASSERT (pattern_string_p == NULL); - return ret_value; - } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); - - /* Parse flags. */ - if (!ecma_is_value_undefined (flags_arg)) - { - ecma_value_t flags_str_value = ecma_op_to_string (flags_arg); - if (ECMA_IS_VALUE_ERROR (flags_str_value)) - { - ecma_deref_ecma_string (pattern_string_p); - return flags_str_value; - } - - ecma_value_t parsed_flags_val = ecma_regexp_parse_flags (ecma_get_string_from_value (flags_str_value), &flags); - ecma_free_value (flags_str_value); - if (ECMA_IS_VALUE_ERROR (parsed_flags_val)) - { - ecma_deref_ecma_string (pattern_string_p); - return parsed_flags_val; - } + ecma_ref_object (this_obj_p); + ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); } - /* Try to compile bytecode from new source. */ - const re_compiled_code_t *new_bc_p = NULL; - ecma_value_t bc_val = re_compile_bytecode (&new_bc_p, pattern_string_p, flags); - if (ECMA_IS_VALUE_ERROR (bc_val)) - { - ecma_deref_ecma_string (pattern_string_p); - return bc_val; - } - - ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); - ecma_value_t *bc_prop_p = &(((ecma_extended_object_t *) this_obj_p)->u.class_prop.u.value); - - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); - - JERRY_ASSERT (old_bc_p != NULL); - ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p); - - ECMA_SET_INTERNAL_VALUE_POINTER (*bc_prop_p, new_bc_p); - ecma_regexp_initialize_props (this_obj_p, pattern_string_p, flags); - ecma_deref_ecma_string (pattern_string_p); - - return ecma_copy_value (this_arg); + return ret_value; } /* ecma_builtin_regexp_prototype_compile */ #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */ @@ -355,8 +439,7 @@ static ecma_value_t ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { - if (!ecma_is_value_object (this_arg) - || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_REGEXP_UL)) + if (!ecma_object_is_regexp_object (this_arg)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Incomplete RegExp type")); } @@ -367,17 +450,17 @@ ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ return obj_this; } - ecma_value_t input_str_value = ecma_op_to_string (arg); - if (ECMA_IS_VALUE_ERROR (input_str_value)) + ecma_string_t *input_str_p = ecma_op_to_string (arg); + if (JERRY_UNLIKELY (input_str_p == NULL)) { ecma_free_value (obj_this); - return input_str_value; + return ECMA_VALUE_ERROR; } - ecma_value_t ret_value = ecma_regexp_exec_helper (obj_this, input_str_value, false); + ecma_value_t ret_value = ecma_regexp_exec_helper (ecma_get_object_from_value (obj_this), input_str_p); ecma_free_value (obj_this); - ecma_free_value (input_str_value); + ecma_deref_ecma_string (input_str_p); return ret_value; } /* ecma_builtin_regexp_prototype_exec */ @@ -387,6 +470,7 @@ ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ * * See also: * ECMA-262 v5, 15.10.6.3 + * ECMA-262 v6, 21.2.5.13 * * @return true - if match is not null * false - otherwise @@ -397,12 +481,35 @@ static ecma_value_t ecma_builtin_regexp_prototype_test (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { +#if ENABLED (JERRY_ES2015) + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' value is not an object")); + } + + ecma_string_t *arg_str_p = ecma_op_to_string (arg); + + if (JERRY_UNLIKELY (arg_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ecma_op_regexp_exec (this_arg, arg_str_p); + + ecma_deref_ecma_string (arg_str_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } +#else /* !ENABLED (JERRY_ES2015) */ ecma_value_t result = ecma_builtin_regexp_prototype_exec (this_arg, arg); if (ECMA_IS_VALUE_ERROR (result)) { return result; } +#endif /* ENABLED (JERRY_ES2015) */ ecma_value_t ret_value = ecma_make_boolean_value (!ecma_is_value_null (result)); ecma_free_value (result); @@ -422,31 +529,68 @@ ecma_builtin_regexp_prototype_test (ecma_value_t this_arg, /**< this argument */ static ecma_value_t ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argument */ { - if (!ecma_is_value_object (this_arg) - || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_REGEXP_UL)) +#if ENABLED (JERRY_ES2015) + if (!ecma_is_value_object (this_arg)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' value is not an object.")); + } + + ecma_object_t *object_p = ecma_get_object_from_value (this_arg); + + ecma_value_t result = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_SOURCE); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_string_t *source_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (source_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + result = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_FLAGS); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_ecma_string (source_p); + return result; + } + + ecma_string_t *flags_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (flags_p == NULL) + { + ecma_deref_ecma_string (source_p); + return ECMA_VALUE_ERROR; + } + + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_SLASH); + ecma_stringbuilder_append (&builder, source_p); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_SLASH); + ecma_stringbuilder_append (&builder, flags_p); + + ecma_deref_ecma_string (source_p); + ecma_deref_ecma_string (flags_p); + + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); +#else /* !ENABLED (JERRY_ES2015) */ + if (!ecma_object_is_regexp_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' value is not a RegExp object.")); } ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) obj_p; - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, - re_obj_p->u.class_prop.u.value); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + re_obj_p->u.class_prop.u.value); - ecma_string_t *source_p; - uint16_t flags; - - if (bc_p != NULL) - { - source_p = ecma_get_string_from_value (bc_p->source); - flags = bc_p->header.status_flags; - } - else - { - source_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); - flags = RE_FLAG_EMPTY; - } + ecma_string_t *source_p = ecma_get_string_from_value (bc_p->source); + uint16_t flags = bc_p->header.status_flags; ecma_stringbuilder_t result = ecma_stringbuilder_create (); ecma_stringbuilder_append_byte (&result, LIT_CHAR_SLASH); @@ -469,8 +613,90 @@ ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argume } return ecma_make_string_value (ecma_stringbuilder_finalize (&result)); +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_builtin_regexp_prototype_to_string */ +#if ENABLED (JERRY_ES2015) +/** + * Helper function to determine if method is the builtin exec method + * + * @return true, if function is the builtin exec method + * false, otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_builtin_is_regexp_exec (ecma_extended_object_t *obj_p) +{ + return (ecma_get_object_is_builtin ((ecma_object_t *) obj_p) + && obj_p->u.built_in.routine_id == ECMA_ROUTINE_LIT_MAGIC_STRING_EXECecma_builtin_regexp_prototype_exec); +} /* ecma_builtin_is_regexp_exec */ + +/** + * The RegExp.prototype object's '@@replace' routine + * + * See also: + * ECMA-262 v6.0, 21.2.5.8 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_symbol_replace (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg, /**< source string */ + ecma_value_t replace_arg) /**< replace string */ +{ + return ecma_regexp_replace_helper (this_arg, string_arg, replace_arg); +} /* ecma_builtin_regexp_prototype_symbol_replace */ + +/** + * The RegExp.prototype object's '@@search' routine + * + * See also: + * ECMA-262 v6.0, 21.2.5.9 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_symbol_search (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg) /**< string argument */ +{ + return ecma_regexp_search_helper (this_arg, string_arg); +} /* ecma_builtin_regexp_prototype_symbol_search */ + +/** + * The RegExp.prototype object's '@@split' routine + * + * See also: + * ECMA-262 v6.0, 21.2.5.11 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_symbol_split (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg, /**< source string */ + ecma_value_t limit_arg) /**< limit */ +{ + return ecma_regexp_split_helper (this_arg, string_arg, limit_arg); +} /* ecma_builtin_regexp_prototype_symbol_split */ + +/** + * The RegExp.prototype object's '@@match' routine + * + * See also: + * ECMA-262 v6.0, 21.2.5.6 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_regexp_prototype_symbol_match (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg) /**< source string */ +{ + return ecma_regexp_match_helper (this_arg, string_arg); +} /* ecma_builtin_regexp_prototype_symbol_match */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.inc.h index 33a1375b..ead2be39 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.inc.h @@ -29,23 +29,36 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, #if ENABLED (JERRY_ES2015) ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_FLAGS, ecma_builtin_regexp_prototype_get_flags, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SOURCE, ecma_builtin_regexp_prototype_get_source, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_GLOBAL, ecma_builtin_regexp_prototype_get_global, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_IGNORECASE_UL, ecma_builtin_regexp_prototype_get_ignorecase, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_MULTILINE, ecma_builtin_regexp_prototype_get_multiline, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_UNICODE, + ecma_builtin_regexp_prototype_get_unicode, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_STICKY, + ecma_builtin_regexp_prototype_get_sticky, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +ROUTINE (LIT_GLOBAL_SYMBOL_REPLACE, ecma_builtin_regexp_prototype_symbol_replace, 2, 2) +ROUTINE (LIT_GLOBAL_SYMBOL_SEARCH, ecma_builtin_regexp_prototype_symbol_search, 1, 1) +ROUTINE (LIT_GLOBAL_SYMBOL_SPLIT, ecma_builtin_regexp_prototype_symbol_split, 2, 2) +ROUTINE (LIT_GLOBAL_SYMBOL_MATCH, ecma_builtin_regexp_prototype_symbol_match, 1, 1) #else /* !ENABLED (JERRY_ES2015) */ /* ECMA-262 v5, 15.10.7.1 */ STRING_VALUE (LIT_MAGIC_STRING_SOURCE, @@ -66,12 +79,12 @@ SIMPLE_VALUE (LIT_MAGIC_STRING_IGNORECASE_UL, SIMPLE_VALUE (LIT_MAGIC_STRING_MULTILINE, ECMA_VALUE_FALSE, ECMA_PROPERTY_FIXED) -#endif /* ENABLED (JERRY_ES2015) */ /* ECMA-262 v5, 15.10.7.5 */ NUMBER_VALUE (LIT_MAGIC_STRING_LASTINDEX_UL, 0, ECMA_PROPERTY_FLAG_WRITABLE) +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) ROUTINE (LIT_MAGIC_STRING_COMPILE, ecma_builtin_regexp_prototype_compile, 2, 1) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c index 592aec18..5c6ed125 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c @@ -17,7 +17,9 @@ #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" +#include "ecma-gc.h" #include "ecma-helpers.h" +#include "jcontext.h" #include "ecma-objects.h" #include "ecma-regexp-object.h" #include "ecma-try-catch-macro.h" @@ -41,31 +43,19 @@ * @{ */ -/** - * Handle calling [[Call]] of built-in RegExp object - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -ecma_builtin_regexp_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ -{ - return ecma_builtin_regexp_dispatch_construct (arguments_list_p, arguments_list_len); -} /* ecma_builtin_regexp_dispatch_call */ - -/** - * Handle calling [[Construct]] of built-in RegExp object - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ +static ecma_value_t +ecma_builtin_regexp_dispatch_helper (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ { ecma_value_t pattern_value = ECMA_VALUE_UNDEFINED; ecma_value_t flags_value = ECMA_VALUE_UNDEFINED; +#if ENABLED (JERRY_ES2015) + bool create_regexp_from_bc = false; + bool free_arguments = false; + ecma_object_t *new_target_p = JERRY_CONTEXT (current_new_target); +#else /* !ENABLED (JERRY_ES2015) */ + ecma_object_t *new_target_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ if (arguments_list_len > 0) { @@ -78,8 +68,85 @@ ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /* } } - if (ecma_is_value_object (pattern_value) - && ecma_object_class_is (ecma_get_object_from_value (pattern_value), LIT_MAGIC_STRING_REGEXP_UL)) +#if ENABLED (JERRY_ES2015) + ecma_value_t regexp_value = ecma_op_is_regexp (pattern_value); + + if (ECMA_IS_VALUE_ERROR (regexp_value)) + { + return regexp_value; + } + + bool pattern_is_regexp = regexp_value == ECMA_VALUE_TRUE; + re_compiled_code_t *bc_p = NULL; + + if (new_target_p == NULL) + { + new_target_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP); + + if (pattern_is_regexp && ecma_is_value_undefined (flags_value)) + { + ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value); + + ecma_value_t pattern_constructor = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); + + if (ECMA_IS_VALUE_ERROR (pattern_constructor)) + { + return pattern_constructor; + } + + bool is_same = ecma_op_same_value (ecma_make_object_value (new_target_p), pattern_constructor); + ecma_free_value (pattern_constructor); + + if (is_same) + { + return ecma_copy_value (pattern_value); + } + } + } + + if (ecma_object_is_regexp_object (pattern_value)) + { + ecma_extended_object_t *pattern_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_value); + bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + pattern_obj_p->u.class_prop.u.value); + + create_regexp_from_bc = ecma_is_value_undefined (flags_value); + + if (!create_regexp_from_bc) + { + pattern_value = bc_p->source; + } + } + else if (pattern_is_regexp) + { + ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value); + + pattern_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_SOURCE); + + if (ECMA_IS_VALUE_ERROR (pattern_value)) + { + return pattern_value; + } + + if (ecma_is_value_undefined (flags_value)) + { + flags_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_FLAGS); + + if (ECMA_IS_VALUE_ERROR (flags_value)) + { + ecma_free_value (pattern_value); + return flags_value; + } + } + else + { + flags_value = ecma_copy_value (flags_value); + } + + free_arguments = true; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (pattern_value)) { if (ecma_is_value_undefined (flags_value)) { @@ -88,44 +155,84 @@ ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /* return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument of RegExp call.")); } +#endif /* ENABLED (JERRY_ES2015) */ - ecma_string_t *pattern_string_p = NULL; - ecma_value_t ret_value = ecma_regexp_read_pattern_str_helper (pattern_value, &pattern_string_p); - if (ECMA_IS_VALUE_ERROR (ret_value)) + ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_object_t *new_target_obj_p = ecma_op_regexp_alloc (new_target_p); + + if (JERRY_LIKELY (new_target_obj_p != NULL)) { - return ret_value; - } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); - - uint16_t flags = 0; - if (!ecma_is_value_undefined (flags_value)) - { - ecma_value_t flags_str_value = ecma_op_to_string (flags_value); - - if (ECMA_IS_VALUE_ERROR (flags_str_value)) +#if ENABLED (JERRY_ES2015) + if (create_regexp_from_bc) { - ecma_deref_ecma_string (pattern_string_p); - return flags_str_value; + ret_value = ecma_op_create_regexp_from_bytecode (new_target_obj_p, bc_p); + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (ret_value)); } - - ecma_string_t *flags_string_p = ecma_get_string_from_value (flags_str_value); - JERRY_ASSERT (flags_string_p != NULL); - ret_value = ecma_regexp_parse_flags (flags_string_p, &flags); - ecma_free_value (flags_str_value); // implicit frees flags_string_p - - if (ECMA_IS_VALUE_ERROR (ret_value)) + else +#endif /* ENABLED (JERRY_ES2015) */ { - ecma_deref_ecma_string (pattern_string_p); - return ret_value; + ret_value = ecma_op_create_regexp_from_pattern (new_target_obj_p, pattern_value, flags_value); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_deref_object (new_target_obj_p); + } } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); } - ret_value = ecma_op_create_regexp_object (pattern_string_p, flags); - ecma_deref_ecma_string (pattern_string_p); +#if ENABLED (JERRY_ES2015) + if (free_arguments) + { + ecma_free_value (pattern_value); + ecma_free_value (flags_value); + } +#endif /* ENABLED (JERRY_ES2015) */ + return ret_value; +} /* ecma_builtin_regexp_dispatch_helper */ + +/** + * Handle calling [[Call]] of built-in RegExp object + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_regexp_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_regexp_dispatch_helper (arguments_list_p, + arguments_list_len); +} /* ecma_builtin_regexp_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in RegExp object + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_regexp_dispatch_helper (arguments_list_p, + arguments_list_len); } /* ecma_builtin_regexp_dispatch_construct */ +#if ENABLED (JERRY_ES2015) +/** + * 21.2.4.2 get RegExp [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_regexp_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_regexp_species_get */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h index 135427af..bbc0be6c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h @@ -21,16 +21,22 @@ #if ENABLED (JERRY_BUILTIN_REGEXP) -/* ECMA-262 v5, 15.10.5 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 2, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* ECMA-262 v5, 15.10.5.1 */ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_BUILTIN_ID_REGEXP_PROTOTYPE, ECMA_PROPERTY_FIXED) +#if ENABLED (JERRY_ES2015) +/* ECMA-262 v6, 21.2.4.2 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_regexp_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +#endif /* ENABLED (JERRY_ES2015) */ + #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c index 6a0f5d14..b629771b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set-iterator-prototype.c @@ -19,10 +19,6 @@ #if ENABLED (JERRY_ES2015_BUILTIN_SET) -#if !ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) -#error "Set iterator builtin requires ES2015 iterator builtin" -#endif /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c index af5d1ffa..038916b5 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c @@ -130,7 +130,8 @@ ecma_builtin_set_prototype_object_size_getter (ecma_value_t this_arg) /**< this return ecma_op_container_size (this_arg, LIT_MAGIC_STRING_SET_UL); } /* ecma_builtin_set_prototype_object_size_getter */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * The Set.prototype object's 'entries' routine * @@ -188,7 +189,7 @@ ecma_builtin_set_prototype_object_values (ecma_value_t this_arg) /**< this argum ECMA_PSEUDO_SET_ITERATOR); } /* ecma_builtin_set_prototype_object_values */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h index a0356127..9e070503 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h @@ -29,12 +29,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_SET, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 23.1.3.13 */ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_SET_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -43,16 +43,16 @@ ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_set_prototype_object_clear, 0, 0) ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_set_prototype_object_delete, 1, 1) ROUTINE (LIT_MAGIC_STRING_FOR_EACH_UL, ecma_builtin_set_prototype_object_foreach, 2, 1) ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_set_prototype_object_has, 1, 1) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_ENTRIES, ecma_builtin_set_prototype_object_entries, 0, 0) ROUTINE (LIT_MAGIC_STRING_VALUES, ecma_builtin_set_prototype_object_values, 0, 0) ROUTINE (LIT_MAGIC_STRING_KEYS, ecma_builtin_set_prototype_object_keys, 0, 0) ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ecma_builtin_set_prototype_object_values, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SIZE, ecma_builtin_set_prototype_object_size_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c index e6f6187a..e6f9f9df 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c @@ -65,6 +65,18 @@ ecma_builtin_set_dispatch_construct (const ecma_value_t *arguments_list_p, /**< ECMA_BUILTIN_ID_SET_PROTOTYPE); } /* ecma_builtin_set_dispatch_construct */ +/** + * 23.2.2.2 get Set [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_set_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_set_species_get */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h index c2847bbc..dc63bd69 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h @@ -27,7 +27,7 @@ /* ECMA-262 v6, 23.2.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 0, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ECMA-262 v6, 23.1 */ STRING_VALUE (LIT_MAGIC_STRING_NAME, @@ -42,6 +42,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_BUILTIN_ID_SET_PROTOTYPE, ECMA_PROPERTY_FIXED) +/* ECMA-262 v6, 23.2.2.2 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_set_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.c index d2bab9ce..6ce4d272 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.c @@ -17,11 +17,7 @@ #include "ecma-builtins.h" #include "ecma-iterator-object.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) - -#if !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) -#error "Iterator builtin requires ES2015 symbol builtin" -#endif /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#if ENABLED (JERRY_ES2015) #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -81,7 +77,6 @@ ecma_builtin_string_iterator_prototype_object_next (ecma_value_t this_val) /**< JERRY_ASSERT (ecma_is_value_string (iterated_value)); - ecma_string_t *string_p = ecma_get_string_from_value (iterated_value); /* 6. */ @@ -149,4 +144,4 @@ ecma_builtin_string_iterator_prototype_object_next (ecma_value_t this_val) /**< * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.inc.h index 9a04570e..def35bd1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-iterator-prototype.inc.h @@ -19,7 +19,7 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_STRING_ITERATOR_UL, @@ -29,6 +29,6 @@ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_NEXT, ecma_builtin_string_iterator_prototype_object_next, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index f227662d..03701b35 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -17,6 +17,7 @@ #include "ecma-array-object.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" +#include "ecma-builtin-regexp.inc.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" @@ -26,11 +27,11 @@ #include "ecma-iterator-object.h" #include "ecma-objects.h" #include "ecma-string-object.h" -#include "ecma-try-catch-macro.h" #include "jcontext.h" #include "jrt.h" #include "jrt-libc-includes.h" #include "lit-char-helpers.h" +#include "lit-strings.h" #if ENABLED (JERRY_BUILTIN_REGEXP) #include "ecma-regexp-object.h" @@ -78,9 +79,10 @@ enum ECMA_STRING_PROTOTYPE_SUBSTR, ECMA_STRING_PROTOTYPE_REPEAT, + ECMA_STRING_PROTOTYPE_CODE_POINT_AT, /* Note: These 5 routines MUST be in this order */ - ECMA_STRING_PROTOTYPE_INDEX_OF, ECMA_STRING_PROTOTYPE_LAST_INDEX_OF, + ECMA_STRING_PROTOTYPE_INDEX_OF, ECMA_STRING_PROTOTYPE_STARTS_WITH, ECMA_STRING_PROTOTYPE_INCLUDES, ECMA_STRING_PROTOTYPE_ENDS_WITH, @@ -150,30 +152,28 @@ ecma_builtin_string_prototype_char_at_helper (ecma_value_t this_arg, /**< this a { /* 3 */ ecma_number_t index_num; - ecma_value_t to_num_result = ecma_get_number (arg, &index_num); + ecma_value_t to_num_result = ecma_op_to_integer (arg, &index_num); if (JERRY_UNLIKELY (!ecma_is_value_empty (to_num_result))) { return to_num_result; } - ecma_free_value (to_num_result); /* 2 */ - ecma_value_t to_string_val = ecma_op_to_string (this_arg); - if (ECMA_IS_VALUE_ERROR (to_string_val)) + ecma_string_t *original_string_p = ecma_op_to_string (this_arg); + if (JERRY_UNLIKELY (original_string_p == NULL)) { - return to_string_val; + return ECMA_VALUE_ERROR; } /* 4 */ - ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val); const ecma_length_t len = ecma_string_get_length (original_string_p); /* 5 */ // When index_num is NaN, then the first two comparisons are false if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && len == 0)) { - ecma_free_value (to_string_val); + ecma_deref_ecma_string (original_string_p); return (charcode_mode ? ecma_make_nan_value () : ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY)); } @@ -188,7 +188,7 @@ ecma_builtin_string_prototype_char_at_helper (ecma_value_t this_arg, /**< this a JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num)); ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num)); - ecma_free_value (to_string_val); + ecma_deref_ecma_string (original_string_p); return (charcode_mode ? ecma_make_uint32_value (new_ecma_char) : ecma_make_string_value (ecma_new_ecma_string_from_code_unit (new_ecma_char))); @@ -208,29 +208,27 @@ ecma_builtin_string_prototype_object_concat (ecma_string_t *this_string_p, /**< const ecma_value_t *argument_list_p, /**< arguments list */ ecma_length_t arguments_number) /**< number of arguments */ { - ecma_ref_ecma_string (this_string_p); + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (this_string_p); - ecma_string_t *string_to_return = this_string_p; /* 5 */ for (uint32_t arg_index = 0; arg_index < arguments_number; ++arg_index) { /* 5a, b */ - ecma_value_t get_arg_string = ecma_op_to_string (argument_list_p[arg_index]); + ecma_string_t *get_arg_string_p = ecma_op_to_string (argument_list_p[arg_index]); - if (ECMA_IS_VALUE_ERROR (get_arg_string)) + if (JERRY_UNLIKELY (get_arg_string_p == NULL)) { - ecma_deref_ecma_string (string_to_return); - return get_arg_string; + ecma_stringbuilder_destroy (&builder); + return ECMA_VALUE_ERROR; } - ecma_string_t *get_arg_string_p = ecma_get_string_from_value (get_arg_string); - string_to_return = ecma_concat_ecma_strings (string_to_return, get_arg_string_p); + ecma_stringbuilder_append (&builder, get_arg_string_p); ecma_deref_ecma_string (get_arg_string_p); } /* 6 */ - return ecma_make_string_value (string_to_return); + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_builtin_string_prototype_object_concat */ /** @@ -247,15 +245,13 @@ ecma_builtin_string_prototype_object_locale_compare (ecma_string_t *this_string_ ecma_value_t arg) /**< routine's argument */ { /* 3. */ - ecma_value_t arg_to_string_val = ecma_op_to_string (arg); + ecma_string_t *arg_string_p = ecma_op_to_string (arg); - if (ECMA_IS_VALUE_ERROR (arg_to_string_val)) + if (JERRY_UNLIKELY (arg_string_p == NULL)) { - return arg_to_string_val; + return ECMA_VALUE_ERROR; } - ecma_string_t *arg_string_p = ecma_get_string_from_value (arg_to_string_val); - ecma_number_t result = ECMA_NUMBER_ZERO; if (ecma_compare_ecma_strings_relational (this_string_p, arg_string_p)) @@ -273,47 +269,10 @@ ecma_builtin_string_prototype_object_locale_compare (ecma_string_t *this_string_ ecma_deref_ecma_string (arg_string_p); - return ecma_make_number_value (result); } /* ecma_builtin_string_prototype_object_locale_compare */ #if ENABLED (JERRY_BUILTIN_REGEXP) - -/** - * The common preparation code for 'search' and 'match' functions - * of the String prototype. - * - * @return empty value on success, error value otherwise - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_string_prepare_search (ecma_value_t regexp_arg, /**< regex argument */ - ecma_value_t *regexp_value) /**< [out] ptr to store the regexp object */ -{ - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - /* 3. */ - if (ecma_is_value_object (regexp_arg) - && ecma_object_class_is (ecma_get_object_from_value (regexp_arg), LIT_MAGIC_STRING_REGEXP_UL)) - { - *regexp_value = ecma_copy_value (regexp_arg); - } - else - { - /* 4. */ - ecma_value_t regexp_arguments[1] = { regexp_arg }; - ECMA_TRY_CATCH (new_regexp_value, - ecma_builtin_regexp_dispatch_construct (regexp_arguments, 1), - ret_value); - - *regexp_value = ecma_copy_value (new_regexp_value); - - ECMA_FINALIZE (new_regexp_value); - } - - return ret_value; -} /* ecma_builtin_string_prepare_search */ - /** * The String.prototype object's 'match' routine * @@ -324,859 +283,288 @@ ecma_builtin_string_prepare_search (ecma_value_t regexp_arg, /**< regex argument * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_string_prototype_object_match (ecma_value_t this_to_string_value, /**< this argument */ +ecma_builtin_string_prototype_object_match (ecma_value_t this_argument, /**< this argument */ ecma_value_t regexp_arg) /**< routine's argument */ { - ecma_value_t regexp_value = ECMA_VALUE_EMPTY; - - ecma_value_t ret_value = ecma_builtin_string_prepare_search (regexp_arg, ®exp_value); - - if (ECMA_IS_VALUE_ERROR (ret_value)) +#if ENABLED (JERRY_ES2015) + /* 3. */ + if (!(ecma_is_value_undefined (regexp_arg) || ecma_is_value_null (regexp_arg))) { - return ret_value; + /* 3.a */ + ecma_value_t matcher = ecma_op_get_method_by_symbol_id (regexp_arg, LIT_GLOBAL_SYMBOL_MATCH); + + /* 3.b */ + if (ECMA_IS_VALUE_ERROR (matcher)) + { + return matcher; + } + + /* 3.c */ + if (!ecma_is_value_undefined (matcher)) + { + /* 3.c.i */ + ecma_object_t *matcher_method = ecma_get_object_from_value (matcher); + ecma_value_t result = ecma_op_function_call (matcher_method, regexp_arg, &this_argument, 1); + ecma_deref_object (matcher_method); + return result; + } } - JERRY_ASSERT (!ecma_is_value_empty (regexp_value)); - ecma_object_t *regexp_obj_p = ecma_get_object_from_value (regexp_value); + /* 4. */ + ecma_string_t *this_str_p = ecma_op_to_string (this_argument); /* 5. */ - ecma_value_t global_value = ecma_op_object_get_by_magic_id (regexp_obj_p, LIT_MAGIC_STRING_GLOBAL); - - if (ECMA_IS_VALUE_ERROR (global_value)) + if (JERRY_UNLIKELY (this_str_p == NULL)) { + return ECMA_VALUE_ERROR; + } + + /* 6. */ + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) + { + ecma_deref_ecma_string (this_str_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (new_regexp)) + { + ecma_deref_object (regexp_obj_p); - return global_value; + ecma_deref_ecma_string (this_str_p); + return new_regexp; } + ecma_value_t this_str_value = ecma_make_string_value (this_str_p); - ecma_string_t *this_string_p = ecma_get_string_from_value (this_to_string_value); - ecma_ref_ecma_string (this_string_p); + /* 8. */ + ecma_value_t ret_value = ecma_op_invoke_by_symbol_id (new_regexp, LIT_GLOBAL_SYMBOL_MATCH, &this_str_value, 1); - JERRY_ASSERT (ecma_is_value_boolean (global_value)); - - if (ecma_is_value_false (global_value)) - { - /* 7. */ - ret_value = ecma_regexp_exec_helper (regexp_value, this_to_string_value, false); - ecma_deref_ecma_string (this_string_p); - ecma_deref_object (regexp_obj_p); - return ret_value; - } - - /* 8.a. */ - ecma_string_t *index_zero_string_p = ecma_get_ecma_string_from_uint32 (0); - - ecma_value_t put_value = ecma_op_object_put (regexp_obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ecma_make_integer_value (0), - true); - - JERRY_ASSERT (ecma_is_value_boolean (put_value) - || ecma_is_value_empty (put_value) - || ECMA_IS_VALUE_ERROR (put_value)); - - - if (ECMA_IS_VALUE_ERROR (put_value)) - { - ecma_deref_ecma_string (this_string_p); - ecma_deref_object (regexp_obj_p); - return put_value; - } - - /* 8.b. */ - ecma_value_t new_array_value = ecma_op_create_array_object (NULL, 0, false); - - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array_value)); - - ecma_object_t *new_array_obj_p = ecma_get_object_from_value (new_array_value); - - /* 8.c. */ - ecma_number_t previous_last_index = 0; - /* 8.d. */ - uint32_t n = 0; - /* 8.e. */ - bool last_match = true; - - /* 8.f. */ - while (last_match && ecma_is_value_empty (ret_value)) - { - /* 8.f.i. */ - ecma_value_t exec_value = ecma_regexp_exec_helper (regexp_value, this_to_string_value, false); - - if (ECMA_IS_VALUE_ERROR (exec_value)) - { - break; - } - - if (ecma_is_value_null (exec_value)) - { - /* 8.f.ii. */ - break; - } - - /* 8.f.iii. */ - ECMA_TRY_CATCH (this_index_value, - ecma_op_object_get_by_magic_id (regexp_obj_p, LIT_MAGIC_STRING_LASTINDEX_UL), - ret_value); - - ECMA_TRY_CATCH (this_index_number, - ecma_op_to_number (this_index_value), - ret_value); - - ecma_number_t this_index = ecma_get_number_from_value (this_index_number); - - /* 8.f.iii.2. */ - if (this_index == previous_last_index) - { - /* 8.f.iii.2.a. */ - ECMA_TRY_CATCH (index_put_value, - ecma_op_object_put (regexp_obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ecma_make_number_value (this_index + 1), - true), - ret_value); - - /* 8.f.iii.2.b. */ - previous_last_index = this_index + 1; - - ECMA_FINALIZE (index_put_value); - } - else - { - /* 8.f.iii.3. */ - previous_last_index = this_index; - } - - if (ecma_is_value_empty (ret_value)) - { - /* 8.f.iii.4. */ - JERRY_ASSERT (ecma_is_value_object (exec_value)); - ecma_object_t *exec_obj_p = ecma_get_object_from_value (exec_value); - - ECMA_TRY_CATCH (match_string_value, - ecma_op_object_get (exec_obj_p, index_zero_string_p), - ret_value); - - ecma_string_t *current_index_str_p = ecma_new_ecma_string_from_uint32 (n); - - /* 8.f.iii.5. */ - ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_obj_p, - current_index_str_p, - match_string_value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (completion)); - - ecma_deref_ecma_string (current_index_str_p); - - /* 8.f.iii.6. */ - n++; - - ECMA_FINALIZE (match_string_value); - } - - ECMA_FINALIZE (this_index_number); - - ECMA_FINALIZE (this_index_value); - - ecma_free_value (exec_value); - } - - if (ecma_is_value_empty (ret_value)) - { - if (n == 0) - { - /* 8.g. */ - ret_value = ECMA_VALUE_NULL; - } - else - { - /* 8.h. */ - ret_value = ecma_copy_value (new_array_value); - } - } - - ecma_deref_object (new_array_obj_p); - - ecma_deref_object (regexp_obj_p); - ecma_deref_ecma_string (this_string_p); + ecma_deref_ecma_string (this_str_p); + ecma_free_value (new_regexp); return ret_value; + +#else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (regexp_arg)) + { + return ecma_regexp_match_helper (regexp_arg, this_argument); + } + + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); + + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (regexp_obj_p, regexp_arg, ECMA_VALUE_UNDEFINED); + + if (ECMA_IS_VALUE_ERROR (new_regexp)) + { + ecma_deref_object (regexp_obj_p); + return new_regexp; + } + + ecma_value_t result = ecma_regexp_match_helper (new_regexp, this_argument); + + ecma_free_value (new_regexp); + + return result; +#endif /* ENABLED (JERRY_ES2015) */ } /* ecma_builtin_string_prototype_object_match */ -/** - * This structure is the context which represents - * the state of the ongoing string replace. - */ -typedef struct -{ - /* General part. */ - bool is_regexp; /**< whether we search a regexp or string */ - bool is_global; /**< global search or not */ - bool is_replace_callable; /**< replace part is callable or not */ - ecma_value_t input_string; /**< input string */ - ecma_length_t input_length; /**< input string length */ - ecma_value_t regexp_or_search_string; /**< regular expression or search string - * depending on the value of is_regexp */ - ecma_length_t match_start; /**< starting position of the match */ - ecma_length_t match_end; /**< end position of the match */ - - /* Replace value callable part. */ - ecma_object_t *replace_function_p; /**< replace function */ - - /* Replace value string part. */ - ecma_string_t *replace_string_p; /**< replace string */ - lit_utf8_byte_t *replace_str_curr_p; /**< replace string iterator */ -} ecma_builtin_replace_search_ctx_t; - -/** - * Generic helper function to append a substring at the end of a base string - * - * @return the constructed string - */ -static ecma_string_t * -ecma_builtin_string_prototype_object_replace_append_substr (ecma_string_t *base_string_p, /**< base string */ - ecma_string_t *appended_string_p, /**< appended string */ - ecma_length_t start, /**< start position */ - ecma_length_t end) /**< end position */ -{ - JERRY_ASSERT (start <= end); - JERRY_ASSERT (end <= ecma_string_get_length (appended_string_p)); - - if (start < end) - { - ecma_string_t *substring_p = ecma_string_substr (appended_string_p, start, end); - - base_string_p = ecma_concat_ecma_strings (base_string_p, substring_p); - - ecma_deref_ecma_string (substring_p); - } - - return base_string_p; -} /* ecma_builtin_string_prototype_object_replace_append_substr */ - -/** - * Generic helper function to perform the find the next match - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_string_prototype_object_replace_match (ecma_builtin_replace_search_ctx_t *context_p) /**< search - * context */ -{ - context_p->match_start = 0; - context_p->match_end = 0; - - if (context_p->is_regexp) - { - ecma_value_t match_value = ecma_regexp_exec_helper (context_p->regexp_or_search_string, - context_p->input_string, - false); - - if (ECMA_IS_VALUE_ERROR (match_value)) - { - return match_value; - } - - if (ecma_is_value_null (match_value)) - { - return match_value; - } - - JERRY_ASSERT (ecma_is_value_object (match_value)); - - ecma_object_t *match_object_p = ecma_get_object_from_value (match_value); - - ecma_value_t index_value = ecma_op_object_get_by_magic_id (match_object_p, LIT_MAGIC_STRING_INDEX); - - if (ECMA_IS_VALUE_ERROR (index_value)) - { - ecma_deref_object (match_object_p); - return index_value; - } - - JERRY_ASSERT (ecma_is_value_number (index_value)); - ecma_value_t result_string_value = ecma_op_object_get (match_object_p, ecma_get_ecma_string_from_uint32 (0)); - - if (ECMA_IS_VALUE_ERROR (result_string_value)) - { - ecma_free_number (index_value); - ecma_deref_object (match_object_p); - return result_string_value; - } - - /* We directly call the built-in exec, so - * we can trust in the returned value. */ - - JERRY_ASSERT (ecma_is_value_string (result_string_value)); - - /* We use the length of the result string to determine the - * match end. This works regardless the global flag is set. */ - ecma_string_t *result_string_p = ecma_get_string_from_value (result_string_value); - ecma_number_t index_number = ecma_get_number_from_value (index_value); - - context_p->match_start = (ecma_length_t) (index_number); - context_p->match_end = context_p->match_start + (ecma_length_t) ecma_string_get_length (result_string_p); - - JERRY_ASSERT ((ecma_length_t) ecma_number_to_uint32 (index_number) == context_p->match_start); - - ecma_deref_ecma_string (result_string_p); - ecma_free_number (index_value); - - return match_value; - } - - JERRY_ASSERT (!context_p->is_global); - - ecma_string_t *search_string_p = ecma_get_string_from_value (context_p->regexp_or_search_string); - ecma_string_t *input_string_p = ecma_get_string_from_value (context_p->input_string); - - ecma_length_t index_of = 0; - if (ecma_builtin_helper_string_find_index (input_string_p, search_string_p, true, 0, &index_of)) - { - ecma_value_t arguments_list_p[1] = { context_p->regexp_or_search_string }; - - context_p->match_start = index_of; - context_p->match_end = index_of + ecma_string_get_length (search_string_p); - - return ecma_op_create_array_object (arguments_list_p, 1, false); - } - - return ECMA_VALUE_NULL; -} /* ecma_builtin_string_prototype_object_replace_match */ - -/** - * Generic helper function to construct the string which replaces the matched part - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_string_prototype_object_replace_get_string (ecma_builtin_replace_search_ctx_t *context_p, /**< search - * context */ - ecma_value_t match_value) /**< returned match value */ -{ - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_object_t *match_object_p = ecma_get_object_from_value (match_value); - - ecma_value_t match_length_value = ecma_op_object_get_by_magic_id (match_object_p, LIT_MAGIC_STRING_LENGTH); - - if (ECMA_IS_VALUE_ERROR (match_length_value)) - { - return match_length_value; - } - - JERRY_ASSERT (ecma_is_value_number (match_length_value)); - - ecma_number_t match_length_number = ecma_get_number_from_value (match_length_value); - ecma_length_t match_length = (ecma_length_t) (match_length_number); - - JERRY_ASSERT ((ecma_length_t) ecma_number_to_uint32 (match_length_number) == match_length); - JERRY_ASSERT (match_length >= 1); - - if (context_p->is_replace_callable) - { - JMEM_DEFINE_LOCAL_ARRAY (arguments_list, - match_length + 2, - ecma_value_t); - - /* An error might occure during the array copy and - * uninitalized elements must not be freed. */ - ecma_length_t values_copied = 0; - - for (ecma_length_t i = 0; - (i < match_length) && ecma_is_value_empty (ret_value); - i++) - { - ecma_string_t *index_p = ecma_new_ecma_string_from_uint32 (i); - ECMA_TRY_CATCH (current_value, - ecma_op_object_get (match_object_p, index_p), - ret_value); - - arguments_list[i] = ecma_copy_value (current_value); - values_copied++; - - ECMA_FINALIZE (current_value); - ecma_deref_ecma_string (index_p); - } - - if (ecma_is_value_empty (ret_value)) - { - arguments_list[match_length] = ecma_make_uint32_value (context_p->match_start); - arguments_list[match_length + 1] = ecma_copy_value (context_p->input_string); - - ECMA_TRY_CATCH (result_value, - ecma_op_function_call (context_p->replace_function_p, - ECMA_VALUE_UNDEFINED, - arguments_list, - match_length + 2), - ret_value); - - ECMA_TRY_CATCH (to_string_value, - ecma_op_to_string (result_value), - ret_value); - - ret_value = ecma_copy_value (to_string_value); - - ECMA_FINALIZE (to_string_value); - ECMA_FINALIZE (result_value); - - ecma_free_value (arguments_list[match_length + 1]); - } - - for (ecma_length_t i = 0; i < values_copied; i++) - { - ecma_free_value (arguments_list[i]); - } - - JMEM_FINALIZE_LOCAL_ARRAY (arguments_list); - } - else - { - /* Although the ECMA standard does not specify how $nn (n is a decimal - * number) captures should be replaced if nn is greater than the maximum - * capture index, we follow the test-262 expected behaviour: - * - * if maximum capture index is < 10 - * we replace only those $n and $0n captures, where n < maximum capture index - * otherwise - * we replace only those $nn captures, where nn < maximum capture index - * - * other $n $nn sequences left unchanged - * - * example: "".replace(/(x)y/, "$1,$2,$01,$12") === "" - */ - - ecma_string_t *result_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - - ecma_length_t previous_start = 0; - ecma_length_t current_position = 0; - - lit_utf8_byte_t *replace_str_curr_p = context_p->replace_str_curr_p; - lit_utf8_byte_t *replace_str_end_p = replace_str_curr_p + ecma_string_get_size (context_p->replace_string_p); - - while (replace_str_curr_p < replace_str_end_p) - { - ecma_char_t action = LIT_CHAR_NULL; - - if (*replace_str_curr_p != LIT_CHAR_DOLLAR_SIGN) - { - /* if not a continuation byte */ - if ((*replace_str_curr_p & LIT_UTF8_EXTRA_BYTE_MASK) != LIT_UTF8_EXTRA_BYTE_MARKER) - { - current_position++; - } - replace_str_curr_p++; - continue; - } - - replace_str_curr_p++; - - if (replace_str_curr_p < replace_str_end_p) - { - action = *replace_str_curr_p; - - if (action == LIT_CHAR_DOLLAR_SIGN) - { - current_position++; - } - else if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9) - { - uint32_t index = 0; - - index = (uint32_t) (action - LIT_CHAR_0); - - if (index >= match_length) - { - action = LIT_CHAR_NULL; - } - else if (index == 0 || match_length > 10) - { - replace_str_curr_p++; - - if (replace_str_curr_p < replace_str_end_p) - { - ecma_char_t next_character = *replace_str_curr_p; - - if (next_character >= LIT_CHAR_0 && next_character <= LIT_CHAR_9) - { - uint32_t full_index = index * 10 + (uint32_t) (next_character - LIT_CHAR_0); - if (full_index > 0 && full_index < match_length) - { - index = match_length; - } - } - } - - replace_str_curr_p--; - - if (index == 0) - { - action = LIT_CHAR_NULL; - } - } - } - else if (action != LIT_CHAR_AMPERSAND - && action != LIT_CHAR_GRAVE_ACCENT - && action != LIT_CHAR_SINGLE_QUOTE) - { - action = LIT_CHAR_NULL; - } - } - - if (action != LIT_CHAR_NULL) - { - result_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - context_p->replace_string_p, - previous_start, - current_position); - replace_str_curr_p++; - current_position++; - - if (action == LIT_CHAR_DOLLAR_SIGN) - { - current_position--; - } - else if (action == LIT_CHAR_GRAVE_ACCENT) - { - ecma_string_t *input_string_p = ecma_get_string_from_value (context_p->input_string); - result_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - input_string_p, - 0, - context_p->match_start); - } - else if (action == LIT_CHAR_SINGLE_QUOTE) - { - ecma_string_t *input_string_p = ecma_get_string_from_value (context_p->input_string); - result_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - input_string_p, - context_p->match_end, - context_p->input_length); - } - else - { - /* Everything else is submatch reading. */ - uint32_t index = 0; - - JERRY_ASSERT (action == LIT_CHAR_AMPERSAND || (action >= LIT_CHAR_0 && action <= LIT_CHAR_9)); - - if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9) - { - index = (uint32_t) (action - LIT_CHAR_0); - - if ((match_length > 10 || index == 0) - && replace_str_curr_p < replace_str_end_p) - { - action = *replace_str_curr_p; - if (action >= LIT_CHAR_0 && action <= LIT_CHAR_9) - { - uint32_t full_index = index * 10 + (uint32_t) (action - LIT_CHAR_0); - if (full_index < match_length) - { - index = full_index; - replace_str_curr_p++; - current_position++; - } - } - } - JERRY_ASSERT (index > 0 && index < match_length); - } - - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - - ECMA_TRY_CATCH (submatch_value, - ecma_op_object_get (match_object_p, index_string_p), - ret_value); - - /* Undefined values are converted to empty string. */ - if (!ecma_is_value_undefined (submatch_value)) - { - JERRY_ASSERT (ecma_is_value_string (submatch_value)); - ecma_string_t *submatch_string_p = ecma_get_string_from_value (submatch_value); - - result_string_p = ecma_concat_ecma_strings (result_string_p, submatch_string_p); - } - - ECMA_FINALIZE (submatch_value); - ecma_deref_ecma_string (index_string_p); - - if (!ecma_is_value_empty (ret_value)) - { - break; - } - } - - current_position++; - previous_start = current_position; - } - else - { - current_position++; - } - } - - if (ecma_is_value_empty (ret_value)) - { - result_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - context_p->replace_string_p, - previous_start, - current_position); - - ret_value = ecma_make_string_value (result_string_p); - } - } - - ecma_free_number (match_length_value); - - return ret_value; -} /* ecma_builtin_string_prototype_object_replace_get_string */ - -/** - * Generic helper function to do the string replace - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_string_prototype_object_replace_loop (ecma_builtin_replace_search_ctx_t *context_p) /**< search - * context */ -{ - ecma_length_t previous_start = 0; - - ecma_string_t *result_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ecma_string_t *input_string_p = ecma_get_string_from_value (context_p->input_string); - - while (true) - { - ecma_value_t match_value = ecma_builtin_string_prototype_object_replace_match (context_p); - - if (ECMA_IS_VALUE_ERROR (match_value)) - { - break; - } - - if (!ecma_is_value_null (match_value)) - { - result_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - input_string_p, - previous_start, - context_p->match_start); - - ecma_value_t string_value = ecma_builtin_string_prototype_object_replace_get_string (context_p, match_value); - - if (ECMA_IS_VALUE_ERROR (string_value)) - { - ecma_free_value (match_value); - break; - } - - JERRY_ASSERT (ecma_is_value_string (string_value)); - - ecma_string_t *string_p = ecma_get_string_from_value (string_value); - - result_string_p = ecma_concat_ecma_strings (result_string_p, string_p); - - ecma_deref_ecma_string (string_p); - - previous_start = context_p->match_end; - - if (context_p->is_global - && context_p->match_start == context_p->match_end) - { - JERRY_ASSERT (context_p->is_regexp); - - if (context_p->match_end == context_p->input_length) - { - /* Aborts the match. */ - context_p->is_global = false; - } - else - { - ecma_object_t *regexp_obj_p = ecma_get_object_from_value (context_p->regexp_or_search_string); - - ecma_value_t put_value = ecma_op_object_put (regexp_obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ecma_make_uint32_value (context_p->match_end + 1), - true); - - JERRY_ASSERT (ecma_is_value_boolean (put_value) - || ecma_is_value_empty (put_value) - || ECMA_IS_VALUE_ERROR (put_value)); - - if (ECMA_IS_VALUE_ERROR (put_value)) - { - ecma_free_value (match_value); - break; - } - } - } - } - - ecma_free_value (match_value); - - if (!context_p->is_global || ecma_is_value_null (match_value)) - { - /* No more matches */ - ecma_string_t *appended_string_p; - - appended_string_p = ecma_builtin_string_prototype_object_replace_append_substr (result_string_p, - input_string_p, - previous_start, - context_p->input_length); - return ecma_make_string_value (appended_string_p); - } - } - - ecma_deref_ecma_string (result_string_p); - - return ECMA_VALUE_ERROR; -} /* ecma_builtin_string_prototype_object_replace_loop */ - -/** - * Generic helper function to check whether the search value is callable. - * If it is not, the function converts the search value to string. The - * appropriate fields of the context were filled as well and the search - * loop is run afterwards. - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_string_prototype_object_replace_main (ecma_builtin_replace_search_ctx_t *context_p, /**< search - * context */ - ecma_value_t replace_value) /**< replacement for a match */ -{ - if (ecma_op_is_callable (replace_value)) - { - context_p->is_replace_callable = true; - context_p->replace_function_p = ecma_get_object_from_value (replace_value); - - return ecma_builtin_string_prototype_object_replace_loop (context_p); - } - - - context_p->is_replace_callable = false; - - ecma_value_t to_string_replace_val = ecma_op_to_string (replace_value); - - if (ECMA_IS_VALUE_ERROR (to_string_replace_val)) - { - return to_string_replace_val; - } - - ecma_value_t ret_value; - ecma_string_t *replace_string_p = ecma_get_string_from_value (to_string_replace_val); - - ECMA_STRING_TO_UTF8_STRING (replace_string_p, replace_start_p, replace_start_size); - - context_p->replace_string_p = replace_string_p; - context_p->replace_str_curr_p = (lit_utf8_byte_t *) replace_start_p; - - ret_value = ecma_builtin_string_prototype_object_replace_loop (context_p); - - ECMA_FINALIZE_UTF8_STRING (replace_start_p, replace_start_size); - ecma_deref_ecma_string (replace_string_p); - - return ret_value; -} /* ecma_builtin_string_prototype_object_replace_main */ - /** * The String.prototype object's 'replace' routine * - * The replace algorithm is splitted into several helper functions. - * This allows using ECMA_TRY_CATCH macros and avoiding early returns. - * - * To share data between these helper functions, we created a - * structure called ecma_builtin_replace_search_ctx_t, which - * represents the current state of the replace. - * - * The helper functions are called in the following order: - * - * 1) ecma_builtin_string_prototype_object_replace is called - * it initialise the context depending on search_value (regexp or string) - * 2) ecma_builtin_string_prototype_object_replace_main is called - * it initialise the context depending on replace_value (callable or string) - * 3) ecma_builtin_string_prototype_object_replace_loop is called - * this function has a loop which repeatedly calls - * - ecma_builtin_string_prototype_object_replace_match - * which performs a match - * - ecma_builtin_string_prototype_object_replace_get_string - * which computes the replacement string - * - * The final string is created from several string fragments appended - * together by ecma_builtin_string_prototype_object_replace_append_substr. - * * See also: * ECMA-262 v5, 15.5.4.11 + * ECMA-262 v6, 21.1.3.14 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_string_prototype_object_replace (ecma_value_t to_string_value, /**< this argument */ +ecma_builtin_string_prototype_object_replace (ecma_value_t this_value, /**< this argument */ ecma_value_t search_value, /**< routine's first argument */ ecma_value_t replace_value) /**< routine's second argument */ { - ecma_builtin_replace_search_ctx_t context; - - if (ecma_is_value_object (search_value) - && ecma_object_class_is (ecma_get_object_from_value (search_value), LIT_MAGIC_STRING_REGEXP_UL)) +#if ENABLED (JERRY_ES2015) + if (!(ecma_is_value_undefined (search_value) || ecma_is_value_null (search_value))) { - ecma_object_t *regexp_obj_p = ecma_get_object_from_value (search_value); + ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (search_value)); + ecma_value_t replace_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_REPLACE); + ecma_deref_object (obj_p); - ecma_value_t global_value = ecma_op_object_get_by_magic_id (regexp_obj_p, LIT_MAGIC_STRING_GLOBAL); - - if (ECMA_IS_VALUE_ERROR (global_value)) + if (ECMA_IS_VALUE_ERROR (replace_symbol)) { - return global_value; + return replace_symbol; } - JERRY_ASSERT (ecma_is_value_boolean (global_value)); - - context.is_regexp = true; - context.is_global = ecma_is_value_true (global_value); - context.input_string = to_string_value; - context.input_length = ecma_string_get_length (ecma_get_string_from_value (to_string_value)); - context.regexp_or_search_string = search_value; - - if (context.is_global) + if (!ecma_is_value_undefined (replace_symbol) && !ecma_is_value_null (replace_symbol)) { - ecma_value_t put_value = ecma_op_object_put (regexp_obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ecma_make_integer_value (0), - true); - - JERRY_ASSERT (ecma_is_value_boolean (put_value) - || ecma_is_value_empty (put_value) - || ECMA_IS_VALUE_ERROR (put_value)); - - if (ECMA_IS_VALUE_ERROR (put_value)) + if (!ecma_op_is_callable (replace_symbol)) { - return put_value; + ecma_free_value (replace_symbol); + return ecma_raise_type_error (ECMA_ERR_MSG ("@@replace is not callable")); + } + + ecma_object_t *replace_method = ecma_get_object_from_value (replace_symbol); + + ecma_value_t arguments[] = { this_value, replace_value }; + ecma_value_t replace_result = ecma_op_function_call (replace_method, search_value, arguments, 2); + + ecma_deref_object (replace_method); + return replace_result; + } + } +#else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (search_value)) + { + return ecma_regexp_replace_helper (search_value, this_value, replace_value); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_string_t *input_str_p = ecma_get_string_from_value (this_value); + + ecma_value_t result = ECMA_VALUE_ERROR; + + ecma_string_t *search_str_p = ecma_op_to_string (search_value); + if (search_str_p == NULL) + { + return result; + } + + ecma_replace_context_t replace_ctx; + replace_ctx.capture_count = 0; + replace_ctx.u.captures_p = NULL; + + replace_ctx.replace_str_p = NULL; + if (!ecma_op_is_callable (replace_value)) + { + replace_ctx.replace_str_p = ecma_op_to_string (replace_value); + if (replace_ctx.replace_str_p == NULL) + { + goto cleanup_search; + } + } + + uint8_t input_flags = ECMA_STRING_FLAG_IS_ASCII; + replace_ctx.string_p = ecma_string_get_chars (input_str_p, + &(replace_ctx.string_size), + NULL, + NULL, + &input_flags); + + lit_utf8_size_t search_size; + uint8_t search_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *search_buf_p = ecma_string_get_chars (search_str_p, + &search_size, + NULL, + NULL, + &search_flags); + + ecma_string_t *result_string_p = NULL; + + if (replace_ctx.string_size >= search_size) + { + replace_ctx.matched_size = search_size; + const lit_utf8_byte_t *const input_end_p = replace_ctx.string_p + replace_ctx.string_size; + const lit_utf8_byte_t *const loop_end_p = input_end_p - search_size; + + uint32_t pos = 0; + for (const lit_utf8_byte_t *curr_p = replace_ctx.string_p; + curr_p <= loop_end_p; + lit_utf8_incr (&curr_p), pos++) + { + if (!memcmp (curr_p, search_buf_p, search_size)) + { + const lit_utf8_size_t byte_offset = (lit_utf8_size_t) (curr_p - replace_ctx.string_p); + replace_ctx.builder = ecma_stringbuilder_create_raw (replace_ctx.string_p, byte_offset); + + if (replace_ctx.replace_str_p == NULL) + { + ecma_object_t *function_p = ecma_get_object_from_value (replace_value); + + ecma_value_t args[] = + { + ecma_make_string_value (search_str_p), + ecma_make_uint32_value (pos), + ecma_make_string_value (input_str_p) + }; + + result = ecma_op_function_call (function_p, + ECMA_VALUE_UNDEFINED, + args, + 3); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_stringbuilder_destroy (&replace_ctx.builder); + goto cleanup_replace; + } + + ecma_string_t *const result_str_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (result_str_p == NULL) + { + ecma_stringbuilder_destroy (&replace_ctx.builder); + result = ECMA_VALUE_ERROR; + goto cleanup_replace; + } + + ecma_stringbuilder_append (&replace_ctx.builder, result_str_p); + ecma_deref_ecma_string (result_str_p); + } + else + { + replace_ctx.matched_p = curr_p; + replace_ctx.match_byte_pos = byte_offset; + + ecma_builtin_replace_substitute (&replace_ctx); + } + + const lit_utf8_byte_t *const match_end_p = curr_p + search_size; + ecma_stringbuilder_append_raw (&replace_ctx.builder, + match_end_p, + (lit_utf8_size_t) (input_end_p - match_end_p)); + result_string_p = ecma_stringbuilder_finalize (&replace_ctx.builder); + break; } } - - return ecma_builtin_string_prototype_object_replace_main (&context, replace_value); } - ecma_value_t to_string_search_val = ecma_op_to_string (search_value); - - if (ECMA_IS_VALUE_ERROR (to_string_search_val)) + if (result_string_p == NULL) { - return to_string_search_val; + ecma_ref_ecma_string (input_str_p); + result_string_p = input_str_p; } - context.is_regexp = false; - context.is_global = false; - context.input_string = to_string_value; - context.input_length = ecma_string_get_length (ecma_get_string_from_value (to_string_value)); - context.regexp_or_search_string = to_string_search_val; + result = ecma_make_string_value (result_string_p); - ecma_value_t ret_value = ecma_builtin_string_prototype_object_replace_main (&context, replace_value); +cleanup_replace: + if (input_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) replace_ctx.string_p, replace_ctx.string_size); + } - ecma_deref_ecma_string (ecma_get_string_from_value (to_string_search_val)); + if (search_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) search_buf_p, search_size); + } - return ret_value; + if (replace_ctx.replace_str_p != NULL) + { + ecma_deref_ecma_string (replace_ctx.replace_str_p); + } + +cleanup_search: + ecma_deref_ecma_string (search_str_p); + return result; } /* ecma_builtin_string_prototype_object_replace */ /** @@ -1184,67 +572,113 @@ ecma_builtin_string_prototype_object_replace (ecma_value_t to_string_value, /**< * * See also: * ECMA-262 v5, 15.5.4.12 + * ECMA-262 v6, 21.1.3.15 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_string_prototype_object_search (ecma_value_t to_string_value, /**< this argument */ - ecma_value_t regexp_arg) /**< routine's argument */ +ecma_builtin_string_prototype_object_search (ecma_value_t this_value, /**< this argument */ + ecma_value_t regexp_value) /**< routine's argument */ { - - ecma_value_t regexp_value = ECMA_VALUE_EMPTY; - - ecma_value_t ret_value = ecma_builtin_string_prepare_search (regexp_arg, ®exp_value); - - if (ECMA_IS_VALUE_ERROR (ret_value)) +#if ENABLED (JERRY_ES2015) + if (!(ecma_is_value_undefined (regexp_value) || ecma_is_value_null (regexp_value))) { - return ret_value; + ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (regexp_value)); + ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SEARCH); + ecma_deref_object (obj_p); + + if (ECMA_IS_VALUE_ERROR (search_symbol)) + { + return search_symbol; + } + + if (!ecma_is_value_undefined (search_symbol) && !ecma_is_value_null (search_symbol)) + { + if (!ecma_op_is_callable (search_symbol)) + { + ecma_free_value (search_symbol); + return ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable")); + } + + ecma_object_t *search_method = ecma_get_object_from_value (search_symbol); + ecma_value_t search_result = ecma_op_function_call (search_method, regexp_value, &this_value, 1); + + ecma_deref_object (search_method); + return search_result; + } + } +#else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (regexp_value)) + { + return ecma_regexp_search_helper (regexp_value, this_value); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t result = ECMA_VALUE_ERROR; + + ecma_string_t *string_p = ecma_op_to_string (this_value); + if (string_p == NULL) + { + return result; } - /* 5. */ - ecma_string_t *this_string_p = ecma_get_string_from_value (to_string_value); - ecma_ref_ecma_string (this_string_p); - - ecma_value_t match_result = ecma_regexp_exec_helper (regexp_value, to_string_value, true); - - if (ECMA_IS_VALUE_ERROR (match_result)) + ecma_string_t *pattern_p = ecma_regexp_read_pattern_str_helper (regexp_value); + if (pattern_p == NULL) { - ecma_free_value (regexp_value); - ecma_deref_ecma_string (this_string_p); - return match_result; + goto cleanup_string; } - ecma_number_t offset = -1; + ecma_object_t *new_regexp_obj_p = ecma_op_regexp_alloc (NULL); - if (!ecma_is_value_null (match_result)) + if (JERRY_UNLIKELY (new_regexp_obj_p == NULL)) { - JERRY_ASSERT (ecma_is_value_object (match_result)); - - ecma_object_t *match_object_p = ecma_get_object_from_value (match_result); - - ECMA_TRY_CATCH (index_value, - ecma_op_object_get_by_magic_id (match_object_p, LIT_MAGIC_STRING_INDEX), - ret_value); - - JERRY_ASSERT (ecma_is_value_number (index_value)); - - offset = ecma_get_number_from_value (index_value); - - ECMA_FINALIZE (index_value); + ecma_deref_ecma_string (string_p); + ecma_deref_ecma_string (pattern_p); + return ECMA_VALUE_ERROR; } - if (ecma_is_value_empty (ret_value)) + ecma_value_t new_regexp = ecma_op_create_regexp_from_pattern (new_regexp_obj_p, + ecma_make_string_value (pattern_p), + ECMA_VALUE_UNDEFINED); + + ecma_deref_ecma_string (pattern_p); + + if (ECMA_IS_VALUE_ERROR (new_regexp)) { - ret_value = ecma_make_number_value (offset); + ecma_deref_object (new_regexp_obj_p); + goto cleanup_string; } - ecma_free_value (match_result); - ecma_free_value (regexp_value); - ecma_deref_ecma_string (this_string_p); +#if !ENABLED (JERRY_ES2015) + result = ecma_regexp_search_helper (new_regexp, ecma_make_string_value (string_p)); + ecma_deref_object (ecma_get_object_from_value (new_regexp)); +#else /* ENABLED (JERRY_ES2015) */ + ecma_object_t *regexp_obj_p = ecma_get_object_from_value (new_regexp); + ecma_value_t search_symbol = ecma_op_object_get_by_symbol_id (regexp_obj_p, LIT_GLOBAL_SYMBOL_SEARCH); + if (ECMA_IS_VALUE_ERROR (search_symbol)) + { + goto cleanup_regexp; + } - /* 6. */ - return ret_value; + if (!ecma_op_is_callable (search_symbol)) + { + result = ecma_raise_type_error (ECMA_ERR_MSG ("@@search is not callable")); + goto cleanup_regexp; + } + + ecma_object_t *search_method_p = ecma_get_object_from_value (search_symbol); + ecma_value_t arguments[] = { ecma_make_string_value (string_p) }; + result = ecma_op_function_call (search_method_p, new_regexp, arguments, 1); + ecma_deref_object (search_method_p); + +cleanup_regexp: + ecma_deref_object (regexp_obj_p); +#endif /* !ENABLED (JERRY_ES2015) */ + +cleanup_string: + ecma_deref_ecma_string (string_p); + return result; } /* ecma_builtin_string_prototype_object_search */ #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ @@ -1265,18 +699,16 @@ ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< { const ecma_length_t len = ecma_string_get_length (get_string_val); - /* 4. */ + /* 4. 6. */ ecma_length_t start = 0, end = len; - ecma_number_t start_num; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg1, &start_num))) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg1, + len, + &start))) { return ECMA_VALUE_ERROR; } - start = ecma_builtin_helper_array_index_normalize (start_num, len, false); - /* 5. 7. */ if (ecma_is_value_undefined (arg2)) { @@ -1284,14 +716,12 @@ ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< } else { - ecma_number_t end_num; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg2, &end_num))) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (arg2, + len, + &end))) { return ECMA_VALUE_ERROR; } - - end = ecma_builtin_helper_array_index_normalize (end_num, len, false); } JERRY_ASSERT (start <= len && end <= len); @@ -1302,7 +732,6 @@ ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< return ecma_make_string_value (new_str_p); } /* ecma_builtin_string_prototype_object_slice */ - /** * The String.prototype object's 'split' routine * @@ -1313,374 +742,185 @@ ecma_builtin_string_prototype_object_slice (ecma_string_t *get_string_val, /**< * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_string_prototype_object_split (ecma_value_t this_to_string_val, /**< this argument */ - ecma_value_t arg1, /**< separator */ - ecma_value_t arg2) /**< limit */ +ecma_builtin_string_prototype_object_split (ecma_value_t this_value, /**< this argument */ + ecma_value_t separator_value, /**< separator */ + ecma_value_t limit_value) /**< limit */ { - /* 5. */ - ecma_length_t limit = 0; - - if (ecma_is_value_undefined (arg2)) +#if ENABLED (JERRY_ES2015) + if (!(ecma_is_value_undefined (separator_value) || ecma_is_value_null (separator_value))) { - limit = (uint32_t) -1; - } - else - { - ecma_number_t limit_num; + ecma_object_t *obj_p = ecma_get_object_from_value (ecma_op_to_object (separator_value)); + ecma_value_t split_symbol = ecma_op_object_get_by_symbol_id (obj_p, LIT_GLOBAL_SYMBOL_SPLIT); + ecma_deref_object (obj_p); - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg2, &limit_num))) + if (ECMA_IS_VALUE_ERROR (split_symbol)) { - return ECMA_VALUE_ERROR; + return split_symbol; } - limit = ecma_number_to_uint32 (limit_num); + if (!ecma_is_value_undefined (split_symbol) && !ecma_is_value_null (split_symbol)) + { + if (!ecma_op_is_callable (split_symbol)) + { + ecma_free_value (split_symbol); + return ecma_raise_type_error (ECMA_ERR_MSG ("@@split is not callable")); + } + + ecma_object_t *split_method_p = ecma_get_object_from_value (split_symbol); + + ecma_value_t arguments[] = { this_value, limit_value }; + ecma_value_t split_result = ecma_op_function_call (split_method_p, separator_value, arguments, 2); + + ecma_deref_object (split_method_p); + return split_result; + } } - - /* 3. */ - ecma_value_t new_array = ecma_op_create_array_object (0, 0, false); - - if (limit == 0) +#else /* !ENABLED (JERRY_ES2015) */ + if (ecma_object_is_regexp_object (separator_value)) { - return new_array; +#if ENABLED (JERRY_BUILTIN_REGEXP) + return ecma_regexp_split_helper (separator_value, this_value, limit_value); +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ } +#endif /* ENABLED (JERRY_ES2015) */ - ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_value_t result = ECMA_VALUE_ERROR; - ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); - - /* 10. */ - if (ecma_is_value_undefined (arg1)) + /* 4. */ + ecma_string_t *string_p = ecma_op_to_string (this_value); + if (string_p == NULL) { - ecma_string_t *zero_str_p = ecma_new_ecma_string_from_number (ECMA_NUMBER_ZERO); - - ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, - zero_str_p, - this_to_string_val, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - ecma_deref_ecma_string (zero_str_p); - - return new_array; + return result; } /* 8. */ - ecma_value_t separator = ECMA_VALUE_EMPTY; - - bool separator_is_regexp = false; - - if (ecma_is_value_object (arg1) - && ecma_object_class_is (ecma_get_object_from_value (arg1), LIT_MAGIC_STRING_REGEXP_UL)) + uint32_t limit = UINT32_MAX; + if (!ecma_is_value_undefined (limit_value)) { - separator_is_regexp = true; - separator = ecma_copy_value (arg1); - } - else - { - ECMA_TRY_CATCH (separator_to_string_val, - ecma_op_to_string (arg1), - ret_value); - - separator = ecma_copy_value (separator_to_string_val); - - ECMA_FINALIZE (separator_to_string_val); - } - - const ecma_string_t *this_to_string_p = ecma_get_string_from_value (this_to_string_val); - - /* 11. */ - if (ecma_string_is_empty (this_to_string_p) && ecma_is_value_empty (ret_value)) - { - bool should_return = false; - - if (separator_is_regexp) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (limit_value, &limit))) { -#if ENABLED (JERRY_BUILTIN_REGEXP) - ecma_value_t regexp_value = ecma_copy_value_if_not_object (separator); - ecma_value_t match_result; - match_result = ecma_regexp_exec_helper (regexp_value, - ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY), - true); - should_return = !ecma_is_value_null (match_result); - - if (ECMA_IS_VALUE_ERROR (match_result)) - { - match_result = JERRY_CONTEXT (error_value); - } - - ecma_free_value (match_result); -#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ - return ecma_raise_type_error (ECMA_ERR_MSG ("REGEXP separator is disabled in split method.")); -#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ - } - else - { - ecma_string_t *separator_str_p = ecma_get_string_from_value (separator); - - if (ecma_string_get_length (separator_str_p) == 0) - { - should_return = true; - } - } - - if (!should_return) - { - /* 11.c */ - ecma_string_t *zero_str_p = ecma_new_ecma_string_from_number (ECMA_NUMBER_ZERO); - - ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, - zero_str_p, - this_to_string_val, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - ecma_deref_ecma_string (zero_str_p); - } - } - else - { - /* 4. */ - ecma_length_t new_array_length = 0; - - /* 7. */ - ecma_length_t start_pos = 0; - - /* 12. */ - ecma_length_t curr_pos = start_pos; - - bool separator_is_empty = false; - bool should_return = false; - - /* 6. */ - const ecma_length_t string_length = ecma_string_get_length (this_to_string_p); - - while (curr_pos < string_length && !should_return && ecma_is_value_empty (ret_value)) - { - ecma_value_t match_result = ECMA_VALUE_NULL; - - if (separator_is_regexp) - { -#if ENABLED (JERRY_BUILTIN_REGEXP) - ecma_value_t regexp_value = ecma_copy_value_if_not_object (separator); - ecma_string_t *substr_str_p = ecma_string_substr (this_to_string_p, curr_pos, string_length); - match_result = ecma_regexp_exec_helper (regexp_value, ecma_make_string_value (substr_str_p), true); - ecma_deref_ecma_string (substr_str_p); -#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ - return ecma_raise_type_error (ECMA_ERR_MSG ("REGEXP separator is disabled in split method.")); -#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ - } - else - { - ecma_string_t *separator_str_p = ecma_get_string_from_value (separator); - ecma_length_t separator_length = ecma_string_get_length (separator_str_p); - - if (curr_pos + separator_length <= string_length) - { - bool is_different = false; - for (ecma_length_t i = 0; i < separator_length && !is_different; i++) - { - ecma_char_t char_from_string = ecma_string_get_char_at_pos (this_to_string_p, curr_pos + i); - ecma_char_t char_from_separator = ecma_string_get_char_at_pos (separator_str_p, i); - is_different = (char_from_string != char_from_separator); - } - - if (!is_different) - { - /* 6-7. */ - match_result = ecma_op_create_array_object (0, 0, false); - } - } - } - - if (ecma_is_value_null (match_result) || ECMA_IS_VALUE_ERROR (match_result)) - { - curr_pos++; - if (ECMA_IS_VALUE_ERROR (match_result)) - { - ecma_free_value (JERRY_CONTEXT (error_value)); - } - } - else - { - ecma_object_t *match_obj_p = ecma_get_object_from_value (match_result); - ecma_string_t *zero_str_p = ecma_get_ecma_string_from_uint32 (0); - ecma_string_t *magic_index_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INDEX); - ecma_value_t index_prop_value; - - if (separator_is_regexp) - { - JERRY_ASSERT (ecma_get_object_type (match_obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) match_obj_p)->u.array.is_fast_mode); - - ecma_property_value_t *index_prop_value_p = ecma_get_named_data_property (match_obj_p, magic_index_str_p); - ecma_number_t index_num = ecma_get_number_from_value (index_prop_value_p->value); - ecma_value_assign_number (&index_prop_value_p->value, index_num + (ecma_number_t) curr_pos); - index_prop_value = index_prop_value_p->value; - } - else - { - const uint32_t opts = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW; - ecma_string_t *separator_str_p = ecma_get_string_from_value (separator); - - ecma_value_t put_comp = ecma_builtin_helper_def_prop (match_obj_p, - zero_str_p, - ecma_make_string_value (separator_str_p), - opts); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - index_prop_value = ecma_make_uint32_value (curr_pos); - - put_comp = ecma_builtin_helper_def_prop (match_obj_p, - magic_index_str_p, - index_prop_value, - ECMA_PROPERTY_FLAG_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - } - - ecma_value_t match_comp_value = ecma_op_object_get (match_obj_p, zero_str_p); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (match_comp_value)); - - ecma_string_t *match_str_p = ecma_get_string_from_value (match_comp_value); - ecma_length_t match_str_length = ecma_string_get_length (match_str_p); - - separator_is_empty = ecma_string_is_empty (match_str_p); - - ecma_free_value (match_comp_value); - - ecma_number_t index_num = ecma_get_number_from_value (index_prop_value); - JERRY_ASSERT (index_num >= 0); - - - uint32_t end_pos = ecma_number_to_uint32 (index_num); - - if (separator_is_empty) - { - end_pos = curr_pos + 1; - } - - /* 13.c.iii.1-2 */ - ecma_string_t *substr_str_p = ecma_string_substr (this_to_string_p, - start_pos, - end_pos); - - ecma_string_t *array_length_str_p = ecma_new_ecma_string_from_uint32 (new_array_length); - - ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, - array_length_str_p, - ecma_make_string_value (substr_str_p), - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - /* 13.c.iii.3 */ - new_array_length++; - - /* 13.c.iii.4 */ - if (new_array_length == limit && ecma_is_value_empty (ret_value)) - { - should_return = true; - } - - /* 13.c.iii.5 */ - start_pos = end_pos + match_str_length; - - ECMA_TRY_CATCH (array_length_val, - ecma_op_object_get_by_magic_id (match_obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num, array_length_val, ret_value); - - /* The first item is the match object, thus we should skip it. */ - const uint32_t match_result_array_length = ecma_number_to_uint32 (array_length_num) - 1; - - /* 13.c.iii.6 */ - uint32_t i = 0; - - /* 13.c.iii.7 */ - while (i < match_result_array_length && ecma_is_value_empty (ret_value)) - { - /* 13.c.iii.7.a */ - i++; - ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (i); - ecma_string_t *new_array_idx_str_p = ecma_new_ecma_string_from_uint32 (new_array_length); - - match_comp_value = ecma_op_object_get (match_obj_p, idx_str_p); - - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (match_comp_value)); - - /* 13.c.iii.7.b */ - put_comp = ecma_builtin_helper_def_prop (new_array_p, - new_array_idx_str_p, - match_comp_value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - /* 13.c.iii.7.c */ - new_array_length++; - - /* 13.c.iii.7.d */ - if (new_array_length == limit && ecma_is_value_empty (ret_value)) - { - should_return = true; - } - - ecma_free_value (match_comp_value); - ecma_deref_ecma_string (new_array_idx_str_p); - ecma_deref_ecma_string (idx_str_p); - } - - /* 13.c.iii.8 */ - curr_pos = start_pos; - - ECMA_OP_TO_NUMBER_FINALIZE (array_length_num); - ECMA_FINALIZE (array_length_val); - ecma_deref_ecma_string (array_length_str_p); - ecma_deref_ecma_string (substr_str_p); - } - - ecma_free_value (match_result); - - } - - if (!should_return && !separator_is_empty && ecma_is_value_empty (ret_value)) - { - /* 14. */ - ecma_string_t *substr_str_p; - substr_str_p = ecma_string_substr (this_to_string_p, - start_pos, - string_length); - - /* 15. */ - ecma_string_t *array_length_string_p = ecma_new_ecma_string_from_uint32 (new_array_length); - - ecma_value_t put_comp = ecma_builtin_helper_def_prop (new_array_p, - array_length_string_p, - ecma_make_string_value (substr_str_p), - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - - JERRY_ASSERT (ecma_is_value_true (put_comp)); - - ecma_deref_ecma_string (array_length_string_p); - ecma_deref_ecma_string (substr_str_p); + goto cleanup_string; } } - ecma_free_value (separator); - - if (ecma_is_value_empty (ret_value)) + /* 12. */ + ecma_string_t *separator_p = ecma_op_to_string (separator_value); + if (separator_p == NULL) { - ret_value = new_array; - } - else - { - ecma_deref_object (new_array_p); + goto cleanup_string; } - return ret_value; + /* 6. */ + result = ecma_op_create_array_object (NULL, 0, false); + + /* 14. */ + if (limit == 0) + { + goto cleanup_separator; + } + + ecma_object_t *array_p = ecma_get_object_from_value (result); + ecma_length_t array_length = 0; + + /* 15. */ + if (ecma_is_value_undefined (separator_value)) + { + ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length, + ecma_make_string_value (string_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (put_result == ECMA_VALUE_TRUE); + goto cleanup_separator; + } + + /* 16. */ + if (ecma_string_is_empty (string_p)) + { + if (!ecma_string_is_empty (separator_p)) + { + ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length, + ecma_make_string_value (string_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (put_result == ECMA_VALUE_TRUE); + } + + goto cleanup_separator; + } + + lit_utf8_size_t string_size; + uint8_t string_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *string_buffer_p = ecma_string_get_chars (string_p, + &string_size, + NULL, + NULL, + &string_flags); + lit_utf8_size_t separator_size; + uint8_t separator_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *separator_buffer_p = ecma_string_get_chars (separator_p, + &separator_size, + NULL, + NULL, + &separator_flags); + + const lit_utf8_byte_t *const string_end_p = string_buffer_p + string_size; + const lit_utf8_byte_t *const compare_end_p = JERRY_MIN (string_end_p - separator_size + 1, + string_end_p); + const lit_utf8_byte_t *current_p = string_buffer_p; + const lit_utf8_byte_t *last_str_begin_p = string_buffer_p; + + while (current_p < compare_end_p) + { + if (!memcmp (current_p, separator_buffer_p, separator_size) + && (last_str_begin_p != current_p + separator_size)) + { + ecma_string_t *substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p, + (lit_utf8_size_t) (current_p - last_str_begin_p)); + ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + ecma_make_string_value (substr_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (put_result == ECMA_VALUE_TRUE); + ecma_deref_ecma_string (substr_p); + + if (array_length >= limit) + { + goto cleanup_buffers; + } + + current_p += separator_size; + last_str_begin_p = current_p; + continue; + } + + lit_utf8_incr (¤t_p); + } + + ecma_string_t *end_substr_p = ecma_new_ecma_string_from_utf8 (last_str_begin_p, + (lit_utf8_size_t) (string_end_p - last_str_begin_p)); + ecma_value_t put_result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length, + ecma_make_string_value (end_substr_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (put_result == ECMA_VALUE_TRUE); + ecma_deref_ecma_string (end_substr_p); + +cleanup_buffers: + if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) string_buffer_p, string_size); + } + + if (separator_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) separator_buffer_p, separator_size); + } + +cleanup_separator: + ecma_deref_ecma_string (separator_p); +cleanup_string: + ecma_deref_ecma_string (string_p); + return result; } /* ecma_builtin_string_prototype_object_split */ /** @@ -1697,35 +937,37 @@ ecma_builtin_string_prototype_object_substring (ecma_string_t *original_string_p ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { + /* 3 */ const ecma_length_t len = ecma_string_get_length (original_string_p); + ecma_length_t start = 0, end = len; - /* 4, 6 */ + /* 4 */ ecma_number_t start_num; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg1, &start_num))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg1, &start_num))) { return ECMA_VALUE_ERROR; } - ecma_length_t start = 0, end = len; + /* 6 */ + start = (uint32_t) JERRY_MIN (JERRY_MAX (start_num, 0), len); - start = ecma_builtin_helper_string_index_normalize (start_num, len, true); - - /* 5, 7 */ + /* 5 */ if (ecma_is_value_undefined (arg2)) { end = len; } else { + /* 5 part 2 */ ecma_number_t end_num; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (arg2, &end_num))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg2, &end_num))) { return ECMA_VALUE_ERROR; } - - end = ecma_builtin_helper_string_index_normalize (end_num, len, true); + /* 7 */ + end = (uint32_t) JERRY_MIN (JERRY_MAX (end_num, 0), len); } JERRY_ASSERT (start <= len && end <= len); @@ -1777,7 +1019,7 @@ ecma_builtin_string_prototype_object_conversion_helper (ecma_string_t *input_str while (input_str_curr_p < input_str_end_p) { - ecma_char_t character = lit_utf8_read_next (&input_str_curr_p); + ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p); ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH]; ecma_length_t character_length; lit_utf8_byte_t utf8_byte_buffer[LIT_CESU8_MAX_BYTES_IN_CODE_POINT]; @@ -1816,7 +1058,7 @@ ecma_builtin_string_prototype_object_conversion_helper (ecma_string_t *input_str while (input_str_curr_p < input_str_end_p) { - ecma_char_t character = lit_utf8_read_next (&input_str_curr_p); + ecma_char_t character = lit_cesu8_read_next (&input_str_curr_p); ecma_char_t character_buffer[LIT_MAXIMUM_OTHER_CASE_LENGTH]; ecma_length_t character_length; @@ -1870,7 +1112,7 @@ ecma_builtin_string_prototype_object_trim (ecma_string_t *original_string_p) /** return ecma_make_string_value (trimmed_string_p); } /* ecma_builtin_string_prototype_object_trim */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) /** * The String.prototype object's 'repeat' routine @@ -1889,7 +1131,7 @@ ecma_builtin_string_prototype_object_repeat (ecma_string_t *original_string_p, / /* 4 */ ecma_number_t count_number; - ecma_value_t count_value = ecma_get_number (repeat, &count_number); + ecma_value_t count_value = ecma_op_to_integer (repeat, &count_number); /* 5 */ if (ECMA_IS_VALUE_ERROR (count_value)) @@ -1937,7 +1179,56 @@ ecma_builtin_string_prototype_object_repeat (ecma_string_t *original_string_p, / return ecma_make_string_value (ret_string_p); } /* ecma_builtin_string_prototype_object_repeat */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +/** + * The String.prototype object's 'codePointAt' routine + * + * See also: + * ECMA-262 v6, 21.1.3.3 + * + * @return lit_code_point_t + */ +static ecma_value_t +ecma_builtin_string_prototype_object_code_point_at (ecma_string_t *this_string_p, /**< this argument */ + ecma_value_t pos) /**< given position */ +{ + ecma_number_t pos_num; + ecma_value_t error = ecma_op_to_integer (pos, &pos_num); + + if (ECMA_IS_VALUE_ERROR (error)) + { + return error; + } + + ecma_length_t size = ecma_string_get_length (this_string_p); + + if (pos_num < 0 || pos_num >= size) + { + return ECMA_VALUE_UNDEFINED; + } + + uint32_t index = (uint32_t) pos_num; + + ecma_char_t first = ecma_string_get_char_at_pos (this_string_p, index); + + if (first < LIT_UTF16_HIGH_SURROGATE_MIN + || first > LIT_UTF16_HIGH_SURROGATE_MAX + || index + 1 == size) + { + return ecma_make_uint32_value (first); + } + + ecma_char_t second = ecma_string_get_char_at_pos (this_string_p, index + 1); + + if (second < LIT_UTF16_LOW_SURROGATE_MARKER + || second > LIT_UTF16_LOW_SURROGATE_MAX) + { + return ecma_make_uint32_value (first); + } + + return ecma_make_uint32_value (lit_convert_surrogate_pair_to_code_point (first, second)); +} /* ecma_builtin_string_prototype_object_code_point_at */ + +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -1958,16 +1249,11 @@ ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< /* 2. */ ecma_number_t start_num; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (start, &start_num))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (start, &start_num))) { return ECMA_VALUE_ERROR; } - if (ecma_number_is_nan (start_num)) - { - start_num = 0; - } - /* 3. */ ecma_number_t length_num = ecma_number_make_infinity (false); @@ -1975,7 +1261,7 @@ ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< { ecma_number_t len; - if (ECMA_IS_VALUE_ERROR (ecma_get_number (length, &len))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (length, &len))) { return ECMA_VALUE_ERROR; } @@ -1984,15 +1270,21 @@ ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< } /* 4. */ - ecma_number_t this_len = (ecma_number_t) ecma_string_get_length (this_string_p); + ecma_length_t this_len = ecma_string_get_length (this_string_p); /* 5. */ - ecma_number_t from_num = (start_num < 0) ? JERRY_MAX (this_len + start_num, 0) : start_num; - uint32_t from = ecma_builtin_helper_string_index_normalize (from_num, ecma_number_to_uint32 (this_len), true); + uint32_t from = (uint32_t) ((start_num < 0) ? JERRY_MAX (this_len + start_num, 0) : start_num); - /* 6-7. */ - ecma_number_t to_num = JERRY_MAX (JERRY_MIN (JERRY_MAX (length_num, 0), this_len - from_num), 0); - uint32_t to = from + ecma_builtin_helper_string_index_normalize (to_num, ecma_number_to_uint32 (this_len), true); + if (from > this_len) + { + from = this_len; + } + + /* 6. */ + ecma_number_t to_num = JERRY_MIN (JERRY_MAX (length_num, 0), this_len - from); + + /* 7. */ + uint32_t to = from + (uint32_t) to_num; /* 8. */ ecma_string_t *new_str_p = ecma_string_substr (this_string_p, from, to); @@ -2001,7 +1293,8 @@ ecma_builtin_string_prototype_object_substr (ecma_string_t *this_string_p, /**< #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * The String.prototype object's @@iterator routine * @@ -2019,7 +1312,8 @@ ecma_builtin_string_prototype_object_iterator (ecma_value_t to_string) /**< this ECMA_PSEUDO_STRING_ITERATOR, 0); } /* ecma_builtin_string_prototype_object_iterator */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Dispatcher of the built-in's routines @@ -2050,6 +1344,13 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** ecma_value_t arg1 = arguments_list_p[0]; ecma_value_t arg2 = arguments_list_p[1]; +#if ENABLED (JERRY_BUILTIN_REGEXP) + if (builtin_routine_id == ECMA_STRING_PROTOTYPE_MATCH) + { + return ecma_builtin_string_prototype_object_match (this_arg, arg1); + } +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ + if (builtin_routine_id <= ECMA_STRING_PROTOTYPE_CHAR_CODE_AT) { return ecma_builtin_string_prototype_char_at_helper (this_arg, @@ -2057,15 +1358,14 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** builtin_routine_id == ECMA_STRING_PROTOTYPE_CHAR_CODE_AT); } - ecma_value_t to_string_val = ecma_op_to_string (this_arg); + ecma_string_t *string_p = ecma_op_to_string (this_arg); - if (ECMA_IS_VALUE_ERROR (to_string_val)) + if (JERRY_UNLIKELY (string_p == NULL)) { - return to_string_val; + return ECMA_VALUE_ERROR; } - ecma_string_t *string_p = ecma_get_string_from_value (to_string_val); - + ecma_value_t to_string_val = ecma_make_string_value (string_p); ecma_value_t ret_value = ECMA_VALUE_EMPTY; switch (builtin_routine_id) @@ -2080,16 +1380,16 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** ret_value = ecma_builtin_string_prototype_object_slice (string_p, arg1, arg2); break; } - case ECMA_STRING_PROTOTYPE_INDEX_OF: case ECMA_STRING_PROTOTYPE_LAST_INDEX_OF: -#if ENABLED (JERRY_ES2015_BUILTIN) + case ECMA_STRING_PROTOTYPE_INDEX_OF: +#if ENABLED (JERRY_ES2015) case ECMA_STRING_PROTOTYPE_STARTS_WITH: case ECMA_STRING_PROTOTYPE_INCLUDES: case ECMA_STRING_PROTOTYPE_ENDS_WITH: -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ +#endif /* ENABLED (JERRY_ES2015) */ { ecma_string_index_of_mode_t mode; - mode = (ecma_string_index_of_mode_t) (builtin_routine_id - ECMA_STRING_PROTOTYPE_INDEX_OF); + mode = (ecma_string_index_of_mode_t) (builtin_routine_id - ECMA_STRING_PROTOTYPE_LAST_INDEX_OF); ret_value = ecma_builtin_helper_string_prototype_object_index_of (string_p, arg1, arg2, mode); break; } @@ -2099,11 +1399,6 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** break; } #if ENABLED (JERRY_BUILTIN_REGEXP) - case ECMA_STRING_PROTOTYPE_MATCH: - { - ret_value = ecma_builtin_string_prototype_object_match (to_string_val, arg1); - break; - } case ECMA_STRING_PROTOTYPE_REPLACE: { ret_value = ecma_builtin_string_prototype_object_replace (to_string_val, arg1, arg2); @@ -2146,20 +1441,23 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** break; } #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) case ECMA_STRING_PROTOTYPE_REPEAT: { ret_value = ecma_builtin_string_prototype_object_repeat (string_p, arg1); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) + case ECMA_STRING_PROTOTYPE_CODE_POINT_AT: + { + ret_value = ecma_builtin_string_prototype_object_code_point_at (string_p, arg1); + break; + } case ECMA_STRING_PROTOTYPE_ITERATOR: { ret_value = ecma_builtin_string_prototype_object_iterator (to_string_val); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_UNREACHABLE (); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h index 5679079c..785be7b3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h @@ -67,16 +67,14 @@ ROUTINE (LIT_MAGIC_STRING_TRIM, ECMA_STRING_PROTOTYPE_TRIM, 0, 0) ROUTINE (LIT_MAGIC_STRING_SUBSTR, ECMA_STRING_PROTOTYPE_SUBSTR, 2, 2) #endif /* ENABLED (JERRY_BUILTIN_ANNEXB) */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_REPEAT, ECMA_STRING_PROTOTYPE_REPEAT, 1, 1) ROUTINE (LIT_MAGIC_STRING_STARTS_WITH, ECMA_STRING_PROTOTYPE_STARTS_WITH, 2, 1) ROUTINE (LIT_MAGIC_STRING_INCLUDES, ECMA_STRING_PROTOTYPE_INCLUDES, 2, 1) ROUTINE (LIT_MAGIC_STRING_ENDS_WITH, ECMA_STRING_PROTOTYPE_ENDS_WITH, 2, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ - -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +ROUTINE (LIT_MAGIC_STRING_CODE_POINT_AT, ECMA_STRING_PROTOTYPE_CODE_POINT_AT, 1, 1) ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ECMA_STRING_PROTOTYPE_ITERATOR, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_BUILTIN_STRING) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string.c index ddb5da9f..7537fa93 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "lit-strings.h" #include "ecma-alloc.h" #include "ecma-builtins.h" #include "ecma-conversion.h" @@ -22,9 +23,9 @@ #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-string-object.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #include "ecma-symbol-object.h" -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-try-catch-macro.h" #include "jrt.h" @@ -109,6 +110,231 @@ ecma_builtin_string_object_from_char_code (ecma_value_t this_arg, /**< 'this' ar return ret_value; } /* ecma_builtin_string_object_from_char_code */ +#if ENABLED (JERRY_ES2015) + +/** + * The String object's 'raw' routine + * + * See also: + * ECMA-262 v6, 21.1.2.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_string_object_raw (ecma_value_t this_arg, /**< 'this' argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + JERRY_UNUSED (this_arg); + + /* 1 - 2. */ + const ecma_value_t *substitutions; + ecma_length_t number_of_substitutions; + + if (args_number > 1) + { + substitutions = args + 1; + number_of_substitutions = args_number - 1; + } + else + { + substitutions = NULL; + number_of_substitutions = 0; + } + + /* 3. */ + ecma_value_t template = args_number > 0 ? args[0] : ECMA_VALUE_UNDEFINED; + + ecma_value_t cooked = ecma_op_to_object (template); + + /* 4. */ + if (ECMA_IS_VALUE_ERROR (cooked)) + { + return cooked; + } + + ecma_object_t *cooked_obj_p = ecma_get_object_from_value (cooked); + + /* 5. */ + ecma_value_t raw = ecma_op_object_get_by_magic_id (cooked_obj_p, LIT_MAGIC_STRING_RAW); + + ecma_deref_object (cooked_obj_p); + + if (ECMA_IS_VALUE_ERROR (raw)) + { + return raw; + } + + ecma_value_t raw_obj = ecma_op_to_object (raw); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (raw_obj)) + { + ecma_free_value (raw); + return raw_obj; + } + + ecma_object_t *raw_obj_p = ecma_get_object_from_value (raw_obj); + + ecma_value_t ret_value = ECMA_VALUE_ERROR; + + /* 7 - 8. */ + uint32_t literal_segments; + if (ECMA_IS_VALUE_ERROR (ecma_op_object_get_length (raw_obj_p, &literal_segments))) + { + goto cleanup; + } + + /* 9. */ + if (literal_segments == 0) + { + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + goto cleanup; + } + + /* 10. */ + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); + + /* 11. */ + uint32_t next_index = 0; + + /* 12. */ + while (true) + { + /* 12.a,b */ + ecma_value_t next_seg = ecma_op_object_get_by_uint32_index (raw_obj_p, next_index); + + if (ECMA_IS_VALUE_ERROR (next_seg)) + { + goto builder_cleanup; + } + + ecma_string_t *next_seg_srt_p = ecma_op_to_string (next_seg); + + /* 12.c */ + if (JERRY_UNLIKELY (next_seg_srt_p == NULL)) + { + ecma_free_value (next_seg); + goto builder_cleanup; + } + + /* 12.d */ + ecma_stringbuilder_append (&builder, next_seg_srt_p); + + ecma_deref_ecma_string (next_seg_srt_p); + ecma_free_value (next_seg); + + /* 12.e */ + if (next_index + 1 == literal_segments) + { + ret_value = ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); + goto cleanup; + } + + /* 12.f-g */ + if (next_index >= number_of_substitutions) + { + next_index++; + continue; + } + + /* 12.h */ + ecma_string_t *next_sub_p = ecma_op_to_string (substitutions[next_index]); + + /* 12.i */ + if (JERRY_UNLIKELY (next_sub_p == NULL)) + { + goto builder_cleanup; + } + + /* 12.j */ + ecma_stringbuilder_append (&builder, next_sub_p); + ecma_deref_ecma_string (next_sub_p); + + /* 12.k */ + next_index++; + } + +builder_cleanup: + ecma_stringbuilder_destroy (&builder); + +cleanup: + ecma_deref_object (raw_obj_p); + ecma_free_value (raw); + + return ret_value; +} /* ecma_builtin_string_object_raw */ + +/** + * The String object's 'fromCodePoint' routine + * + * See also: + * ECMA-262 v6, 21.1.2.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_string_object_from_code_point (ecma_value_t this_arg, /**< 'this' argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + JERRY_UNUSED (this_arg); + + if (args_number == 0) + { + return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + } + + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); + + for (ecma_length_t index = 0; index < args_number; index++) + { + ecma_value_t to_number_value = ecma_op_to_number (args[index]); + + if (ECMA_IS_VALUE_ERROR (to_number_value)) + { + ecma_stringbuilder_destroy (&builder); + return to_number_value; + } + + ecma_number_t to_number_num = ecma_get_number_from_value (to_number_value); + ecma_free_value (to_number_value); + + ecma_number_t to_int_num; + ecma_value_t to_int_value = ecma_op_to_integer (to_number_value, &to_int_num); + + if (ECMA_IS_VALUE_ERROR (to_int_value)) + { + ecma_stringbuilder_destroy (&builder); + return to_int_value; + } + + if (to_number_num != to_int_num || to_int_num < 0 || to_int_num > LIT_UNICODE_CODE_POINT_MAX) + { + ecma_stringbuilder_destroy (&builder); + return ecma_raise_range_error (ECMA_ERR_MSG ("Error: Invalid code point")); + } + + lit_code_point_t code_point = (uint32_t) to_int_num; + + ecma_char_t converted_cp[2]; + uint8_t encoded_size = lit_utf16_encode_code_point (code_point, converted_cp); + + for (uint8_t i = 0; i < encoded_size; i++) + { + ecma_stringbuilder_append_char (&builder, converted_cp[i]); + } + } + + ecma_string_t *ret_str_p = ecma_stringbuilder_finalize (&builder); + + return ecma_make_string_value (ret_str_p); +} /* ecma_builtin_string_object_from_code_point */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Handle calling [[Call]] of built-in String object * @@ -130,17 +356,23 @@ ecma_builtin_string_dispatch_call (const ecma_value_t *arguments_list_p, /**< ar { ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* 2.a */ else if (ecma_is_value_symbol (arguments_list_p[0])) { ret_value = ecma_get_symbol_descriptive_string (arguments_list_p[0]); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* 2.b */ else { - ret_value = ecma_op_to_string (arguments_list_p[0]); + ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); + if (JERRY_UNLIKELY (str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ret_value = ecma_make_string_value (str_p); } return ret_value; diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-string.inc.h index a8435a90..d3e8d88b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.5.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ @@ -41,6 +40,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_FROM_CHAR_CODE_UL, ecma_builtin_string_object_from_char_code, NON_FIXED, 1) +#if ENABLED (JERRY_ES2015) +ROUTINE (LIT_MAGIC_STRING_FROM_CODE_POINT_UL, ecma_builtin_string_object_from_code_point, NON_FIXED, 1) +ROUTINE (LIT_MAGIC_STRING_RAW, ecma_builtin_string_object_raw, NON_FIXED, 1) +#endif /* ENABLED (JERRY_ES2015) */ + #endif /* ENABLED (JERRY_BUILTIN_STRING) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c index 5dfd259c..6ed00163 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c @@ -25,7 +25,7 @@ #include "ecma-try-catch-macro.h" #include "jrt.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -95,4 +95,4 @@ ecma_builtin_symbol_prototype_object_to_primitive (ecma_value_t this_arg) /**< t * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h index 8301f78b..a3a5b4e6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h @@ -19,7 +19,7 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* Object properties: * (property name, object pointer getter) */ @@ -28,10 +28,6 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_SYMBOL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, - 0, - ECMA_PROPERTY_FLAG_WRITABLE) - ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_symbol_prototype_object_to_string, 0, 0) ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ecma_builtin_symbol_prototype_object_value_of, 0, 0) ROUTINE_CONFIGURABLE_ONLY (LIT_GLOBAL_SYMBOL_TO_PRIMITIVE, @@ -44,6 +40,6 @@ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_SYMBOL_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.c b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.c index 68c28cf8..6c568119 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.c @@ -27,7 +27,7 @@ #include "jcontext.h" #include "jrt.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -198,18 +198,16 @@ ecma_builtin_symbol_for (ecma_value_t this_arg, /**< this argument */ ecma_value_t key) /**< key string */ { JERRY_UNUSED (this_arg); - ecma_value_t string_desc = ecma_op_to_string (key); + ecma_string_t *string_desc_p = ecma_op_to_string (key); /* 1. */ - if (ECMA_IS_VALUE_ERROR (string_desc)) + if (JERRY_UNLIKELY (string_desc_p == NULL)) { /* 2. */ - return string_desc; + return ECMA_VALUE_ERROR; } - /* 4-7. */ - JERRY_ASSERT (ecma_is_value_string (string_desc)); - return ecma_builtin_symbol_for_helper (string_desc); + return ecma_builtin_symbol_for_helper (ecma_make_string_value (string_desc_p)); } /* ecma_builtin_symbol_for */ /** @@ -243,4 +241,4 @@ ecma_builtin_symbol_key_for (ecma_value_t this_arg, /**< this argument */ * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.inc.h index b9a33ffd..cb932b1c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol.inc.h @@ -19,7 +19,7 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* Number properties: * (property name, number value, writable, enumerable, configurable) */ @@ -27,7 +27,7 @@ /* ECMA-262 v6, 19.4.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 0, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* Object properties: * (property name, object pointer getter) */ @@ -38,54 +38,65 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.2 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_HAS_INSTANCE, - LIT_GLOBAL_SYMBOL_HAS_INSTANCE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_HAS_INSTANCE, + LIT_GLOBAL_SYMBOL_HAS_INSTANCE, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.3 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_IS_CONCAT_SPREADABLE, - LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_IS_CONCAT_SPREADABLE, + LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.4 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_ITERATOR, - LIT_GLOBAL_SYMBOL_ITERATOR) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_ITERATOR, + LIT_GLOBAL_SYMBOL_ITERATOR, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.6 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_MATCH, - LIT_GLOBAL_SYMBOL_MATCH) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_MATCH, + LIT_GLOBAL_SYMBOL_MATCH, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.8 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_REPLACE, - LIT_GLOBAL_SYMBOL_REPLACE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_REPLACE, + LIT_GLOBAL_SYMBOL_REPLACE, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.9 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_SEARCH, - LIT_GLOBAL_SYMBOL_SEARCH) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_SEARCH, + LIT_GLOBAL_SYMBOL_SEARCH, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.10 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_SPECIES, - LIT_GLOBAL_SYMBOL_SPECIES) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_SPECIES, + LIT_GLOBAL_SYMBOL_SPECIES, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.11 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_SPLIT, - LIT_GLOBAL_SYMBOL_SPLIT) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_SPLIT, + LIT_GLOBAL_SYMBOL_SPLIT, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.12 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_TO_PRIMITIVE, - LIT_GLOBAL_SYMBOL_TO_PRIMITIVE) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_TO_PRIMITIVE, + LIT_GLOBAL_SYMBOL_TO_PRIMITIVE, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.13 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_TO_STRING_TAG, - LIT_GLOBAL_SYMBOL_TO_STRING_TAG) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_TO_STRING_TAG, + LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + ECMA_PROPERTY_FIXED) /* ECMA-262 v6, 19.4.2.14 */ -SYMBOL_VALUE (LIT_MAGIC_STRING_UNSCOPABLES, - LIT_GLOBAL_SYMBOL_UNSCOPABLES) +INTRINSIC_PROPERTY (LIT_MAGIC_STRING_UNSCOPABLES, + LIT_GLOBAL_SYMBOL_UNSCOPABLES, + ECMA_PROPERTY_FIXED) /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_FOR, ecma_builtin_symbol_for, 1, 1) ROUTINE (LIT_MAGIC_STRING_KEY_FOR, ecma_builtin_symbol_key_for, 1, 1) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-syntaxerror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-syntaxerror.inc.h index 3585aea9..848b1bcd 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-syntaxerror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-syntaxerror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-type-error-thrower.c b/jerry-core/ecma/builtin-objects/ecma-builtin-type-error-thrower.c index fe58158b..d6d7c447 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-type-error-thrower.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-type-error-thrower.c @@ -55,8 +55,8 @@ ecma_builtin_type_error_thrower_dispatch_call (const ecma_value_t *arguments_lis { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - /* The object should throw TypeError */ - return ecma_raise_type_error (ECMA_ERR_MSG ("")); + return ecma_raise_type_error (ECMA_ERR_MSG ("'caller', 'callee', and 'arguments' properties may not be accessed" + " on strict mode functions or the arguments objects for calls to them")); } /* ecma_builtin_type_error_thrower_dispatch_call */ /** @@ -73,8 +73,7 @@ ecma_builtin_type_error_thrower_dispatch_construct (const ecma_value_t *argument { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - /* The object is not a constructor */ - return ecma_raise_type_error (ECMA_ERR_MSG ("")); + return ecma_builtin_type_error_thrower_dispatch_call (arguments_list_p, arguments_list_len); } /* ecma_builtin_type_error_thrower_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-typeerror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-typeerror.inc.h index 587c4e76..5c5b42a2 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-typeerror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-typeerror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-urierror.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-urierror.inc.h index c0d555be..84845b6d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-urierror.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-urierror.inc.h @@ -24,10 +24,9 @@ /* Number properties: * (property name, number value, writable, enumerable, configurable) */ -/* ECMA-262 v5, 15.11.3 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 1, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_DEFAULT_LENGTH) /* Object properties: * (property name, object pointer getter) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c new file mode 100644 index 00000000..720b5dfa --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c @@ -0,0 +1,108 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakmap-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID weakmap_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakmap ECMA WeakMap object built-in + * @{ + */ + +/** + * The WeakMap.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.3.3.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_delete_weak (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_delete */ + +/** + * The WeakMap.prototype object's 'get' routine + * + * See also: + * ECMA-262 v6, 23.3.3.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_get (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_get (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_get */ + +/** + * The WeakMap.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.3.3.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_has (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_has */ + +/** + * The WeakMap.prototype object's 'set' routine + * + * See also: + * ECMA-262 v6, 23.3.3.5 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_set (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_set (this_arg, key_arg, value_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_set */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h new file mode 100644 index 00000000..a2db2edf --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h @@ -0,0 +1,46 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * WeakMap.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.3.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_WEAKMAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* ECMA-262 v6, 23.3.3.6 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_weakmap_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_GET, ecma_builtin_weakmap_prototype_object_get, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_weakmap_prototype_object_has, 1, 1) +ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_weakmap_prototype_object_set, 2, 2) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c new file mode 100644 index 00000000..8a94940b --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c @@ -0,0 +1,74 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakmap.inc.h" +#define BUILTIN_UNDERSCORED_ID weakmap +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakmap ECMA WeakMap object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in WeakMap object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakmap_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor WeakMap requires 'new'.")); +} /* ecma_builtin_weakmap_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in WeakMap object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakmap_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_container_create (arguments_list_p, + arguments_list_len, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE); +} /* ecma_builtin_weakmap_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h new file mode 100644 index 00000000..a27be6bc --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h @@ -0,0 +1,47 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * WeakMap built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.3.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 23.1 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.3.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c new file mode 100644 index 00000000..476489d4 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c @@ -0,0 +1,91 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakset-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID weakset_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakset ECMA WeakSet object built-in + * @{ + */ + +/** + * The WeakSet.prototype object's 'add' routine + * + * See also: + * ECMA-262 v6, 23.4.3.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_add (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_set (this_arg, value_arg, ECMA_VALUE_UNDEFINED, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_add */ + +/** + * The WeakSet.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.4.3.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_delete_weak (this_arg, value_arg, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_delete */ + +/** + * The WeakSet.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.4.3.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_has (this_arg, value_arg, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_has */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h new file mode 100644 index 00000000..9ee89842 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h @@ -0,0 +1,45 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * WeakSet.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.4.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_WEAKSET, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* ECMA-262 v6, 23.4.3.5 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_ADD, ecma_builtin_weakset_prototype_object_add, 1, 1) +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_weakset_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_weakset_prototype_object_has, 1, 1) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c new file mode 100644 index 00000000..823abde8 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c @@ -0,0 +1,74 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakset.inc.h" +#define BUILTIN_UNDERSCORED_ID weakset +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakset ECMA WeakSet object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in WeakSet object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakset_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor WeakSet requires 'new'.")); +} /* ecma_builtin_weakset_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in WeakSet object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakset_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_container_create (arguments_list_p, + arguments_list_len, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE); +} /* ecma_builtin_weakset_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h new file mode 100644 index 00000000..6fc3a749 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h @@ -0,0 +1,47 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * WeakSet built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.4.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 23.4 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.4.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h index c82672bd..aca0f317 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h @@ -31,9 +31,12 @@ typedef enum ECMA_BUILTIN_PROPERTY_SIMPLE, /**< simple value property */ ECMA_BUILTIN_PROPERTY_NUMBER, /**< number value property */ ECMA_BUILTIN_PROPERTY_STRING, /**< string value property */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) ECMA_BUILTIN_PROPERTY_SYMBOL, /**< symbol value property */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + ECMA_BUILTIN_PROPERTY_INTRINSIC_PROPERTY, /**< intrinsic routine property */ + ECMA_BUILTIN_PROPERTY_ACCESSOR_BUILTIN_FUNCTION, /**< full accessor property with builtin function object + getter/setter pair */ +#endif /* ENABLED (JERRY_ES2015) */ ECMA_BUILTIN_PROPERTY_OBJECT, /**< builtin object property */ ECMA_BUILTIN_PROPERTY_ROUTINE, /**< routine property */ ECMA_BUILTIN_PROPERTY_ACCESSOR_READ_WRITE, /**< full accessor property */ @@ -48,10 +51,11 @@ typedef enum { ECMA_BUILTIN_NUMBER_MAX = 256, /**< value of ECMA_NUMBER_MAX_VALUE */ ECMA_BUILTIN_NUMBER_MIN, /**< value of ECMA_NUMBER_MIN_VALUE */ -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) ECMA_BUILTIN_NUMBER_EPSILON, /**< value of ECMA_NUMBER_EPSILON */ ECMA_BUILTIN_NUMBER_MAX_SAFE_INTEGER, /**< value of ECMA_NUMBER_MAX_SAFE_INTEGER */ -#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + ECMA_BUILTIN_NUMBER_MIN_SAFE_INTEGER, /**< value of ECMA_NUMBER_MIN_SAFE_INTEGER */ +#endif /* ENABLED (JERRY_ES2015) */ ECMA_BUILTIN_NUMBER_E, /**< value of ECMA_NUMBER_E */ ECMA_BUILTIN_NUMBER_PI, /**< value of ECMA_NUMBER_PI */ ECMA_BUILTIN_NUMBER_LN10, /**< value of ECMA_NUMBER_LN10 */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 00927a53..ccd82540 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -15,6 +15,7 @@ #include "ecma-alloc.h" #include "ecma-builtins.h" +#include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" @@ -42,15 +43,15 @@ typedef const ecma_builtin_property_descriptor_t *ecma_builtin_property_list_ref /** * Definition of built-in dispatch routine function pointer. */ -typedef ecma_value_t (*ecma_builtin_dispatch_routine_t)(uint16_t builtin_routine_id, - ecma_value_t this_arg, - const ecma_value_t arguments_list[], - ecma_length_t arguments_number); +typedef ecma_value_t (*ecma_builtin_dispatch_routine_t) (uint16_t builtin_routine_id, + ecma_value_t this_arg, + const ecma_value_t arguments_list[], + ecma_length_t arguments_number); /** * Definition of built-in dispatch call function pointer. */ -typedef ecma_value_t (*ecma_builtin_dispatch_call_t)(const ecma_value_t arguments_list[], - ecma_length_t arguments_number); +typedef ecma_value_t (*ecma_builtin_dispatch_call_t) (const ecma_value_t arguments_list[], + ecma_length_t arguments_number); /** * Definition of a builtin descriptor which contains the builtin object's: * - prototype objects's id (13-bits) @@ -348,6 +349,7 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_object_t *prototype_obj_p; + /* cppcheck-suppress arrayIndexOutOfBoundsCond */ if (JERRY_UNLIKELY (object_prototype_builtin_id == ECMA_BUILTIN_ID__COUNT)) { prototype_obj_p = NULL; @@ -384,7 +386,14 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, ext_object_size, obj_type); - ecma_set_object_extensible (obj_p, (obj_builtin_id != ECMA_BUILTIN_ID_TYPE_ERROR_THROWER)); + if (JERRY_UNLIKELY (obj_builtin_id == ECMA_BUILTIN_ID_TYPE_ERROR_THROWER)) + { + ecma_op_ordinary_object_prevent_extensions (obj_p); + } + else + { + ecma_op_ordinary_object_set_extensible (obj_p); + } /* * [[Class]] property of built-in object is not stored explicitly. @@ -406,13 +415,13 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ built_in_props_p->id = (uint8_t) obj_builtin_id; built_in_props_p->routine_id = (uint16_t) obj_builtin_id; - built_in_props_p->instantiated_bitset[0] = 0; + built_in_props_p->u.instantiated_bitset[0] = 0; if (property_count > 32) { built_in_props_p->length_and_bitset_size = 1 << ECMA_BUILT_IN_BITSET_SHIFT; - uint32_t *instantiated_bitset_p = built_in_props_p->instantiated_bitset; + uint32_t *instantiated_bitset_p = built_in_props_p->u.instantiated_bitset; instantiated_bitset_p[1] = 0; instantiated_bitset_p[2] = 0; } @@ -431,13 +440,12 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; ext_object_p->u.array.length = 0; - ext_object_p->u.array.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; - ext_object_p->u.array.is_fast_mode = false; - ext_object_p->u.array.hole_count = 0; + ext_object_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; break; } #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ +#if !ENABLED (JERRY_ES2015) #if ENABLED (JERRY_BUILTIN_STRING) case ECMA_BUILTIN_ID_STRING_PROTOTYPE: { @@ -496,10 +504,18 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; - ext_object_p->u.class_prop.u.value = ECMA_NULL_POINTER; + + re_compiled_code_t *bc_p = re_compile_bytecode (ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP), + RE_FLAG_EMPTY); + + JERRY_ASSERT (bc_p != NULL); + + ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bc_p); + break; } #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#endif /* !ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (obj_type != ECMA_OBJECT_TYPE_CLASS); @@ -522,7 +538,22 @@ ecma_finalize_builtins (void) { if (JERRY_CONTEXT (ecma_builtin_objects)[id] != JMEM_CP_NULL) { - ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_builtin_objects)[id])); + ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_builtin_objects)[id]); + ecma_deref_object (obj_p); + +#if ENABLED (JERRY_ES2015) + /* Note: In ES2015 a function object may contain tagged template literal collection. Whenever + this function is assigned to a builtin function or function routine during the GC it may cause unresolvable + circle since one part of the circle is a weak reference (marked by GC) and the other part is hard reference + (reference count). In this case when the function which contains the tagged template literal collection + is getting GC marked the arrays in the collection are still holding weak references to properties/prototypes + which prevents these objects from getting freed. Releasing the property list and the prototype reference + manually eliminates the existence of the unresolvable circle described above. */ + ecma_gc_free_properties (obj_p); + obj_p->u1.property_list_cp = JMEM_CP_NULL; + obj_p->u2.prototype_cp = JMEM_CP_NULL; +#endif /* ENABLED (JERRY_ES2015) */ + JERRY_CONTEXT (ecma_builtin_objects)[id] = JMEM_CP_NULL; } } @@ -539,6 +570,7 @@ static ecma_object_t * ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t builtin_id, /**< identifier of built-in object */ uint16_t routine_id, /**< builtin-wide identifier of the built-in * object's routine property */ + uint16_t name_id, /**< magic string id of 'name' property */ uint8_t length_prop_value) /**< value of 'length' property */ { JERRY_ASSERT (length_prop_value < (1 << ECMA_BUILT_IN_BITSET_SHIFT)); @@ -547,17 +579,6 @@ ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t builtin_id, /** size_t ext_object_size = sizeof (ecma_extended_object_t); - size_t property_count = ecma_builtin_get_property_count (builtin_id); - - if (property_count > 32) - { - /* Only 64 extra properties supported at the moment. - * This can be extended to 256 later. */ - JERRY_ASSERT (property_count <= (32 + 64)); - - ext_object_size += sizeof (uint32_t) * 2; - } - ecma_object_t *func_obj_p = ecma_create_object (prototype_obj_p, ext_object_size, ECMA_OBJECT_TYPE_FUNCTION); @@ -569,16 +590,8 @@ ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t builtin_id, /** ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; ext_func_obj_p->u.built_in.id = (uint8_t) builtin_id; ext_func_obj_p->u.built_in.routine_id = routine_id; - ext_func_obj_p->u.built_in.instantiated_bitset[0] = 0; - - if (property_count > 32) - { - length_prop_value = (uint8_t) (length_prop_value | (1 << ECMA_BUILT_IN_BITSET_SHIFT)); - - uint32_t *instantiated_bitset_p = ext_func_obj_p->u.built_in.instantiated_bitset; - instantiated_bitset_p[1] = 0; - instantiated_bitset_p[2] = 0; - } + ext_func_obj_p->u.built_in.u.builtin_routine.name = name_id; + ext_func_obj_p->u.built_in.u.builtin_routine.bitset = 0; ext_func_obj_p->u.built_in.length_and_bitset_size = length_prop_value; @@ -592,10 +605,11 @@ ecma_builtin_make_function_object_for_routine (ecma_builtin_id_t builtin_id, /** */ static ecma_object_t * ecma_builtin_make_function_object_for_getter_accessor (ecma_builtin_id_t builtin_id, /**< id of built-in object */ - uint16_t routine_id) /**< builtin-wide id of the built-in + uint16_t routine_id, /**< builtin-wide id of the built-in * object's routine property */ + uint16_t name_id) /**< magic string id of 'name' property */ { - return ecma_builtin_make_function_object_for_routine (builtin_id, routine_id, 0); + return ecma_builtin_make_function_object_for_routine (builtin_id, routine_id, name_id, 0); } /* ecma_builtin_make_function_object_for_getter_accessor */ /** @@ -605,12 +619,72 @@ ecma_builtin_make_function_object_for_getter_accessor (ecma_builtin_id_t builtin */ static ecma_object_t * ecma_builtin_make_function_object_for_setter_accessor (ecma_builtin_id_t builtin_id, /**< id of built-in object */ - uint16_t routine_id) /**< builtin-wide id of the built-in + uint16_t routine_id, /**< builtin-wide id of the built-in * object's routine property */ + uint16_t name_id) /**< magic string id of 'name' property */ { - return ecma_builtin_make_function_object_for_routine (builtin_id, routine_id, 1); + return ecma_builtin_make_function_object_for_routine (builtin_id, routine_id, name_id, 1); } /* ecma_builtin_make_function_object_for_setter_accessor */ +/** + * Lazy instantiation of builtin routine property of builtin object + * + * If the property is not instantiated yet, instantiate the property and + * return pointer to the instantiated property. + * + * @return pointer property, if one was instantiated, + * NULL - otherwise. + */ +ecma_property_t * +ecma_builtin_routine_try_to_instantiate_property (ecma_object_t *object_p, /**< object */ + ecma_string_t *string_p) /**< property's name */ +{ + JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION); + JERRY_ASSERT (ecma_builtin_function_is_routine (object_p)); + + if (ecma_string_is_length (string_p)) + { + /* + * Lazy instantiation of 'length' property + */ + + ecma_property_t *len_prop_p; + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; +#if ENABLED (JERRY_ES2015) + uint16_t *bitset_p = &ext_func_p->u.built_in.u.builtin_routine.bitset; + if (*bitset_p & (1u << 0)) + { + /* length property was already instantiated */ + return NULL; + } + /* We mark that the property was lazily instantiated, + * as it is configurable and so can be deleted (ECMA-262 v6, 19.2.4.1) */ + *bitset_p |= (1u << 0); + ecma_property_value_t *len_prop_value_p = ecma_create_named_data_property (object_p, + string_p, + ECMA_PROPERTY_FLAG_CONFIGURABLE, + &len_prop_p); +#else /* !ENABLED (JERRY_ES2015) */ + /* We don't need to mark that the property was already lazy instantiated, + * as it is non-configurable and so can't be deleted (ECMA-262 v5, 13.2.5) */ + ecma_property_value_t *len_prop_value_p = ecma_create_named_data_property (object_p, + string_p, + ECMA_PROPERTY_FIXED, + &len_prop_p); +#endif /* ENABLED (JERRY_ES2015) */ + + uint8_t length = ext_func_p->u.built_in.length_and_bitset_size; + JERRY_ASSERT (length < (1 << ECMA_BUILT_IN_BITSET_SHIFT)); + + len_prop_value_p->value = ecma_make_integer_value (length); + + return len_prop_p; + } + + return NULL; +} /* ecma_builtin_routine_try_to_instantiate_property */ + /** * If the property's name is one of built-in properties of the object * that is not instantiated yet, instantiate the property and @@ -625,40 +699,9 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * { JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); - if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION - && ecma_builtin_function_is_routine (object_p)) - { - if (ecma_string_is_length (string_p)) - { - /* - * Lazy instantiation of 'length' property - * - * Note: - * We don't need to mark that the property was already lazy instantiated, - * as it is non-configurable and so can't be deleted - */ - - ecma_property_t *len_prop_p; - ecma_property_value_t *len_prop_value_p = ecma_create_named_data_property (object_p, - string_p, - ECMA_PROPERTY_FIXED, - &len_prop_p); - - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - - uint8_t length = ext_obj_p->u.built_in.length_and_bitset_size & ((1 << ECMA_BUILT_IN_BITSET_SHIFT) - 1); - - len_prop_value_p->value = ecma_make_integer_value (length); - - return len_prop_p; - } - - return NULL; - } - lit_magic_string_id_t magic_string_id = ecma_get_string_magic (string_p); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (JERRY_UNLIKELY (ecma_prop_name_is_symbol (string_p))) { if (string_p->u.hash & ECMA_GLOBAL_SYMBOL_FLAG) @@ -666,7 +709,7 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * magic_string_id = (string_p->u.hash >> ECMA_GLOBAL_SYMBOL_SHIFT); } } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if (magic_string_id == LIT_MAGIC_STRING__COUNT) { @@ -675,6 +718,7 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * ecma_built_in_props_t *built_in_props_p; ecma_object_type_t object_type = ecma_get_object_type (object_p); + JERRY_ASSERT (object_type != ECMA_OBJECT_TYPE_FUNCTION || !ecma_builtin_function_is_routine (object_p)); if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY) { @@ -705,7 +749,7 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * uint32_t index = (uint32_t) (curr_property_p - property_list_p); - uint32_t *bitset_p = built_in_props_p->instantiated_bitset + (index >> 5); + uint32_t *bitset_p = built_in_props_p->u.instantiated_bitset + (index >> 5); uint32_t bit_for_index = (uint32_t) (1u << (index & 0x1f)); @@ -743,10 +787,11 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * { ECMA_NUMBER_MAX_VALUE, ECMA_NUMBER_MIN_VALUE, -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) ECMA_NUMBER_EPSILON, ECMA_NUMBER_MAX_SAFE_INTEGER, -#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + ECMA_NUMBER_MIN_SAFE_INTEGER, +#endif /* ENABLED (JERRY_ES2015) */ ECMA_NUMBER_E, ECMA_NUMBER_PI, ECMA_NUMBER_LN10, @@ -791,25 +836,42 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * value = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->value); break; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) case ECMA_BUILTIN_PROPERTY_SYMBOL: { - lit_magic_string_id_t symbol_desc_id = (lit_magic_string_id_t) curr_property_p->magic_string_id; + ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) "Symbol.", 7); - ecma_string_t *symbol_desc_p; - symbol_desc_p = ecma_append_magic_string_to_string (ecma_get_magic_string (LIT_MAGIC_STRING_SYMBOL_DOT_UL), - symbol_desc_id); + lit_magic_string_id_t symbol_desc_id = (lit_magic_string_id_t) curr_property_p->value; - ecma_value_t symbol_desc_value = ecma_make_string_value (symbol_desc_p); + ecma_stringbuilder_append_magic (&builder, symbol_desc_id); + + ecma_value_t symbol_desc_value = ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); ecma_string_t *symbol_p = ecma_new_symbol_from_descriptor_string (symbol_desc_value); - lit_magic_string_id_t symbol_id = (lit_magic_string_id_t) curr_property_p->value; + lit_magic_string_id_t symbol_id = (lit_magic_string_id_t) curr_property_p->magic_string_id; symbol_p->u.hash = (uint16_t) ((symbol_id << ECMA_GLOBAL_SYMBOL_SHIFT) | ECMA_GLOBAL_SYMBOL_FLAG); value = ecma_make_symbol_value (symbol_p); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + case ECMA_BUILTIN_PROPERTY_INTRINSIC_PROPERTY: + { + value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_INTRINSIC_OBJECT), + (lit_magic_string_id_t) curr_property_p->value); + break; + } + case ECMA_BUILTIN_PROPERTY_ACCESSOR_BUILTIN_FUNCTION: + { + is_accessor = true; + uint16_t getter_id = ECMA_ACCESSOR_READ_WRITE_GET_GETTER_ID (curr_property_p->value); + uint16_t setter_id = ECMA_ACCESSOR_READ_WRITE_GET_SETTER_ID (curr_property_p->value); + getter_p = ecma_builtin_get (getter_id); + setter_p = ecma_builtin_get (setter_id); + ecma_ref_object (getter_p); + ecma_ref_object (setter_p); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ case ECMA_BUILTIN_PROPERTY_OBJECT: { ecma_object_t *builtin_object_p = ecma_builtin_get ((ecma_builtin_id_t) curr_property_p->value); @@ -822,6 +884,7 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * ecma_object_t *func_obj_p; func_obj_p = ecma_builtin_make_function_object_for_routine (builtin_id, ECMA_GET_ROUTINE_ID (curr_property_p->value), + curr_property_p->magic_string_id, ECMA_GET_ROUTINE_LENGTH (curr_property_p->value)); value = ecma_make_object_value (func_obj_p); break; @@ -831,8 +894,12 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * is_accessor = true; uint16_t getter_id = ECMA_ACCESSOR_READ_WRITE_GET_GETTER_ID (curr_property_p->value); uint16_t setter_id = ECMA_ACCESSOR_READ_WRITE_GET_SETTER_ID (curr_property_p->value); - getter_p = ecma_builtin_make_function_object_for_getter_accessor (builtin_id, getter_id); - setter_p = ecma_builtin_make_function_object_for_setter_accessor (builtin_id, setter_id); + getter_p = ecma_builtin_make_function_object_for_getter_accessor (builtin_id, + getter_id, + curr_property_p->magic_string_id); + setter_p = ecma_builtin_make_function_object_for_setter_accessor (builtin_id, + setter_id, + curr_property_p->magic_string_id); break; } default: @@ -841,7 +908,8 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * is_accessor = true; getter_p = ecma_builtin_make_function_object_for_getter_accessor (builtin_id, - curr_property_p->value); + curr_property_p->value, + curr_property_p->magic_string_id); break; } } @@ -884,6 +952,48 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * return prop_p; } /* ecma_builtin_try_to_instantiate_property */ +/** + * List names of a built-in function's lazy instantiated properties + * + * See also: + * ecma_builtin_routine_try_to_instantiate_property + */ +void +ecma_builtin_routine_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in object */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ + ecma_collection_t *main_collection_p, /**< 'main' collection */ + ecma_collection_t *non_enum_collection_p) /**< skipped 'non-enumerable' + * collection */ +{ + JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION); + JERRY_ASSERT (ecma_builtin_function_is_routine (object_p)); + + const bool separate_enumerable = (opts & ECMA_LIST_ENUMERABLE) != 0; + const bool is_array_indices_only = (opts & ECMA_LIST_ARRAY_INDICES) != 0; + + ecma_collection_t *for_enumerable_p = main_collection_p; + JERRY_UNUSED (for_enumerable_p); + + ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + if (!is_array_indices_only) + { +#if ENABLED (JERRY_ES2015) + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + if (!(ext_func_p->u.built_in.u.builtin_routine.bitset & (1u << 0))) + { + /* Unintialized 'length' property is non-enumerable (ECMA-262 v6, 19.2.4.1) */ + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + } +#else /* !ENABLED (JERRY_ES2015) */ + /* 'length' property is non-enumerable (ECMA-262 v5, 15) */ + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); +#endif /* ENABLED (JERRY_ES2015) */ + } +} /* ecma_builtin_routine_list_lazy_property_names */ + /** * List names of a built-in object's lazy instantiated properties * @@ -892,87 +1002,89 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * */ void ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in object */ - bool separate_enumerable, /**< true - list enumerable properties into - * main collection, and non-enumerable - * to collection of 'skipped non-enumerable' - * properties, - * false - list all properties into main collection. - */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ ecma_collection_t *main_collection_p, /**< 'main' collection */ ecma_collection_t *non_enum_collection_p) /**< skipped 'non-enumerable' * collection */ { JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); + JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_FUNCTION + || !ecma_builtin_function_is_routine (object_p)); - if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION - && ecma_builtin_function_is_routine (object_p)) + const bool separate_enumerable = (opts & ECMA_LIST_ENUMERABLE) != 0; + const bool is_array_indices_only = (opts & ECMA_LIST_ARRAY_INDICES) != 0; + + ecma_built_in_props_t *built_in_props_p; + ecma_object_type_t object_type = ecma_get_object_type (object_p); + + if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY) { - ecma_collection_t *for_enumerable_p = main_collection_p; - JERRY_UNUSED (for_enumerable_p); - - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; - - /* 'length' property is non-enumerable (ECMA-262 v5, 15) */ - ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + built_in_props_p = &((ecma_extended_built_in_object_t *) object_p)->built_in; } else { - ecma_built_in_props_t *built_in_props_p; - ecma_object_type_t object_type = ecma_get_object_type (object_p); + built_in_props_p = &((ecma_extended_object_t *) object_p)->u.built_in; + } - if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY) + ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) built_in_props_p->id; + + JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT); + JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); + + const ecma_builtin_property_descriptor_t *curr_property_p = ecma_builtin_property_list_references[builtin_id]; + + ecma_length_t index = 0; + uint32_t *bitset_p = built_in_props_p->u.instantiated_bitset; + + ecma_collection_t *for_non_enumerable_p = (separate_enumerable ? non_enum_collection_p + : main_collection_p); + + while (curr_property_p->magic_string_id != LIT_MAGIC_STRING__COUNT) + { + if (index == 32) { - built_in_props_p = &((ecma_extended_built_in_object_t *) object_p)->built_in; - } - else - { - built_in_props_p = &((ecma_extended_object_t *) object_p)->u.built_in; + bitset_p++; + index = 0; } - ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) built_in_props_p->id; - - JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT); - JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); - - const ecma_builtin_property_descriptor_t *curr_property_p = ecma_builtin_property_list_references[builtin_id]; - - ecma_length_t index = 0; - uint32_t *bitset_p = built_in_props_p->instantiated_bitset; - - ecma_collection_t *for_non_enumerable_p = (separate_enumerable ? non_enum_collection_p - : main_collection_p); - - while (curr_property_p->magic_string_id != LIT_MAGIC_STRING__COUNT) +#if ENABLED (JERRY_ES2015) + /* Builtin symbol properties are internal magic strings which must not be listed */ + if (curr_property_p->magic_string_id > LIT_NON_INTERNAL_MAGIC_STRING__COUNT) { - if (index == 32) + curr_property_p++; + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_string_t *name_p = ecma_get_magic_string ((lit_magic_string_id_t) curr_property_p->magic_string_id); + + if (is_array_indices_only && ecma_string_get_array_index (name_p) == ECMA_STRING_NOT_ARRAY_INDEX) + { + curr_property_p++; + continue; + } + + uint32_t bit_for_index = (uint32_t) 1u << index; + + if (!(*bitset_p & bit_for_index) || ecma_op_ordinary_object_has_own_property (object_p, name_p)) + { + ecma_value_t name = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->magic_string_id); + +#if ENABLED (JERRY_ES2015) + if (curr_property_p->attributes & ECMA_PROPERTY_FLAG_ENUMERABLE) { - bitset_p++; - index = 0; + ecma_collection_push_back (main_collection_p, name); } - -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - /* Builtin symbol properties are internal magic strings which must not be listed */ - if (curr_property_p->magic_string_id > LIT_NON_INTERNAL_MAGIC_STRING__COUNT) + else +#endif /* ENABLED (JERRY_ES2015) */ { - curr_property_p++; - continue; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - - ecma_string_t *name_p = ecma_get_magic_string ((lit_magic_string_id_t) curr_property_p->magic_string_id); - - uint32_t bit_for_index = (uint32_t) 1u << index; - - if (!(*bitset_p & bit_for_index) || ecma_op_object_has_own_property (object_p, name_p)) - { - ecma_value_t name = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->magic_string_id); - ecma_collection_push_back (for_non_enumerable_p, name); } - - curr_property_p++; - index++; } + + curr_property_p++; + index++; } } /* ecma_builtin_list_lazy_property_names */ @@ -983,15 +1095,12 @@ ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-in object' identifier */ - uint16_t builtin_routine_id, /**< builtin-wide identifier - * of the built-in object's - * routine property */ +ecma_builtin_dispatch_routine (ecma_extended_object_t *func_obj_p, /**< builtin object */ ecma_value_t this_arg_value, /**< 'this' argument value */ const ecma_value_t *arguments_list_p, /**< list of arguments passed to routine */ ecma_length_t arguments_list_len) /**< length of arguments' list */ { - JERRY_ASSERT (builtin_object_id < ECMA_BUILTIN_ID__COUNT); + JERRY_ASSERT (ecma_builtin_function_is_routine ((ecma_object_t *) func_obj_p)); ecma_value_t padded_arguments_list_p[3] = { ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED }; @@ -1018,10 +1127,10 @@ ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-i arguments_list_p = padded_arguments_list_p; } - return ecma_builtin_routines[builtin_object_id] (builtin_routine_id, - this_arg_value, - arguments_list_p, - arguments_list_len); + return ecma_builtin_routines[func_obj_p->u.built_in.id] (func_obj_p->u.built_in.routine_id, + this_arg_value, + arguments_list_p, + arguments_list_len); } /* ecma_builtin_dispatch_routine */ /** @@ -1038,27 +1147,19 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ecma_builtin_function_is_routine (obj_p)) { - ret_value = ecma_builtin_dispatch_routine (ext_obj_p->u.built_in.id, - ext_obj_p->u.built_in.routine_id, - this_arg_value, - arguments_list_p, - arguments_list_len); - } - else - { - ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; - JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_call_functions) / sizeof (ecma_builtin_dispatch_call_t)); - return ecma_builtin_call_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + return ecma_builtin_dispatch_routine (ext_obj_p, + this_arg_value, + arguments_list_p, + arguments_list_len); } - JERRY_ASSERT (!ecma_is_value_empty (ret_value)); - - return ret_value; + ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; + JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_call_functions) / sizeof (ecma_builtin_dispatch_call_t)); + return ecma_builtin_call_functions[builtin_object_id] (arguments_list_p, arguments_list_len); } /* ecma_builtin_dispatch_call */ /** @@ -1068,16 +1169,36 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ */ ecma_value_t ecma_builtin_dispatch_construct (ecma_object_t *obj_p, /**< built-in object */ + ecma_object_t *new_target_p, /**< new target */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< arguments list length */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); + if (ecma_builtin_function_is_routine (obj_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor.")); + } + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_construct_functions) / sizeof (ecma_builtin_dispatch_call_t)); - return ecma_builtin_construct_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (new_target_p); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t ret_value = ecma_builtin_construct_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target; +#endif /* ENABLED (JERRY_ES2015) */ + + return ret_value; } /* ecma_builtin_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.h b/jerry-core/ecma/builtin-objects/ecma-builtins.h index 15d21c42..2bf64800 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.h @@ -85,13 +85,20 @@ ecma_value_t ecma_builtin_dispatch_call (ecma_object_t *obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_value_t -ecma_builtin_dispatch_construct (ecma_object_t *obj_p, +ecma_builtin_dispatch_construct (ecma_object_t *obj_p, ecma_object_t *new_target_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_property_t * +ecma_builtin_routine_try_to_instantiate_property (ecma_object_t *object_p, ecma_string_t *string_p); +ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, ecma_string_t *string_p); void +ecma_builtin_routine_list_lazy_property_names (ecma_object_t *object_p, + uint32_t opts, + ecma_collection_t *main_collection_p, + ecma_collection_t *non_enum_collection_p); +void ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, - bool separate_enumerable, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); bool diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index ddd19606..b2597aa1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -46,14 +46,99 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ARRAY, array) #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ -#if ENABLED (JERRY_BUILTIN_STRING) +#if ENABLED (JERRY_ES2015) +# if ENABLED (JERRY_BUILTIN_STRING) +/* The String.prototype object (21.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_STRING_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + string_prototype) +# endif /* ENABLED (JERRY_BUILTIN_STRING) */ + +# if ENABLED (JERRY_BUILTIN_BOOLEAN) +/* The Boolean.prototype object (19.3.3) */ +BUILTIN (ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + boolean_prototype) +# endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ + +# if ENABLED (JERRY_BUILTIN_NUMBER) +/* The Number.prototype object (20.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_NUMBER_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + number_prototype) +# endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + +# if ENABLED (JERRY_BUILTIN_DATE) +/* The Date.prototype object (20.3.4) */ +BUILTIN (ECMA_BUILTIN_ID_DATE_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + date_prototype) +# endif /* ENABLED (JERRY_BUILTIN_DATE) */ + +# if ENABLED (JERRY_BUILTIN_REGEXP) +/* The RegExp.prototype object (21.2.5) */ +BUILTIN (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + regexp_prototype) +# endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#else /* !ENABLED (JERRY_ES2015) */ +# if ENABLED (JERRY_BUILTIN_STRING) /* The String.prototype object (15.5.4) */ BUILTIN (ECMA_BUILTIN_ID_STRING_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, string_prototype) +# endif /* ENABLED (JERRY_BUILTIN_STRING) */ +# if ENABLED (JERRY_BUILTIN_BOOLEAN) +/* The Boolean.prototype object (15.6.4) */ +BUILTIN (ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE, + ECMA_OBJECT_TYPE_CLASS, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + boolean_prototype) +# endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ + +# if ENABLED (JERRY_BUILTIN_NUMBER) +/* The Number.prototype object (15.7.4) */ +BUILTIN (ECMA_BUILTIN_ID_NUMBER_PROTOTYPE, + ECMA_OBJECT_TYPE_CLASS, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + number_prototype) +# endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + +# if ENABLED (JERRY_BUILTIN_DATE) +/* The Date.prototype object (15.9.4) */ +BUILTIN (ECMA_BUILTIN_ID_DATE_PROTOTYPE, + ECMA_OBJECT_TYPE_CLASS, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + date_prototype) +# endif /* ENABLED (JERRY_BUILTIN_DATE) */ + +# if ENABLED (JERRY_BUILTIN_REGEXP) +/* The RegExp.prototype object (15.10.6) */ +BUILTIN (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE, + ECMA_OBJECT_TYPE_CLASS, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + regexp_prototype) +# endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_BUILTIN_STRING) /* The String object (15.5.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_STRING, ECMA_OBJECT_TYPE_FUNCTION, @@ -63,13 +148,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_STRING, #endif /* ENABLED (JERRY_BUILTIN_STRING) */ #if ENABLED (JERRY_BUILTIN_BOOLEAN) -/* The Boolean.prototype object (15.6.4) */ -BUILTIN (ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE, - ECMA_OBJECT_TYPE_CLASS, - ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, - true, - boolean_prototype) - /* The Boolean object (15.6.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_BOOLEAN, ECMA_OBJECT_TYPE_FUNCTION, @@ -79,13 +157,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_BOOLEAN, #endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ #if ENABLED (JERRY_BUILTIN_NUMBER) -/* The Number.prototype object (15.7.4) */ -BUILTIN (ECMA_BUILTIN_ID_NUMBER_PROTOTYPE, - ECMA_OBJECT_TYPE_CLASS, - ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, - true, - number_prototype) - /* The Number object (15.7.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_NUMBER, ECMA_OBJECT_TYPE_FUNCTION, @@ -117,6 +188,16 @@ BUILTIN (ECMA_BUILTIN_ID_MATH, math) #endif /* ENABLED (JERRY_BUILTIN_MATH) */ +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) + +/* The Reflect object (26.1) */ +BUILTIN (ECMA_BUILTIN_ID_REFLECT, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + reflect) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ + #if ENABLED (JERRY_BUILTIN_JSON) /* The JSON object (15.12) */ BUILTIN (ECMA_BUILTIN_ID_JSON, @@ -127,13 +208,6 @@ BUILTIN (ECMA_BUILTIN_ID_JSON, #endif /* ENABLED (JERRY_BUILTIN_JSON) */ #if ENABLED (JERRY_BUILTIN_DATE) -/* The Date.prototype object (15.9.4) */ -BUILTIN (ECMA_BUILTIN_ID_DATE_PROTOTYPE, - ECMA_OBJECT_TYPE_CLASS, - ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, - true, - date_prototype) - /* The Date object (15.9.3) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_DATE, ECMA_OBJECT_TYPE_FUNCTION, @@ -143,13 +217,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_DATE, #endif /* ENABLED (JERRY_BUILTIN_DATE) */ #if ENABLED (JERRY_BUILTIN_REGEXP) -/* The RegExp.prototype object (15.10.6) */ -BUILTIN (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE, - ECMA_OBJECT_TYPE_CLASS, - ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, - true, - regexp_prototype) - /* The RegExp object (15.10) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_REGEXP, ECMA_OBJECT_TYPE_FUNCTION, @@ -158,6 +225,12 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_REGEXP, regexp) #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#if ENABLED (JERRY_ES2015) +#define ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID ECMA_BUILTIN_ID_ERROR +#else /* !ENABLED (JERRY_ES2015) */ +#define ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE +#endif /* ENABLED (JERRY_ES2015 */ + /* The Error object (15.11.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ERROR, ECMA_OBJECT_TYPE_FUNCTION, @@ -183,7 +256,7 @@ BUILTIN (ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE, /* The EvalError object (15.11.6.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_EVAL_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, eval_error) @@ -197,7 +270,7 @@ BUILTIN (ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE, /* The RangeError object (15.11.6.2) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_RANGE_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, range_error) @@ -211,7 +284,7 @@ BUILTIN (ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE, /* The ReferenceError object (15.11.6.3) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_REFERENCE_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, reference_error) @@ -225,7 +298,7 @@ BUILTIN (ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE, /* The SyntaxError object (15.11.6.4) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SYNTAX_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, syntax_error) @@ -239,7 +312,7 @@ BUILTIN (ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE, /* The TypeError object (15.11.6.5) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_TYPE_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, type_error) @@ -253,7 +326,7 @@ BUILTIN (ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE, /* The URIError object (15.11.6.6) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_URI_ERROR, ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_BUILTIN_NATIVE_ERROR_PROTOTYPE_ID, true, uri_error) #endif /* ENABLED (JERRY_BUILTIN_ERRORS) */ @@ -352,7 +425,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_FLOAT64ARRAY, float64array) #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */ - BUILTIN (ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, @@ -462,7 +534,66 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SET, #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* The WeakMap prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + weakmap_prototype) + +/* The WeakMap routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKMAP, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + weakmap) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* The WeakSet prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + weakset_prototype) + +/* The WeakSet routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKSET, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + weakset) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/* The Proxy routine (ECMA-262 v6, 26.2.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_PROXY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + proxy) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +#if ENABLED (JERRY_ES2015) + +/* Intrinsic hidden builtin object */ +BUILTIN (ECMA_BUILTIN_ID_INTRINSIC_OBJECT, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID__COUNT, + true, + intrinsic) + +/* The Array.prototype[@@unscopables] object */ +BUILTIN (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE_UNSCOPABLES, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID__COUNT, + true, + array_prototype_unscopables) /* The Symbol prototype object (ECMA-262 v6, 19.4.2.7) */ BUILTIN (ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE, @@ -478,8 +609,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SYMBOL, true, symbol) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) /* The %IteratorPrototype% object (ECMA-262 v6, 25.1.2) */ BUILTIN (ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, @@ -501,6 +630,27 @@ BUILTIN (ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE, true, string_iterator_prototype) +/* The %(GeneratorFunction)% object */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_GENERATOR_FUNCTION, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION, + true, + generator_function) + +/* The %(Generator)% object */ +BUILTIN (ECMA_BUILTIN_ID_GENERATOR, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + generator) + +/* The %(Generator).prototype% object */ +BUILTIN (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE, + true, + generator_prototype) + #if ENABLED (JERRY_ES2015_BUILTIN_SET) /* The %SetIteratorPrototype% object (ECMA-262 v6, 23.2.5.2) */ BUILTIN (ECMA_BUILTIN_ID_SET_ITERATOR_PROTOTYPE, @@ -518,7 +668,7 @@ BUILTIN (ECMA_BUILTIN_ID_MAP_ITERATOR_PROTOTYPE, true, map_iterator_prototype) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) /* The DataView prototype object (ECMA-262 v6, 24.2.3.1) */ diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index da9cd4ee..f4dd0d94 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -35,6 +35,7 @@ #include "jmem.h" #include "jrt-libc-includes.h" #include "jrt.h" +#include "lit-char-helpers.h" #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -146,7 +147,7 @@ ecma_builtin_typedarray_prototype_length_getter (ecma_value_t this_arg) /**< thi return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); } /* ecma_builtin_typedarray_prototype_length_getter */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** * The %TypedArray%.prototype[Symbol.toStringTag] accessor * @@ -166,7 +167,7 @@ ecma_builtin_typedarray_prototype_to_string_tag_getter (ecma_value_t this_arg) / return ecma_make_magic_string_value (ecma_object_get_class_name (ecma_get_object_from_value (this_arg))); } /* ecma_builtin_typedarray_prototype_to_string_tag_getter */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Type of routine. @@ -206,6 +207,11 @@ ecma_builtin_typedarray_prototype_exec_routine (ecma_value_t this_arg, /**< this ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_typedarray_getter_fn_t typedarray_getter_cb = ecma_get_typedarray_getter_fn (info.id); @@ -219,47 +225,48 @@ ecma_builtin_typedarray_prototype_exec_routine (ecma_value_t this_arg, /**< this ecma_number_t element_num = typedarray_getter_cb (info.buffer_p + byte_pos); ecma_value_t get_value = ecma_make_number_value (element_num); - JERRY_ASSERT (ecma_is_value_number (get_value)); - ecma_value_t call_args[] = { get_value, current_index, this_arg }; - ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3), ret_value); - - if (mode == TYPEDARRAY_ROUTINE_EVERY) - { - if (!ecma_op_to_boolean (call_value)) - { - ret_value = ECMA_VALUE_FALSE; - } - } - else if (mode == TYPEDARRAY_ROUTINE_SOME - && ecma_op_to_boolean (call_value)) - { - ret_value = ECMA_VALUE_TRUE; - } - - byte_pos += info.element_size; - - ECMA_FINALIZE (call_value); + ecma_value_t call_value = ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3); ecma_fast_free_value (current_index); ecma_fast_free_value (get_value); - } - if (ecma_is_value_empty (ret_value)) - { + if (ECMA_IS_VALUE_ERROR (call_value)) + { + return call_value; + } + + bool to_bool_result = ecma_op_to_boolean (call_value); + ecma_free_value (call_value); + if (mode == TYPEDARRAY_ROUTINE_EVERY) { - ret_value = ECMA_VALUE_TRUE; + if (!to_bool_result) + { + return ECMA_VALUE_FALSE; + } } - else if (mode == TYPEDARRAY_ROUTINE_SOME) + else if (mode == TYPEDARRAY_ROUTINE_SOME + && to_bool_result) { - ret_value = ECMA_VALUE_FALSE; - } - else - { - ret_value = ECMA_VALUE_UNDEFINED; + return ECMA_VALUE_TRUE; } + + byte_pos += info.element_size; + } + + if (mode == TYPEDARRAY_ROUTINE_EVERY) + { + ret_value = ECMA_VALUE_TRUE; + } + else if (mode == TYPEDARRAY_ROUTINE_SOME) + { + ret_value = ECMA_VALUE_FALSE; + } + else + { + ret_value = ECMA_VALUE_UNDEFINED; } return ret_value; @@ -325,8 +332,8 @@ ecma_builtin_typedarray_prototype_for_each (ecma_value_t this_arg, /**< this arg TYPEDARRAY_ROUTINE_FOREACH); } /* ecma_builtin_typedarray_prototype_for_each */ +#if ENABLED (JERRY_ES2015) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) /** * Helper function for typedArray.prototype object's {'keys', 'values', 'entries', '@@iterator'} * routines common parts. @@ -408,7 +415,7 @@ ecma_builtin_typedarray_prototype_entries (ecma_value_t this_arg) /**< this argu return ecma_builtin_typedarray_iterators_helper (this_arg, ECMA_ITERATOR_KEYS_VALUES); } /* ecma_builtin_typedarray_prototype_entries */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * The %TypedArray%.prototype object's 'map' routine @@ -435,11 +442,18 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument } ecma_object_t *src_obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (src_obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t src_info = ecma_typedarray_get_info (src_obj_p); ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val); - ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (src_obj_p, src_info.length); + // TODO: 22.2.3.18, 7-8. + ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (src_info.id, src_info.length); if (ECMA_IS_VALUE_ERROR (new_typedarray)) { @@ -466,6 +480,7 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument { ecma_free_value (current_index); ecma_free_value (get_value); + ecma_free_value (new_typedarray); return mapped_value; } @@ -475,6 +490,7 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument ecma_free_value (mapped_value); ecma_free_value (current_index); ecma_free_value (get_value); + ecma_free_value (new_typedarray); return ECMA_VALUE_ERROR; } else @@ -517,6 +533,12 @@ ecma_builtin_typedarray_prototype_reduce_with_direction (ecma_value_t this_arg, } ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); @@ -691,11 +713,12 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_value_t ret_value = ECMA_VALUE_ERROR; + // TODO: 22.2.3.9, 7-8. if (info.length == 0) { - return ecma_op_create_typedarray_with_type_and_length (obj_p, 0); + return ecma_op_create_typedarray_with_type_and_length (info.id, 0); } JMEM_DEFINE_LOCAL_ARRAY (pass_value_list_p, info.length * info.element_size, lit_utf8_byte_t); @@ -703,7 +726,7 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum lit_utf8_byte_t *pass_value_p = pass_value_list_p; ecma_length_t byte_pos = 0; - for (uint32_t index = 0; index < info.length && ecma_is_value_empty (ret_value); index++) + for (uint32_t index = 0; index < info.length; index++) { ecma_value_t current_index = ecma_make_uint32_value (index); ecma_number_t get_num = getter_cb (info.buffer_p + byte_pos); @@ -713,7 +736,15 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum ecma_value_t call_args[] = { get_value, current_index, this_arg }; - ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3), ret_value); + ecma_value_t call_value = ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3); + + ecma_fast_free_value (current_index); + ecma_fast_free_value (get_value); + + if (ECMA_IS_VALUE_ERROR (call_value)) + { + goto cleanup; + } if (ecma_op_to_boolean (call_value)) { @@ -723,30 +754,25 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum byte_pos += info.element_size; - ECMA_FINALIZE (call_value); - - ecma_fast_free_value (current_index); - ecma_fast_free_value (get_value); + ecma_free_value (call_value); } - if (ecma_is_value_empty (ret_value)) + uint32_t pass_num = (uint32_t) ((pass_value_p - pass_value_list_p) >> info.shift); + + ret_value = ecma_op_create_typedarray_with_type_and_length (info.id, pass_num); + + if (!ECMA_IS_VALUE_ERROR (ret_value)) { - uint32_t pass_num = (uint32_t) ((pass_value_p - pass_value_list_p) >> info.shift); + obj_p = ecma_get_object_from_value (ret_value); - ret_value = ecma_op_create_typedarray_with_type_and_length (obj_p, pass_num); + JERRY_ASSERT (ecma_typedarray_get_offset (obj_p) == 0); - if (!ECMA_IS_VALUE_ERROR (ret_value)) - { - obj_p = ecma_get_object_from_value (ret_value); - - JERRY_ASSERT (ecma_typedarray_get_offset (obj_p) == 0); - - memcpy (ecma_typedarray_get_buffer (obj_p), - pass_value_list_p, - (size_t) (pass_value_p - pass_value_list_p)); - } + memcpy (ecma_typedarray_get_buffer (obj_p), + pass_value_list_p, + (size_t) (pass_value_p - pass_value_list_p)); } +cleanup: JMEM_FINALIZE_LOCAL_ARRAY (pass_value_list_p); return ret_value; @@ -770,6 +796,12 @@ ecma_builtin_typedarray_prototype_reverse (ecma_value_t this_arg) /**< this argu } ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); uint32_t middle = (info.length / 2) << info.shift; @@ -806,14 +838,9 @@ ecma_op_typedarray_set_with_typedarray (ecma_value_t this_arg, /**< this argumen { /* 6.~ 8. targetOffset */ ecma_number_t target_offset_num; - if (!ecma_is_value_empty (ecma_get_number (offset_val, &target_offset_num))) + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (offset_val, &target_offset_num))) { - return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset")); - } - - if (ecma_number_is_nan (target_offset_num)) - { - target_offset_num = 0; + return ECMA_VALUE_ERROR; } if (target_offset_num <= -1.0 || target_offset_num >= (ecma_number_t) UINT32_MAX + 0.5) @@ -822,9 +849,21 @@ ecma_op_typedarray_set_with_typedarray (ecma_value_t this_arg, /**< this argumen } ecma_object_t *target_typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (target_typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t target_info = ecma_typedarray_get_info (target_typedarray_p); ecma_object_t *src_typedarray_p = ecma_get_object_from_value (arr_val); + ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (src_typedarray_p); + if (ecma_arraybuffer_is_detached (src_arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t src_info = ecma_typedarray_get_info (src_typedarray_p); uint32_t target_offset_uint32 = ecma_number_to_uint32 (target_offset_num); @@ -897,12 +936,14 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument } /* 6.~ 8. targetOffset */ - ecma_value_t ret_val = ECMA_VALUE_EMPTY; - ECMA_OP_TO_NUMBER_TRY_CATCH (target_offset_num, offset_val, ret_val); - if (ecma_number_is_nan (target_offset_num)) + ecma_number_t target_offset_num; + ecma_value_t ret_val = ecma_op_to_integer (offset_val, &target_offset_num); + + if (ECMA_IS_VALUE_ERROR (ret_val)) { - target_offset_num = 0; + return ret_val; } + if (target_offset_num <= -1.0 || target_offset_num >= (ecma_number_t) UINT32_MAX + 0.5) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset")); @@ -911,6 +952,12 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument /* 11. ~ 15. */ ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t target_info = ecma_typedarray_get_info (typedarray_p); /* 16.~ 17. */ @@ -923,18 +970,10 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument ecma_op_object_get_by_magic_id (source_obj_p, LIT_MAGIC_STRING_LENGTH), ret_val); - ECMA_OP_TO_NUMBER_TRY_CATCH (source_length_num, source_length, ret_val); - - if (ecma_number_is_nan (source_length_num) || source_length_num <= 0) + uint32_t source_length_uint32; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (source_length, &source_length_uint32))) { - source_length_num = 0; - } - - uint32_t source_length_uint32 = ecma_number_to_uint32 (source_length_num); - - if ((ecma_number_t) source_length_uint32 != source_length_num) - { - return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid source length")); + return ECMA_VALUE_ERROR; } /* 20. if srcLength + targetOffset > targetLength, throw a RangeError */ @@ -951,10 +990,8 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument while (k < source_length_uint32 && ecma_is_value_empty (ret_val)) { - ecma_string_t *k_str_p = ecma_new_ecma_string_from_uint32 (k); - ECMA_TRY_CATCH (elem, - ecma_op_object_get (source_obj_p, k_str_p), + ecma_op_object_get_by_uint32_index (source_obj_p, k), ret_val); ECMA_OP_TO_NUMBER_TRY_CATCH (elem_num, elem, ret_val); @@ -964,16 +1001,12 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument ECMA_OP_TO_NUMBER_FINALIZE (elem_num); ECMA_FINALIZE (elem); - ecma_deref_ecma_string (k_str_p); - k++; target_byte_index += target_info.element_size; } - ECMA_OP_TO_NUMBER_FINALIZE (source_length_num); ECMA_FINALIZE (source_length); ECMA_FINALIZE (source_obj); - ECMA_OP_TO_NUMBER_FINALIZE (target_offset_num); if (ecma_is_value_empty (ret_val)) { @@ -989,35 +1022,32 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument * See also: * ECMA-262 v5.1, 15.4.4.2 * - * @return ecma_value_t value - * Returned value must be freed with ecma_free_value. + * @return NULL - if the converison fails + * ecma_string_t * - otherwise */ -static ecma_value_t +static ecma_string_t * ecma_op_typedarray_get_to_string_at_index (ecma_object_t *obj_p, /**< this object */ uint32_t index) /**< array index */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t index_value = ecma_op_object_get (obj_p, index_string_p); - ecma_deref_ecma_string (index_string_p); + ecma_value_t index_value = ecma_op_object_get_by_uint32_index (obj_p, index); if (ECMA_IS_VALUE_ERROR (index_value)) { - return index_value; + return NULL; } if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) { - ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - } - else - { - ret_value = ecma_op_to_string (index_value); + ecma_free_value (index_value); + return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } + ecma_string_t *ret_str_p = ecma_op_to_string (index_value); + ecma_free_value (index_value); - return ret_value; + + return ret_str_p; } /* ecma_op_typedarray_get_to_string_at_index */ /** @@ -1027,15 +1057,15 @@ ecma_op_typedarray_get_to_string_at_index (ecma_object_t *obj_p, /**< this objec * See also: * ECMA-262 v5.1, 15.4.4.2 4th step * - * @return ecma value - * Returned value must be freed with ecma_free_value. + * @return NULL - if the conversion fails + * ecma_string_t * - otherwise */ -static ecma_value_t +static ecma_string_t * ecma_op_typedarray_get_separator_string (ecma_value_t separator) /**< possible separator */ { if (ecma_is_value_undefined (separator)) { - return ecma_make_magic_string_value (LIT_MAGIC_STRING_COMMA_CHAR); + return ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR); } return ecma_op_to_string (separator); @@ -1073,84 +1103,78 @@ ecma_builtin_typedarray_prototype_join (ecma_value_t this_arg, /**< this argumen return length_value; } - ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_number_t length_number; - ECMA_OP_TO_NUMBER_TRY_CATCH (length_number, - length_value, - ret_value); - - /* 3. */ - uint32_t length = ecma_number_to_uint32 (length_number); - /* 4-5. */ - ecma_value_t separator_value = ecma_op_typedarray_get_separator_string (separator_arg); - if (ECMA_IS_VALUE_ERROR (separator_value)) + if (ECMA_IS_VALUE_ERROR (ecma_get_number (length_value, &length_number))) { ecma_free_value (length_value); ecma_free_value (obj_value); - return separator_value; + return ECMA_VALUE_ERROR; } + ecma_value_t ret_value = ECMA_VALUE_ERROR; + + /* 3. */ + uint32_t length = ecma_number_to_uint32 (length_number); + if (length == 0) { /* 6. */ - ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + ecma_free_value (length_value); + ecma_free_value (obj_value); + return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { - ecma_string_t *separator_string_p = ecma_get_string_from_value (separator_value); + ecma_string_t *separator_string_p = ecma_op_typedarray_get_separator_string (separator_arg); + + if (JERRY_UNLIKELY (separator_string_p == NULL)) + { + goto cleanup; + } /* 7-8. */ - ecma_value_t first_value = ecma_op_typedarray_get_to_string_at_index (obj_p, 0); - if (ECMA_IS_VALUE_ERROR (first_value)) + ecma_string_t *first_string_p = ecma_op_typedarray_get_to_string_at_index (obj_p, 0); + + if (JERRY_UNLIKELY (first_string_p == NULL)) { - ecma_free_value (separator_value); - ecma_free_value (length_value); - ecma_free_value (obj_value); - return first_value; + ecma_deref_ecma_string (separator_string_p); + goto cleanup; } - ecma_string_t *return_string_p = ecma_get_string_from_value (first_value); - ecma_ref_ecma_string (return_string_p); - if (ecma_is_value_empty (ret_value)) + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (first_string_p); + + ecma_deref_ecma_string (first_string_p); + + /* 9-10. */ + for (uint32_t k = 1; k < length; k++) { - /* 9-10. */ - for (uint32_t k = 1; k < length; k++) + /* 10.a */ + ecma_stringbuilder_append (&builder, separator_string_p); + + /* 10.d */ + ecma_string_t *next_string_p = ecma_op_typedarray_get_to_string_at_index (obj_p, k); + + if (JERRY_UNLIKELY (next_string_p == NULL)) { - /* 10.a */ - return_string_p = ecma_concat_ecma_strings (return_string_p, separator_string_p); - - /* 10.b, 10.c */ - ecma_value_t next_string_value = ecma_op_typedarray_get_to_string_at_index (obj_p, k); - if (ECMA_IS_VALUE_ERROR (next_string_value)) - { - ecma_deref_ecma_string (return_string_p); - ecma_free_value (first_value); - ecma_free_value (separator_value); - ecma_free_value (length_value); - ecma_free_value (obj_value); - return next_string_value; - } - - /* 10.d */ - ecma_string_t *next_string_p = ecma_get_string_from_value (next_string_value); - return_string_p = ecma_concat_ecma_strings (return_string_p, next_string_p); - - ecma_free_value (next_string_value); + ecma_stringbuilder_destroy (&builder); + ecma_deref_ecma_string (separator_string_p); + goto cleanup; } - ret_value = ecma_make_string_value (return_string_p); - } - else - { - ecma_deref_ecma_string (return_string_p); + + ecma_stringbuilder_append (&builder, next_string_p); + + ecma_deref_ecma_string (next_string_p); } - ecma_free_value (first_value); + ecma_deref_ecma_string (separator_string_p); + ret_value = ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } - ecma_free_value (separator_value); - ECMA_OP_TO_NUMBER_FINALIZE (length_number); +cleanup: ecma_free_value (length_value); ecma_free_value (obj_value); + return ret_value; } /* ecma_builtin_typedarray_prototype_join */ @@ -1233,9 +1257,12 @@ ecma_builtin_typedarray_prototype_subarray (ecma_value_t this_arg, /**< this arg uint32_t begin_index_uint32 = 0, end_index_uint32 = 0; /* 7. relativeBegin */ - ECMA_OP_TO_NUMBER_TRY_CATCH (relative_begin, begin, ret_value); - - begin_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_begin, info.length, false); + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (begin, + info.length, + &begin_index_uint32))) + { + return ECMA_VALUE_ERROR; + } if (ecma_is_value_undefined (end)) { @@ -1244,15 +1271,14 @@ ecma_builtin_typedarray_prototype_subarray (ecma_value_t this_arg, /**< this arg else { /* 10. relativeEnd */ - ECMA_OP_TO_NUMBER_TRY_CATCH (relative_end, end, ret_value); - - end_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_end, info.length, false); - - ECMA_OP_TO_NUMBER_FINALIZE (relative_end); + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (end, + info.length, + &end_index_uint32))) + { + return ECMA_VALUE_ERROR; + } } - ECMA_OP_TO_NUMBER_FINALIZE (relative_begin); - if (!ecma_is_value_empty (ret_value)) { return ret_value; @@ -1316,9 +1342,12 @@ ecma_builtin_typedarray_prototype_fill (ecma_value_t this_arg, /**< this argumen uint32_t begin_index_uint32 = 0, end_index_uint32 = 0; - ECMA_OP_TO_NUMBER_TRY_CATCH (relative_begin, begin, ret_value); - - begin_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_begin, info.length, false); + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (begin, + info.length, + &begin_index_uint32))) + { + return ECMA_VALUE_ERROR; + } if (ecma_is_value_undefined (end)) { @@ -1326,18 +1355,12 @@ ecma_builtin_typedarray_prototype_fill (ecma_value_t this_arg, /**< this argumen } else { - ECMA_OP_TO_NUMBER_TRY_CATCH (relative_end, end, ret_value); - - end_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_end, info.length, false); - - ECMA_OP_TO_NUMBER_FINALIZE (relative_end); - } - - ECMA_OP_TO_NUMBER_FINALIZE (relative_begin); - - if (!ecma_is_value_empty (ret_value)) - { - return ret_value; + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (end, + info.length, + &end_index_uint32))) + { + return ECMA_VALUE_ERROR; + } } ecma_length_t subarray_length = 0; @@ -1476,6 +1499,11 @@ ecma_builtin_typedarray_prototype_sort (ecma_value_t this_arg, /**< this argumen } ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); if (!info.length) @@ -1577,6 +1605,11 @@ ecma_builtin_typedarray_prototype_find_helper (ecma_value_t this_arg, /**< this ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } uint32_t buffer_index = 0; uint32_t limit = info.length * info.element_size; @@ -1655,84 +1688,6 @@ ecma_builtin_typedarray_prototype_find_index (ecma_value_t this_arg, /**< this a return ecma_builtin_typedarray_prototype_find_helper (this_arg, predicate, predicate_this_arg, false); } /* ecma_builtin_typedarray_prototype_find_index */ -/** - * The %TypedArray%.prototype object's 'indexOf' and 'lastIndexOf' routine helper - * - * See also: - * ECMA-262 v6, 22.2.3.13, 22.2.3.16 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_typedarray_prototype_index_helper (ecma_value_t this_arg, /**< this argument */ - const ecma_value_t args[], /**< arguments list */ - ecma_length_t args_number, /**< number of arguments */ - bool is_last_index_of) /**< true - lastIndexOf routine - false - indexOf routine */ -{ - if (!ecma_is_typedarray (this_arg)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); - } - - ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); - ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); - uint32_t limit = info.length * info.element_size; - uint32_t from_index; - - if (args_number == 0 - || !ecma_is_value_number (args[0]) - || info.length == 0) - { - return ecma_make_integer_value (-1); - } - if (args_number == 1) - { - from_index = is_last_index_of ? info.length - 1 : 0; - } - else - { - ecma_number_t num_var; - - if (ECMA_IS_VALUE_ERROR (ecma_get_number (args[1], &num_var))) - { - return ECMA_VALUE_ERROR; - } - - if (!ecma_number_is_nan (num_var) - && is_last_index_of - && num_var < 0 - && fabs (num_var) > info.length) - { - return ecma_make_integer_value (-1); - } - else - { - from_index = ecma_builtin_helper_array_index_normalize (num_var, info.length, is_last_index_of); - } - } - - ecma_number_t search_num = ecma_get_number_from_value (args[0]); - - int32_t increment = is_last_index_of ? -info.element_size : info.element_size; - ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); - - for (int32_t position = (int32_t) from_index * info.element_size; - (is_last_index_of ? position >= 0 : (uint32_t) position < limit); - position += increment) - { - ecma_number_t element_num = getter_cb (info.buffer_p + position); - - if (search_num == element_num) - { - return ecma_make_number_value ((ecma_number_t) position / info.element_size); - } - } - - return ecma_make_integer_value (-1); -} /* ecma_builtin_typedarray_prototype_index_helper */ - /** * The %TypedArray%.prototype object's 'indexOf' routine * @@ -1744,10 +1699,73 @@ ecma_builtin_typedarray_prototype_index_helper (ecma_value_t this_arg, /**< this */ static ecma_value_t ecma_builtin_typedarray_prototype_index_of (ecma_value_t this_arg, /**< this argument */ - const ecma_value_t args[], /**< arguments list */ - ecma_length_t args_number) /**< number of arguments */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ { - return ecma_builtin_typedarray_prototype_index_helper (this_arg, args, args_number, false); + if (!ecma_is_typedarray (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); + } + + ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); + if (ecma_arraybuffer_is_detached (info.array_buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + + uint32_t limit = info.length * info.element_size; + uint32_t from_index; + + /* 5. */ + if (args_number == 0 + || !ecma_is_value_number (args[0]) + || info.length == 0) + { + return ecma_make_integer_value (-1); + } + if (args_number == 1) + { + from_index = 0; + } + else + { + /* 6. 7. */ + ecma_number_t num_var; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &num_var))) + { + return ECMA_VALUE_ERROR; + } + /* 8. */ + if (num_var >= info.length) + { + return ecma_make_integer_value (-1); + } + + /* 9. 10. */ + from_index = ((num_var >= 0) ? (uint32_t) num_var + : (uint32_t) (info.length + num_var)); + } + + ecma_number_t search_num = ecma_get_number_from_value (args[0]); + + ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); + + /* 11. */ + for (int32_t position = (int32_t) from_index * info.element_size; + (uint32_t) position < limit; + position += info.element_size) + { + ecma_number_t element_num = getter_cb (info.buffer_p + position); + + if (search_num == element_num) + { + return ecma_make_number_value ((ecma_number_t) position / info.element_size); + } + } + + /* 12. */ + return ecma_make_integer_value (-1); } /* ecma_builtin_typedarray_prototype_index_of */ /** @@ -1764,40 +1782,72 @@ ecma_builtin_typedarray_prototype_last_index_of (ecma_value_t this_arg, /**< thi const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { - return ecma_builtin_typedarray_prototype_index_helper (this_arg, args, args_number, true); -} /* ecma_builtin_typedarray_prototype_last_index_of */ - -/** - * Helper function to get the uint32_t value from an argument. - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_get_uint32_value_from_argument (ecma_value_t arg_value, /**< this argument */ - uint32_t length, /**< length of the TypedArray */ - uint32_t *index, /**< [out] pointer to the given index */ - bool is_end_index) /**< true - normalize the end index */ -{ - ecma_number_t num_var; - ecma_value_t ret_value = ecma_get_number (arg_value, &num_var); - - if (ECMA_IS_VALUE_ERROR (ret_value)) + if (!ecma_is_typedarray (this_arg)) { - return ret_value; + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); } - if (is_end_index && ecma_number_is_nan (num_var)) + ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); + if (ecma_arraybuffer_is_detached (info.array_buffer_p)) { - *index = length; + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + + uint32_t from_index; + + /* 5. */ + if (args_number == 0 + || !ecma_is_value_number (args[0]) + || info.length == 0) + { + return ecma_make_integer_value (-1); + } + + if (args_number == 1) + { + from_index = info.length - 1; } else { - *index = ecma_builtin_helper_array_index_normalize (num_var, length, false); + /* 6. 7. */ + ecma_number_t num_var; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (args[1], &num_var))) + { + return ECMA_VALUE_ERROR; + } + + if (!ecma_number_is_nan (num_var) + && -num_var > info.length) + { + return ecma_make_integer_value (-1); + } + + /* 8. 9. */ + from_index = ((num_var >= 0) ? (uint32_t) JERRY_MIN (num_var, info.length - 1) + : (uint32_t) (info.length + num_var)); } - return ECMA_VALUE_EMPTY; -} /* ecma_builtin_get_uint32_value_from_argument */ + ecma_number_t search_num = ecma_get_number_from_value (args[0]); + + ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); + + /* 10. */ + for (int32_t position = (int32_t) from_index * info.element_size; + position >= 0; + position += -info.element_size) + { + ecma_number_t element_num = getter_cb (info.buffer_p + position); + + if (search_num == element_num) + { + return ecma_make_number_value ((ecma_number_t) position / info.element_size); + } + } + + /* 11. */ + return ecma_make_integer_value (-1); +} /* ecma_builtin_typedarray_prototype_last_index_of */ /** * The %TypedArray%.prototype object's 'copyWithin' routine @@ -1820,61 +1870,52 @@ ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); - uint32_t target = 0; - uint32_t start = 0; - uint32_t end = info.length; + uint32_t relative_target = 0; + uint32_t relative_start = 0; + uint32_t relative_end = info.length; if (args_number > 0) { - ecma_value_t target_value = ecma_builtin_get_uint32_value_from_argument (args[0], - info.length, - &target, - false); - - if (ECMA_IS_VALUE_ERROR (target_value)) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0], + info.length, + &relative_target))) { - return target_value; + return ECMA_VALUE_ERROR; } if (args_number > 1) { - ecma_value_t start_value = ecma_builtin_get_uint32_value_from_argument (args[1], - info.length, - &start, - false); - - if (ECMA_IS_VALUE_ERROR (start_value)) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[1], + info.length, + &relative_start))) { - return start_value; + return ECMA_VALUE_ERROR; } - if (args_number > 2) + if (args_number > 2 && args[2] != ECMA_VALUE_UNDEFINED) { - ecma_value_t end_value = ecma_builtin_get_uint32_value_from_argument (args[2], - info.length, - &end, - true); - - if (ECMA_IS_VALUE_ERROR (end_value)) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[2], + info.length, + &relative_end))) { - return end_value; + return ECMA_VALUE_ERROR; } } } } - if (target >= info.length || start >= end || end == 0) + if (relative_target >= info.length || relative_start >= relative_end || relative_end == 0) { return ecma_copy_value (this_arg); } else { - uint32_t distance = end - start; - uint32_t offset = info.length - target; + uint32_t distance = relative_end - relative_start; + uint32_t offset = info.length - relative_target; uint32_t count = JERRY_MIN (distance, offset); - memmove (info.buffer_p + (target * info.element_size), - info.buffer_p + (start * info.element_size), + memmove (info.buffer_p + (relative_target * info.element_size), + info.buffer_p + (relative_start * info.element_size), (size_t) (count * info.element_size)); } @@ -1901,40 +1942,40 @@ ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argume } ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); - uint32_t start = 0; - uint32_t end = info.length; + uint32_t relative_start = 0; + uint32_t relative_end = info.length; if (args_number > 0) { - ecma_value_t start_value = ecma_builtin_get_uint32_value_from_argument (args[0], - info.length, - &start, - false); - - if (ECMA_IS_VALUE_ERROR (start_value)) + if (ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[0], + info.length, + &relative_start))) { - return start_value; + return ECMA_VALUE_ERROR; } - if (args_number > 1) + if (args_number > 1 + && args[1] != ECMA_VALUE_UNDEFINED + && ECMA_IS_VALUE_ERROR (ecma_builtin_helper_array_index_normalize (args[1], + info.length, + &relative_end))) { - ecma_value_t end_value = ecma_builtin_get_uint32_value_from_argument (args[1], - info.length, - &end, - true); - - if (ECMA_IS_VALUE_ERROR (end_value)) - { - return end_value; - } + return ECMA_VALUE_ERROR; } } - int32_t distance = (int32_t) (end - start); + int32_t distance = (int32_t) (relative_end - relative_start); uint32_t count = distance > 0 ? (uint32_t) distance : 0; - ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (typedarray_p, count); + // TODO: 22.2.3.23, 12-13. + ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (info.id, count); if (ECMA_IS_VALUE_ERROR (new_typedarray)) { @@ -1944,8 +1985,9 @@ ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argume if (count > 0) { ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); + lit_utf8_byte_t *new_typedarray_buffer_p = ecma_typedarray_get_buffer (new_typedarray_p); - uint32_t src_byte_index = (start * info.element_size); + uint32_t src_byte_index = (relative_start * info.element_size); memcpy (new_typedarray_buffer_p, info.buffer_p + src_byte_index, @@ -2008,8 +2050,17 @@ ecma_builtin_typedarray_prototype_to_locale_string_helper (ecma_object_t *this_o return call_value; } - ret_value = ecma_op_to_string (call_value); - ecma_free_value (call_value); + ecma_string_t *str_p = ecma_op_to_string (call_value); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + ecma_free_value (element_value); + ecma_deref_object (element_obj_p); + return ECMA_VALUE_ERROR; + } + + ret_value = ecma_make_string_value (str_p); + ecma_deref_ecma_string (str_p); } else { @@ -2056,24 +2107,26 @@ ecma_builtin_typedarray_prototype_to_locale_string (ecma_value_t this_arg) /**< } ecma_string_t *return_string_p = ecma_get_string_from_value (first_element); + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (return_string_p); + ecma_deref_ecma_string (return_string_p); for (uint32_t k = info.element_size; k < limit; k += info.element_size) { - return_string_p = ecma_append_magic_string_to_string (return_string_p, LIT_MAGIC_STRING_COMMA_CHAR); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COMMA); ecma_value_t next_element = ecma_builtin_typedarray_prototype_to_locale_string_helper (typedarray_p, k); if (ECMA_IS_VALUE_ERROR (next_element)) { - ecma_deref_ecma_string (return_string_p); + ecma_stringbuilder_destroy (&builder); return next_element; } ecma_string_t *next_element_p = ecma_get_string_from_value (next_element); - return_string_p = ecma_concat_ecma_strings (return_string_p, next_element_p); + ecma_stringbuilder_append (&builder, next_element_p); ecma_deref_ecma_string (next_element_p); } - return ecma_make_string_value (return_string_p); + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_builtin_typedarray_prototype_to_locale_string */ /** diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h index 7ca5b43a..954a6095 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h @@ -30,27 +30,27 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, /* ES2015 22.2.3.1 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BUFFER, ecma_builtin_typedarray_prototype_buffer_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ES2015 22.2.3.2 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_LENGTH_UL, ecma_builtin_typedarray_prototype_bytelength_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ES2015 22.2.3.3 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_OFFSET_UL, ecma_builtin_typedarray_prototype_byteoffset_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ES2015 22.2.3.17 */ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_LENGTH, ecma_builtin_typedarray_prototype_length_getter, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 23.1.3.13 */ ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, ecma_builtin_typedarray_prototype_to_string_tag_getter, ECMA_PROPERTY_FLAG_CONFIGURABLE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ @@ -76,14 +76,14 @@ ROUTINE (LIT_MAGIC_STRING_COPY_WITHIN, ecma_builtin_typedarray_prototype_copy_wi ROUTINE (LIT_MAGIC_STRING_SLICE, ecma_builtin_typedarray_prototype_slice, NON_FIXED, 2) ROUTINE (LIT_MAGIC_STRING_TO_LOCALE_STRING_UL, ecma_builtin_typedarray_prototype_to_locale_string, 0, 0) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) ROUTINE (LIT_MAGIC_STRING_KEYS, ecma_builtin_typedarray_prototype_keys, 0, 0) ROUTINE (LIT_MAGIC_STRING_VALUES, ecma_builtin_typedarray_prototype_values, 0, 0) ROUTINE (LIT_MAGIC_STRING_ENTRIES, ecma_builtin_typedarray_prototype_entries, 0, 0) ROUTINE (LIT_GLOBAL_SYMBOL_ITERATOR, ecma_builtin_typedarray_prototype_values, 0, 0) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-template.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-template.inc.h index f1ba7406..f4e16127 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-template.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-template.inc.h @@ -32,18 +32,13 @@ /* ES2015 22.2.5 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 3, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ES2015 22.2.5.1 */ NUMBER_VALUE (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U, TYPEDARRAY_BYTES_PER_ELEMENT, ECMA_PROPERTY_FIXED) -/* ES2015 22.2.5 */ -NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, - 3, - ECMA_PROPERTY_FIXED) - /* ES2015 22.2.5 */ STRING_VALUE (LIT_MAGIC_STRING_NAME, TYPEDARRAY_MAGIC_STRING_ID, diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c index 613c8522..d30c0104 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "ecma-typedarray-object.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-gc.h" @@ -127,13 +128,58 @@ ecma_builtin_typedarray_of (ecma_value_t this_arg, /**< 'this' argument */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { - JERRY_UNUSED (this_arg); - JERRY_UNUSED (arguments_list_p); - JERRY_UNUSED (arguments_list_len); + if (!ecma_is_constructor (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a constructor.")); + } - /* TODO: implement 'of' */ + ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + const uint8_t builtin_id = ecma_get_object_builtin_id (obj_p); - return ECMA_VALUE_UNDEFINED; + if (!ecma_typedarray_helper_is_typedarray (builtin_id)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a typedarray constructor")); + } + + ecma_typedarray_type_t typedarray_id = ecma_typedarray_helper_builtin_to_typedarray_id (builtin_id); + + ecma_object_t *proto_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (typedarray_id)); + const uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (typedarray_id); + + ecma_value_t ret_val = ecma_typedarray_create_object_with_length (arguments_list_len, + NULL, + proto_p, + element_size_shift, + typedarray_id); + + if (ECMA_IS_VALUE_ERROR (ret_val)) + { + return ret_val; + } + + uint32_t k = 0; + ecma_object_t *ret_obj_p = ecma_get_object_from_value (ret_val); + ecma_typedarray_info_t info = ecma_typedarray_get_info (ret_obj_p); + ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id); + + while (k < arguments_list_len) + { + ecma_number_t num; + ecma_value_t next_val = ecma_get_number (arguments_list_p[k], &num); + + if (ECMA_IS_VALUE_ERROR (next_val)) + { + ecma_deref_object (ret_obj_p); + return next_val; + } + + setter_cb (info.buffer_p, num); + + k++; + info.buffer_p += info.element_size; + } + + return ret_val; } /* ecma_builtin_typedarray_of */ /** @@ -170,6 +216,18 @@ ecma_builtin_typedarray_dispatch_construct (const ecma_value_t *arguments_list_p return ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray intrinstic cannot be called by a 'new' expression")); } /* ecma_builtin_typedarray_dispatch_construct */ +/** + * 22.2.2.4 get %TypedArray% [ @@species ] accessor + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_builtin_typedarray_species_get (ecma_value_t this_value) /**< This Value */ +{ + return ecma_copy_value (this_value); +} /* ecma_builtin_typedarray_species_get */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h index 36cf1eaf..e46a1852 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h @@ -24,7 +24,7 @@ /* ES2015 22.2.2 */ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, 3, - ECMA_PROPERTY_FIXED) + ECMA_PROPERTY_FLAG_CONFIGURABLE) /* ES2015 22.2.2 */ STRING_VALUE (LIT_MAGIC_STRING_NAME, @@ -45,6 +45,11 @@ ROUTINE (LIT_MAGIC_STRING_FROM, ecma_builtin_typedarray_from, NON_FIXED, 1) /* ES2015 22.2.2.2 */ ROUTINE (LIT_MAGIC_STRING_OF, ecma_builtin_typedarray_of, NON_FIXED, 0) +/* ES2015 22.2.2.4 */ +ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES, + ecma_builtin_typedarray_species_get, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 03a7b2e3..4d5dd6a8 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -15,6 +15,7 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" +#include "ecma-iterator-object.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" @@ -34,6 +35,32 @@ * @{ */ +#if ENABLED (JERRY_CPOINTER_32_BIT) +/** + * Maximum length of the array length to allocate fast mode access for it + * e.g. new Array(5000) is constructed as fast mode access array, + * but new Array(50000000) is consturcted as normal property list based array + */ +#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 17) +#else /* ENABLED (JERRY_CPOINTER_32_BIT) */ +/** + * Maximum length of the array length to allocate fast mode access for it + * e.g. new Array(5000) is constructed as fast mode access array, + * but new Array(50000000) is consturcted as normal property list based array + */ +#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 13) +#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ + +/** + * Property name type flag for array indices. + */ +#define ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE 0x80 + +/** + * Property attribute for the array 'length' virtual property to indicate fast access mode array + */ +#define ECMA_FAST_ARRAY_FLAG (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT) + /** * Allocate a new array object with the given length * @@ -46,7 +73,7 @@ ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */ ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* !ENABLED (JERRY_BUILTIN_ARRAY) */ ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); -#endif /* (ENABLED (JERRY_BUILTIN_ARRAY)) */ +#endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ ecma_object_t *object_p = ecma_create_object (array_prototype_object_p, sizeof (ecma_extended_object_t), @@ -60,13 +87,39 @@ ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */ ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; ext_obj_p->u.array.length = length; - ext_obj_p->u.array.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; - ext_obj_p->u.array.is_fast_mode = false; - ext_obj_p->u.array.hole_count = 0; + ext_obj_p->u.array.u.hole_count = 0; + ext_obj_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; return object_p; } /* ecma_op_new_array_object */ +/** + * Check whether the given object is fast-access mode array + * + * @return true - if the object is fast-access mode array + * false, otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_object_is_fast_array (ecma_object_t *object_p) /**< ecma-object */ +{ + return (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY && + ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p)); +} /* ecma_op_object_is_fast_array */ + +/** + * Check whether the given array object is fast-access mode array + * + * @return true - if the array object is fast-access mode array + * false, otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_array_is_fast_array (ecma_extended_object_t *array_p) /**< ecma-array-object */ +{ + JERRY_ASSERT (ecma_get_object_type ((ecma_object_t *) array_p) == ECMA_OBJECT_TYPE_ARRAY); + + return array_p->u.array.u.length_prop & ECMA_FAST_ARRAY_FLAG; +} /* ecma_op_array_is_fast_array */ + /** * Allocate a new fast access mode array object with the given length * @@ -90,9 +143,10 @@ ecma_op_new_fast_array_object (ecma_length_t length) /**< length of the new fast } ecma_object_t *object_p = ecma_op_new_array_object (length); - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - ext_obj_p->u.array.is_fast_mode = true; + + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG); + ext_obj_p->u.array.u.hole_count += length * ECMA_FAST_ARRAY_HOLE_ONE; JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL); @@ -105,26 +159,19 @@ ecma_op_new_fast_array_object (ecma_length_t length) /**< length of the new fast return object_p; } /* ecma_op_new_fast_array_object */ -/** - * Property name type flag for array indices. - */ -#define ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE 0x80 - /** * Converts a fast access mode array back to a normal property list based array */ void ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mode array object */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - if (object_p->u1.property_list_cp == JMEM_CP_NULL) { - ext_obj_p->u.array.is_fast_mode = false; + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG); return; } @@ -132,15 +179,6 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length); ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - /* Check whether the buffer contains only array holes */ - if (JERRY_UNLIKELY (ext_obj_p->u.array.length == ext_obj_p->u.array.hole_count)) - { - ext_obj_p->u.array.is_fast_mode = false; - jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); - object_p->u1.property_list_cp = JMEM_CP_NULL; - return; - } - ecma_ref_object (object_p); ecma_property_pair_t *property_pair_p = NULL; @@ -179,29 +217,13 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod prop_index = !prop_index; } - ext_obj_p->u.array.is_fast_mode = false; + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG); jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); ECMA_SET_POINTER (object_p->u1.property_list_cp, property_pair_p); ecma_deref_object (object_p); } /* ecma_fast_array_convert_to_normal */ -#if ENABLED (JERRY_SYSTEM_ALLOCATOR) -/** - * Maximum length of the array length to allocate fast mode access for it - * e.g. new Array(5000) is constructed as fast mode access array, - * but new Array(50000000) is consturcted as normal property list based array - */ -#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 17) -#else -/** - * Maximum length of the array length to allocate fast mode access for it - * e.g. new Array(5000) is constructed as fast mode access array, - * but new Array(50000000) is consturcted as normal property list based array - */ -#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 13) -#endif - /** * [[Put]] operation for a fast access mode array * @@ -212,24 +234,16 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod */ bool ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode array object */ - ecma_string_t *property_name_p, /**< property name */ + uint32_t index, /**< property name index */ ecma_value_t value) /**< value to be set */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - - uint32_t index = ecma_string_get_array_index (property_name_p); - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - - if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) - { - ecma_fast_array_convert_to_normal (object_p); - return false; - } + uint32_t old_length = ext_obj_p->u.array.length; ecma_value_t *values_p; - if (JERRY_LIKELY (index < ext_obj_p->u.array.length)) + if (JERRY_LIKELY (index < old_length)) { JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL); @@ -237,7 +251,7 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr if (ecma_is_value_array_hole (values_p[index])) { - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MAX (ext_obj_p->u.array.hole_count - 1, 0); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } else { @@ -249,10 +263,21 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr return true; } - uint32_t new_holes = index - ext_obj_p->u.array.length; - uint32_t old_length = ext_obj_p->u.array.length; + uint32_t old_holes = ext_obj_p->u.array.u.hole_count; + uint32_t new_holes = index - old_length; + + if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT + || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) + { + ecma_fast_array_convert_to_normal (object_p); + + return false; + } + uint32_t new_length = index + 1; + JERRY_ASSERT (new_length < UINT32_MAX); + const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length); if (JERRY_LIKELY (index < aligned_length)) @@ -260,24 +285,15 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL); values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); + /* This area is filled with ECMA_VALUE_ARRAY_HOLE, but not counted in u.array.u.hole_count */ JERRY_ASSERT (ecma_is_value_array_hole (values_p[index])); + ext_obj_p->u.array.u.hole_count += new_holes * ECMA_FAST_ARRAY_HOLE_ONE; ext_obj_p->u.array.length = new_length; - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MIN (ext_obj_p->u.array.hole_count + new_holes, - ECMA_FAST_ARRAY_MAX_HOLE_COUNT); } else { - JERRY_ASSERT (ext_obj_p->u.array.hole_count <= ECMA_FAST_ARRAY_MAX_HOLE_COUNT); - - if (new_holes > (uint32_t) (ECMA_FAST_ARRAY_MAX_HOLE_COUNT - ext_obj_p->u.array.hole_count)) - { - ecma_fast_array_convert_to_normal (object_p); - - return false; - } - values_p = ecma_fast_array_extend (object_p, new_length); - ext_obj_p->u.array.hole_count = (uint8_t) (ext_obj_p->u.array.hole_count + new_holes); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } values_p[index] = ecma_copy_value_if_not_object (value); @@ -285,6 +301,18 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr return true; } /* ecma_fast_array_set_property */ +/** + * Get the number of array holes in a fast access array object + * + * @return number of array holes in a fast access array object + */ +inline uint32_t JERRY_ATTR_ALWAYS_INLINE +ecma_fast_array_get_hole_count (ecma_object_t *obj_p) /**< fast access mode array object */ +{ + JERRY_ASSERT (ecma_op_object_is_fast_array (obj_p)); + + return ((ecma_extended_object_t *) obj_p)->u.array.u.hole_count >> ECMA_FAST_ARRAY_HOLE_SHIFT; +} /* ecma_fast_array_get_hole_count */ /** * Extend the underlying buffer of a fast mode access array for the given new length @@ -295,11 +323,10 @@ ecma_value_t * ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t new_length) /**< new length of the fast access mode array */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; uint32_t old_length = ext_obj_p->u.array.length; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); JERRY_ASSERT (old_length < new_length); ecma_ref_object (object_p); @@ -325,9 +352,10 @@ ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array obj new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; } + ext_obj_p->u.array.u.hole_count += (new_length - old_length) * ECMA_FAST_ARRAY_HOLE_ONE; ext_obj_p->u.array.length = new_length; - ECMA_SET_POINTER (object_p->u1.property_list_cp, new_values_p); + ECMA_SET_NON_NULL_POINTER (object_p->u1.property_list_cp, new_values_p); ecma_deref_object (object_p); return new_values_p; @@ -346,7 +374,7 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - if (!ext_obj_p->u.array.is_fast_mode) + if (!ecma_op_object_is_fast_array (object_p)) { ecma_delete_property (object_p, prop_value_p); return; @@ -368,22 +396,8 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ ecma_free_value_if_not_object (values_p[index]); - if (JERRY_UNLIKELY (ext_obj_p->u.array.length == 1)) - { - const uint32_t old_length_aligned = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_obj_p->u.array.length); - jmem_heap_free_block (values_p, old_length_aligned * sizeof (ecma_value_t)); - ext_obj_p->u.array.hole_count = 0; - ext_obj_p->u.array.length = 0; - object_p->u1.property_list_cp = JMEM_CP_NULL; - return; - } - values_p[index] = ECMA_VALUE_ARRAY_HOLE; - - if (++ext_obj_p->u.array.hole_count > ECMA_FAST_ARRAY_MAX_HOLE_COUNT) - { - ecma_fast_array_convert_to_normal (object_p); - } + ext_obj_p->u.array.u.hole_count += ECMA_FAST_ARRAY_HOLE_ONE; } /* ecma_array_object_delete_property */ /** @@ -391,43 +405,26 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ * * @return the updated value of new_length */ -static uint32_t +uint32_t ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mode array */ uint32_t new_length) /**< new length of the fast access mode array */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - ecma_ref_object (object_p); ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); uint32_t old_length = ext_obj_p->u.array.length; const uint32_t old_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length); JERRY_ASSERT (new_length < old_length); - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - - if (new_length == 0) - { - for (uint32_t i = 0; i < old_length; i++) - { - ecma_free_value_if_not_object (values_p[i]); - } - - jmem_heap_free_block (values_p, old_aligned_length * sizeof (ecma_value_t)); - object_p->u1.property_list_cp = JMEM_CP_NULL; - ext_obj_p->u.array.length = new_length; - ecma_deref_object (object_p); - return new_length; - } for (uint32_t i = new_length; i < old_length; i++) { if (ecma_is_value_array_hole (values_p[i])) { - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MAX (ext_obj_p->u.array.hole_count - 1, 0); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } else { @@ -435,21 +432,33 @@ ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mod } } - const uint32_t new_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length); + jmem_cpointer_t new_property_list_cp; - ecma_value_t *new_values_p; - new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p, - old_aligned_length * sizeof (ecma_value_t), - new_aligned_length * sizeof (ecma_value_t)); - - for (uint32_t i = new_length; i < new_aligned_length; i++) + if (new_length == 0) { - new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; + jmem_heap_free_block (values_p, old_aligned_length * sizeof (ecma_value_t)); + new_property_list_cp = JMEM_CP_NULL; + } + else + { + const uint32_t new_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length); + + ecma_value_t *new_values_p; + new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p, + old_aligned_length * sizeof (ecma_value_t), + new_aligned_length * sizeof (ecma_value_t)); + + for (uint32_t i = new_length; i < new_aligned_length; i++) + { + new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; + } + + ECMA_SET_NON_NULL_POINTER (new_property_list_cp, new_values_p); } ext_obj_p->u.array.length = new_length; + object_p->u1.property_list_cp = new_property_list_cp; - ECMA_SET_POINTER (object_p->u1.property_list_cp, new_values_p); ecma_deref_object (object_p); return new_length; @@ -465,12 +474,11 @@ static void ecma_fast_array_set_length (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t new_length) /**< new length of the fast access mode array object*/ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; uint32_t old_length = ext_obj_p->u.array.length; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); JERRY_ASSERT (new_length >= old_length); if (new_length == old_length) @@ -478,18 +486,18 @@ ecma_fast_array_set_length (ecma_object_t *object_p, /**< fast access mode array return; } - uint32_t new_holes = new_length - old_length - 1; + uint32_t old_holes = ext_obj_p->u.array.u.hole_count; + uint32_t new_holes = new_length - old_length; - JERRY_ASSERT (ext_obj_p->u.array.hole_count <= ECMA_FAST_ARRAY_MAX_HOLE_COUNT); - - if (new_holes > (uint32_t) (ECMA_FAST_ARRAY_MAX_HOLE_COUNT - ext_obj_p->u.array.hole_count)) + if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT + || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) { ecma_fast_array_convert_to_normal (object_p); - return; } - - ecma_fast_array_extend (object_p, new_length); - ext_obj_p->u.array.hole_count = (uint8_t) (ext_obj_p->u.array.hole_count + new_holes); + else + { + ecma_fast_array_extend (object_p, new_length); + } return; } /* ecma_fast_array_set_length */ @@ -506,19 +514,17 @@ ecma_collection_t * ecma_fast_array_get_property_names (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t opts) /**< any combination of ecma_list_properties_options_t values */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - ecma_collection_t *ret_p = ecma_new_collection (); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - if (opts & ECMA_LIST_SYMBOLS) +#if ENABLED (JERRY_ES2015) + if (opts & ECMA_LIST_SYMBOLS_ONLY) { return ret_p; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint32_t length = ext_obj_p->u.array.length; @@ -618,7 +624,7 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of return ecma_make_object_value (ecma_op_new_array_object (length)); } - JERRY_ASSERT (((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); return ecma_make_object_value (object_p); } @@ -645,6 +651,7 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of } ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; for (uint32_t index = 0; index < array_items_count; @@ -654,10 +661,12 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of values_p[index] = ecma_copy_value_if_not_object (array_items_p[index]); } + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * array_items_count; + return ecma_make_object_value (object_p); } /* ecma_op_create_array_object */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) /** * Array object creation with custom prototype. * @@ -667,28 +676,108 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, /**< list of arguments that - * are passed to - * Array constructor */ - ecma_length_t arguments_list_len, /**< length of the arguments' list */ - bool is_treat_single_arg_as_length, /**< if the value is true, - * arguments_list_len is 1 - * and single argument is Number, - * then treat the single argument - * as new Array's length rather - * than as single item of the - * Array */ - ecma_object_t *object_p) /**< The object from whom the new array object - * is being created */ +ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object from whom the new array object + * is being created */ + ecma_length_t length) /**< length of the array */ { - /* TODO: Use @@species after Symbol has been implemented */ - JERRY_UNUSED (object_p); + ecma_value_t constructor = ECMA_VALUE_UNDEFINED; + ecma_value_t original_array = ecma_make_object_value (original_array_p); - return ecma_op_create_array_object (arguments_list_p, - arguments_list_len, - is_treat_single_arg_as_length); -} /* ecma_op_create_array_object_by_constructor */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + ecma_value_t is_array = ecma_is_value_array (original_array); + + if (ECMA_IS_VALUE_ERROR (is_array)) + { + return is_array; + } + + if (ecma_is_value_true (is_array)) + { + constructor = ecma_op_object_get_by_magic_id (original_array_p, LIT_MAGIC_STRING_CONSTRUCTOR); + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_constructor (constructor) + && ecma_get_object_from_value (constructor) == ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY)) + { + ecma_free_value (constructor); + constructor = ECMA_VALUE_UNDEFINED; + } + else if (ecma_is_value_object (constructor)) + { + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + constructor = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_GLOBAL_SYMBOL_SPECIES); + ecma_deref_object (ctor_object_p); + + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_value_null (constructor)) + { + constructor = ECMA_VALUE_UNDEFINED; + } + } + } + + if (ecma_is_value_undefined (constructor)) + { + ecma_value_t length_val = ecma_make_uint32_value (length); + ecma_value_t new_array = ecma_op_create_array_object (&length_val, 1, true); + ecma_free_value (length_val); + + return new_array; + } + + if (!ecma_is_constructor (constructor)) + { + ecma_free_value (constructor); + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid species constructor")); + } + + ecma_value_t len_val = ecma_make_uint32_value (length); + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + ecma_value_t ret_val = ecma_op_function_construct (ctor_object_p, + ctor_object_p, + &len_val, + 1); + + ecma_deref_object (ctor_object_p); + ecma_free_value (len_val); + return ret_val; +} /* ecma_op_array_species_create */ + +/** + * CreateArrayIterator Abstract Operation + * + * See also: + * ECMA-262 v6, 22.1.5.1 + * + * Referenced by: + * ECMA-262 v6, 22.1.3.4 + * ECMA-262 v6, 22.1.3.13 + * ECMA-262 v6, 22.1.3.29 + * ECMA-262 v6, 22.1.3.30 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return array iterator object + */ +ecma_value_t +ecma_op_create_array_iterator (ecma_object_t *obj_p, /**< array object */ + ecma_array_iterator_type_t type) /**< array iterator type */ +{ + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_ITERATOR_PROTOTYPE); + + return ecma_op_create_iterator_object (ecma_make_object_value (obj_p), + prototype_obj_p, + ECMA_PSEUDO_ARRAY_ITERATOR, + (uint8_t) type); +} /* ecma_op_create_array_iterator */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Low level delete of array items from new_length to old_length @@ -705,9 +794,7 @@ ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (new_length < old_length); JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - - if (ext_obj_p->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (object_p)) { return ecma_delete_fast_array_properties (object_p, new_length); } @@ -914,17 +1001,17 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object { if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { - uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); - ext_object_p->u.array.length_prop = new_prop_value; + uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); + ext_object_p->u.array.u.length_prop = new_prop_value; } - else if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } } return ECMA_VALUE_TRUE; } - else if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } @@ -935,7 +1022,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object { current_len_uint32 = ecma_delete_array_properties (object_p, new_len_uint32, old_len_uint32); } - else if (ext_object_p->u.array.is_fast_mode) + else if (ecma_op_object_is_fast_array (object_p)) { ecma_fast_array_set_length (object_p, new_len_uint32); } @@ -945,8 +1032,8 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) && !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { - uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); - ext_object_p->u.array.length_prop = new_prop_value; + uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); + ext_object_p->u.array.u.length_prop = new_prop_value; } if (current_len_uint32 == new_len_uint32) @@ -1035,16 +1122,22 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (object_p)) { if ((property_desc_p->flags & ECMA_FAST_ARRAY_DATA_PROP_FLAGS) == ECMA_FAST_ARRAY_DATA_PROP_FLAGS) { - if (ecma_fast_array_set_property (object_p, property_name_p, property_desc_p->value)) + uint32_t index = ecma_string_get_array_index (property_name_p); + + if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) + { + ecma_fast_array_convert_to_normal (object_p); + } + else if (ecma_fast_array_set_property (object_p, index, property_desc_p->value)) { return ECMA_VALUE_TRUE; } - JERRY_ASSERT (!ext_object_p->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_array_is_fast_array (ext_object_p)); } else { @@ -1052,7 +1145,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra } } - JERRY_ASSERT (!ext_object_p->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); uint32_t index = ecma_string_get_array_index (property_name_p); if (index == ECMA_STRING_NOT_ARRAY_INDEX) @@ -1062,7 +1155,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra bool update_length = (index >= ext_object_p->u.array.length); - if (update_length && !ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (update_length && !ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW); } @@ -1090,6 +1183,19 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra return ECMA_VALUE_TRUE; } /* ecma_op_array_object_define_own_property */ +/** + * Get the length of the an array object + * + * @return the array length + */ +extern inline uint32_t JERRY_ATTR_ALWAYS_INLINE +ecma_array_get_length (ecma_object_t *array_p) /**< array object */ +{ + JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY); + + return ((ecma_extended_object_t *) array_p)->u.array.length; +} /* ecma_array_get_length */ + /** * List names of a String object's lazy instantiated properties * @@ -1097,13 +1203,8 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra */ void ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, /**< a String object */ - bool separate_enumerable, /**< true - list enumerable properties - * into main collection, - * and non-enumerable to collection of - * 'skipped non-enumerable' properties, - * false - list all properties into main - * collection. - */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ ecma_collection_t *main_collection_p, /**< 'main' collection */ ecma_collection_t *non_enum_collection_p) /**< skipped * 'non-enumerable' @@ -1111,9 +1212,12 @@ ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, /**< a String obje { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p; - ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + if ((opts & ECMA_LIST_ARRAY_INDICES) == 0) + { + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + } } /* ecma_op_array_list_lazy_property_names */ /** diff --git a/jerry-core/ecma/operations/ecma-array-object.h b/jerry-core/ecma/operations/ecma-array-object.h index b5de122f..761b6799 100644 --- a/jerry-core/ecma/operations/ecma-array-object.h +++ b/jerry-core/ecma/operations/ecma-array-object.h @@ -26,11 +26,26 @@ */ /** - * Maximum number of array holes in a fast mode access array. - * If the number of holes exceeds this limit, the array is converted back + * Maximum number of new array holes in a fast mode access array. + * If the number of new holes exceeds this limit, the array is converted back * to normal property list based array. */ -#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT 32 +#define ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT 32 + +/** + * Bitshift index for fast array hole count representation + */ +#define ECMA_FAST_ARRAY_HOLE_SHIFT 8 + +/** + * This number represents 1 array hole in underlying buffer of a fast acces mode array + */ +#define ECMA_FAST_ARRAY_HOLE_ONE (1 << ECMA_FAST_ARRAY_HOLE_SHIFT) + +/** + * Maximum number of array holes in a fast access mode array + */ +#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT (1 << 24) /** * Flags for ecma_op_array_object_set_length @@ -52,16 +67,28 @@ ecma_op_new_array_object (ecma_length_t length); ecma_object_t * ecma_op_new_fast_array_object (ecma_length_t length); +bool +ecma_op_object_is_fast_array (ecma_object_t *object_p); + +bool +ecma_op_array_is_fast_array (ecma_extended_object_t *array_p); + +uint32_t +ecma_fast_array_get_hole_count (ecma_object_t *obj_p); + ecma_value_t * ecma_fast_array_extend (ecma_object_t *object_p, uint32_t new_lengt); bool -ecma_fast_array_set_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value); +ecma_fast_array_set_property (ecma_object_t *object_p, uint32_t index, ecma_value_t value); void ecma_array_object_delete_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_property_value_t *prop_value_p); +uint32_t +ecma_delete_fast_array_properties (ecma_object_t *object_p, uint32_t new_length); + ecma_collection_t * ecma_fast_array_get_property_names (ecma_object_t *object_p, uint32_t opts); @@ -72,11 +99,15 @@ ecma_value_t ecma_op_create_array_object (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, bool is_treat_single_arg_as_length); -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) ecma_value_t -ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, - bool is_treat_single_arg_as_length, ecma_object_t *object_p); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +ecma_op_array_species_create (ecma_object_t *original_array_p, + ecma_length_t length); + +ecma_value_t +ecma_op_create_array_iterator (ecma_object_t *obj_p, + ecma_array_iterator_type_t type); +#endif /* ENABLED (JERRY_ES2015) */ ecma_value_t ecma_op_array_object_set_length (ecma_object_t *object_p, ecma_value_t new_value, uint32_t flags); @@ -85,8 +116,11 @@ ecma_value_t ecma_op_array_object_define_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p, const ecma_property_descriptor_t *property_desc_p); +uint32_t ecma_array_get_length (ecma_object_t *array_p); + void -ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, bool separate_enumerable, +ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 08f61554..7b0e0077 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -15,6 +15,7 @@ #include "ecma-arraybuffer-object.h" #include "ecma-try-catch-macro.h" +#include "ecma-typedarray-object.h" #include "ecma-objects.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" @@ -92,7 +93,6 @@ ecma_arraybuffer_new_object_external (ecma_length_t length, /**< length of the b return object_p; } /* ecma_arraybuffer_new_object_external */ - /** * ArrayBuffer object creation operation. * @@ -203,6 +203,79 @@ ecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayB } } /* ecma_arraybuffer_get_buffer */ +/** + * Helper function: check if the target ArrayBuffer is detached + * + * @return true - if value is an detached ArrayBuffer object + * false - otherwise + */ +inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_is_detached (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + /* in case the arraybuffer has been detached */ + return array_p->buffer_p == NULL; + } + + return false; +} /* ecma_arraybuffer_is_detached */ + +/** + * Helper function: check if the target ArrayBuffer is detachable + * + * @return true - if value is an detachable ArrayBuffer object + * false - otherwise + */ +inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_is_detachable (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + /* in case the arraybuffer has been detached */ + return array_p->buffer_p != NULL; + } + + return false; +} /* ecma_arraybuffer_is_detachable */ + +/** + * ArrayBuffer object detaching operation + * + * See also: ES2015 24.1.1.3 + * + * @return true - if detach op succeeded + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_detach (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + if (!ecma_arraybuffer_is_detachable (object_p)) + { + return false; + } + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) ext_object_p; + array_object_p->buffer_p = NULL; + array_object_p->extended_object.u.class_prop.u.length = 0; + + return true; +} /* ecma_arraybuffer_detach */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.h b/jerry-core/ecma/operations/ecma-arraybuffer-object.h index a77deb50..c654b7b6 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.h +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.h @@ -43,6 +43,12 @@ lit_utf8_byte_t * JERRY_ATTR_PURE ecma_arraybuffer_get_buffer (ecma_object_t *obj_p); ecma_length_t JERRY_ATTR_PURE ecma_arraybuffer_get_length (ecma_object_t *obj_p); +bool JERRY_ATTR_PURE +ecma_arraybuffer_is_detached (ecma_object_t *obj_p); +bool JERRY_ATTR_PURE +ecma_arraybuffer_is_detachable (ecma_object_t *obj_p); +bool +ecma_arraybuffer_detach (ecma_object_t *obj_p); bool ecma_is_arraybuffer (ecma_value_t val); diff --git a/jerry-core/ecma/operations/ecma-comparison.c b/jerry-core/ecma/operations/ecma-comparison.c index 886a6004..04d367d3 100644 --- a/jerry-core/ecma/operations/ecma-comparison.c +++ b/jerry-core/ecma/operations/ecma-comparison.c @@ -130,12 +130,12 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ y = tmp; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_is_value_symbol (x)) { return ECMA_VALUE_FALSE; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if (ecma_is_value_boolean (y)) { @@ -153,9 +153,9 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ if (ecma_is_value_object (x)) { if (ecma_is_value_string (y) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) || ecma_is_value_symbol (y) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ || ecma_is_value_number (y)) { /* 9. */ @@ -210,10 +210,10 @@ ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ { if (ecma_is_value_direct (x) || ecma_is_value_direct (y) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) || ecma_is_value_symbol (x) || ecma_is_value_symbol (y) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ || ecma_is_value_object (x) || ecma_is_value_object (y)) { diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index 3c60dcb6..0732c023 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#include "jcontext.h" #include "ecma-alloc.h" #include "ecma-array-object.h" #include "ecma-builtins.h" @@ -26,17 +26,339 @@ #include "ecma-property-hashmap.h" #include "ecma-objects.h" -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** \addtogroup ecma ECMA * @{ * - * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map/set helper functions + * \addtogroup \addtogroup ecmamaphelpers ECMA builtin Map/Set helper functions * @{ */ /** - * Handle calling [[Construct]] of built-in map/set like objects + * Create a new internal buffer. + * + * Note: + * The first element of the collection tracks the size of the buffer. + * ECMA_VALUE_EMPTY values are not calculated into the size. + * + * @return pointer to the internal buffer + */ +static inline ecma_collection_t * +ecma_op_create_internal_buffer (void) +{ + ecma_collection_t *collection_p = ecma_new_collection (); + ecma_collection_push_back (collection_p, (ecma_value_t) 0); + + return collection_p; +} /* ecma_op_create_internal_buffer */ + +/** + * Append values to the internal buffer. + */ +static void +ecma_op_internal_buffer_append (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg, /**< value argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_value_t values[] = { ecma_copy_value_if_not_object (key_arg), ecma_copy_value_if_not_object (value_arg) }; + ecma_collection_append (container_p, values, 2); + } + else + { + ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (key_arg)); + } + + ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) + 1); +} /* ecma_op_internal_buffer_append */ + +/** + * Update the value of a given entry. + */ +static inline void +ecma_op_internal_buffer_update (ecma_value_t *entry_p, /**< entry pointer */ + ecma_value_t value_arg, /**< value argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (entry_p != NULL); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_free_value_if_not_object (((ecma_container_pair_t *) entry_p)->value); + + ((ecma_container_pair_t *) entry_p)->value = ecma_copy_value_if_not_object (value_arg); + } +} /* ecma_op_internal_buffer_update */ + +/** + * Delete element from the internal buffer. + */ +static void +ecma_op_internal_buffer_delete (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_container_pair_t *entry_p, /**< entry pointer */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + JERRY_ASSERT (entry_p != NULL); + + ecma_free_value_if_not_object (entry_p->key); + entry_p->key = ECMA_VALUE_EMPTY; + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_free_value_if_not_object (entry_p->value); + entry_p->value = ECMA_VALUE_EMPTY; + } + + ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) - 1); +} /* ecma_op_internal_buffer_delete */ + +/** + * Find an entry in the collection. + * + * @return pointer to the appropriate entry. + */ +static ecma_value_t * +ecma_op_internal_buffer_find (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + + uint8_t entry_size = ecma_op_container_entry_size (lit_id); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += entry_size) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_op_same_value_zero (*entry_p, key_arg)) + { + return entry_p; + } + } + + return NULL; +} /* ecma_op_internal_buffer_find */ + +/** + * Get the value that belongs to the key. + * + * Note: in case of Set containers, the values are the same as the keys. + * + * @return ecma value + */ +static ecma_value_t +ecma_op_container_get_value (ecma_value_t *entry_p, /**< entry (key) pointer */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (entry_p != NULL); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + return ((ecma_container_pair_t *) entry_p)->value; + } + + return *entry_p; +} /* ecma_op_container_get_value */ + +/** + * Get the size (in ecma_value_t) of the stored entries. + * + * @return size of the entries. + */ +uint8_t +ecma_op_container_entry_size (lit_magic_string_id_t lit_id) /**< class id */ +{ + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + return ECMA_CONTAINER_PAIR_SIZE; + } + + return ECMA_CONTAINER_VALUE_SIZE; +} /* ecma_op_container_entry_size */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +/** + * Release the entries in the WeakSet container. + */ +static void +ecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object pointer */ + ecma_collection_t *container_p) /** internal buffer pointer */ +{ + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p)); + ecma_op_container_remove_weak_entry (object_p, *entry_p); + + *entry_p = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_weakset_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/** + * Release the entries in the WeakMap container. + */ +static void +ecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object pointer */ + ecma_collection_t *container_p) /**< internal buffer pointer */ +{ + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p)); + ecma_op_container_remove_weak_entry (object_p, entry_p->key); + + ecma_free_value_if_not_object (entry_p->value); + + entry_p->key = ECMA_VALUE_EMPTY; + entry_p->value = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_weakmap_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +/** + * Release the entries in the Set container. + */ +static void +ecma_op_container_free_set_entries (ecma_collection_t *container_p) +{ + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + ecma_free_value_if_not_object (*entry_p); + *entry_p = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_set_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +/** + * Release the entries in the Map container. + */ +static void +ecma_op_container_free_map_entries (ecma_collection_t *container_p) +{ + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + ecma_free_value_if_not_object (entry_p->key); + ecma_free_value_if_not_object (entry_p->value); + + entry_p->key = ECMA_VALUE_EMPTY; + entry_p->value = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_map_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +/** + * Release the internal buffer and the stored entries. + */ +void +ecma_op_container_free_entries (ecma_object_t *object_p) /**< collection object pointer */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + switch (map_object_p->u.class_prop.class_id) + { +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: + { + ecma_op_container_free_weakset_entries (object_p, container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: + { + ecma_op_container_free_weakmap_entries (object_p, container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case LIT_MAGIC_STRING_SET_UL: + { + ecma_op_container_free_set_entries (container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case LIT_MAGIC_STRING_MAP_UL: + { + ecma_op_container_free_map_entries (container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + default: + { + break; + } + } + + ECMA_CONTAINER_SET_SIZE (container_p, 0); +} /* ecma_op_container_free_entries */ + +/** + * Handle calling [[Construct]] of built-in Map/Set like objects * * @return ecma value */ @@ -47,305 +369,287 @@ ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments l ecma_builtin_id_t proto_id) /**< prototype builtin id */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_MAP_UL + || lit_id == LIT_MAGIC_STRING_SET_UL + || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL + || lit_id == LIT_MAGIC_STRING_WEAKSET_UL); + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL); - ecma_object_t *internal_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), proto_id); - ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (proto_id), - sizeof (ecma_map_object_t), - ECMA_OBJECT_TYPE_CLASS); + if (JERRY_UNLIKELY (proto_p == NULL)) + { + return ECMA_VALUE_ERROR; + } - ecma_map_object_t *map_obj_p = (ecma_map_object_t *) object_p; - map_obj_p->header.u.class_prop.class_id = (uint16_t) lit_id; - map_obj_p->header.u.class_prop.u.value = ecma_make_object_value (internal_object_p); - map_obj_p->size = 0; + ecma_collection_t *container_p = ecma_op_create_internal_buffer (); + ecma_object_t *object_p = ecma_create_object (proto_p, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (proto_p); + ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p; + map_obj_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; + map_obj_p->u.class_prop.class_id = (uint16_t) lit_id; - ecma_deref_object (internal_object_p); + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + { + map_obj_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK; + } + + ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p); ecma_value_t set_value = ecma_make_object_value (object_p); + ecma_value_t result = set_value; -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (arguments_list_len == 0) { - return set_value; + return result; } ecma_value_t iterable = arguments_list_p[0]; if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable)) { - return set_value; + return result; } - ecma_value_t iter = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); - - if (ECMA_IS_VALUE_ERROR (iter)) + lit_magic_string_id_t adder_string_id; + if (lit_id == LIT_MAGIC_STRING_MAP_UL || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL) { - ecma_deref_object (object_p); - return iter; + adder_string_id = LIT_MAGIC_STRING_SET; } + else + { + adder_string_id = LIT_MAGIC_STRING_ADD; + } + + result = ecma_op_object_get_by_magic_id (object_p, adder_string_id); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_object; + } + + if (!ecma_op_is_callable (result)) + { + ecma_free_value (result); + result = ecma_raise_type_error (ECMA_ERR_MSG ("add/set function is not callable.")); + goto cleanup_object; + } + + ecma_object_t *adder_func_p = ecma_get_object_from_value (result); + + result = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_adder; + } + + const ecma_value_t iter = result; while (true) { - ecma_value_t next = ecma_op_iterator_step (iter); + result = ecma_op_iterator_step (iter); - if (ECMA_IS_VALUE_ERROR (next)) + if (ECMA_IS_VALUE_ERROR (result)) { - ecma_free_value (iter); - ecma_deref_object (object_p); - return next; + goto cleanup_iter; } - if (ecma_is_value_false (next)) + if (ecma_is_value_false (result)) { break; } - ecma_value_t next_value = ecma_op_iterator_value (next); - - if (ECMA_IS_VALUE_ERROR (next_value)) - { - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return next_value; - } - - ecma_value_t result; - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - result = ecma_op_container_set (set_value, next_value, next_value, lit_id); - } - else - { - if (!ecma_is_value_object (next_value)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); - } - - ecma_object_t *next_object_p = ecma_get_object_from_value (next_value); - - ecma_value_t key = ecma_op_object_get (next_object_p, ecma_new_ecma_string_from_uint32 (0)); - - if (ECMA_IS_VALUE_ERROR (key)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return key; - } - - ecma_value_t value = ecma_op_object_get (next_object_p, ecma_new_ecma_string_from_uint32 (1)); - - if (ECMA_IS_VALUE_ERROR (value)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (key); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return value; - } - - result = ecma_op_container_set (set_value, key, value, lit_id); - - ecma_free_value (key); - ecma_free_value (value); - } - - ecma_free_value (next_value); + const ecma_value_t next = result; + result = ecma_op_iterator_value (next); ecma_free_value (next); if (ECMA_IS_VALUE_ERROR (result)) { - // TODO close the iterator when generator function will be supported - ecma_free_value (iter); - ecma_deref_object (object_p); - return result; + goto cleanup_iter; + } + + if (lit_id == LIT_MAGIC_STRING_SET_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + { + const ecma_value_t value = result; + + ecma_value_t arguments[] = { value }; + result = ecma_op_function_call (adder_func_p, set_value, arguments, 1); + + ecma_free_value (value); + } + else + { + if (!ecma_is_value_object (result)) + { + ecma_free_value (result); + ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); + result = ecma_op_iterator_close (iter); + JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result)); + goto cleanup_iter; + } + + ecma_object_t *next_object_p = ecma_get_object_from_value (result); + + result = ecma_op_object_get_by_uint32_index (next_object_p, 0); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (next_object_p); + ecma_op_iterator_close (iter); + goto cleanup_iter; + } + + const ecma_value_t key = result; + + result = ecma_op_object_get_by_uint32_index (next_object_p, 1); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (next_object_p); + ecma_free_value (key); + ecma_op_iterator_close (iter); + goto cleanup_iter; + } + + const ecma_value_t value = result; + ecma_value_t arguments[] = { key, value }; + result = ecma_op_function_call (adder_func_p, set_value, arguments, 2); + + ecma_free_value (key); + ecma_free_value (value); + ecma_deref_object (next_object_p); + } + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_op_iterator_close (iter); + goto cleanup_iter; } ecma_free_value (result); } ecma_free_value (iter); + ecma_deref_object (adder_func_p); + return ecma_make_object_value (object_p); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +cleanup_iter: + ecma_free_value (iter); +cleanup_adder: + ecma_deref_object (adder_func_p); +cleanup_object: + ecma_deref_object (object_p); +#endif /* ENABLED (JERRY_ES2015) */ - return set_value; + return result; } /* ecma_op_container_create */ /** - * Get map/set object pointer + * Get Map/Set object pointer * * Note: * If the function returns with NULL, the error object has * already set, and the caller must return with ECMA_VALUE_ERROR * - * @return pointer to the map/set if this_arg is a valid map/set object + * @return pointer to the Map/Set if this_arg is a valid Map/Set object * NULL otherwise */ -static ecma_map_object_t * +static ecma_extended_object_t * ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { if (ecma_is_value_object (this_arg)) { - ecma_map_object_t *map_object_p = (ecma_map_object_t *) ecma_get_object_from_value (this_arg); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); - if (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS - && map_object_p->header.u.class_prop.class_id == lit_id) + if (ecma_get_object_type ((ecma_object_t *) map_object_p) == ECMA_OBJECT_TYPE_CLASS + && map_object_p->u.class_prop.class_id == lit_id) { return map_object_p; } } -#ifdef JERRY_ENABLE_ERROR_MESSAGES - char *msg_p = "Expected a Map object."; - -#if ENABLED (JERRY_ES2015_BUILTIN_SET) - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - msg_p = "Expected a Set object."; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ - - ecma_raise_type_error (ECMA_ERR_MSG (msg_p)); -#else /* !JERRY_ENABLE_ERROR_MESSAGES */ +#if ENABLED (JERRY_ERROR_MESSAGES) + ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, + "Expected a % object.", + ecma_make_string_value (ecma_get_magic_string (lit_id))); +#else /* !ENABLED (JERRY_ERROR_MESSAGES) */ ecma_raise_type_error (NULL); -#endif /* JERRY_ENABLE_ERROR_MESSAGES */ +#endif /* ENABLED (JERRY_ERROR_MESSAGES) */ return NULL; } /* ecma_op_container_get_object */ /** - * Creates a property key for the internal object from the given argument + * Returns with the size of the Map/Set object. * - * Note: - * This operation does not increase the reference counter of strings and symbols - * - * @return property key - */ -static ecma_string_t * -ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ -{ - if (ecma_is_value_prop_name (key_arg)) - { - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key_arg); - ecma_ref_ecma_string (prop_name_p); - return prop_name_p; - } - - if (ecma_is_value_object (key_arg)) - { - ecma_object_t *obj_p = ecma_get_object_from_value (key_arg); - ecma_string_t *key_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_MAP_KEY); - - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) - { - ecma_fast_array_convert_to_normal (obj_p); - } - - ecma_property_t *property_p = ecma_find_named_property (obj_p, key_string_p); - ecma_string_t *object_key_string; - - if (property_p == NULL) - { - object_key_string = ecma_new_map_key_string (key_arg); - ecma_property_value_t *value_p = ecma_create_named_data_property (obj_p, - key_string_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - value_p->value = ecma_make_string_value (object_key_string); - } - else - { - object_key_string = ecma_get_string_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - } - - ecma_ref_ecma_string (object_key_string); - return object_key_string; - } - - if (ecma_is_value_integer_number (key_arg)) - { - ecma_integer_value_t integer = ecma_get_integer_from_value (key_arg); - - if (JERRY_LIKELY (integer > 0 && integer <= ECMA_DIRECT_STRING_MAX_IMM)) - { - return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_ECMA_INTEGER, (uintptr_t) integer); - } - } - - return ecma_new_map_key_string (key_arg); -} /* ecma_op_container_to_key */ - -/** - * Returns with the size of the map/set object. - * - * @return size of the map/set object as ecma-value. + * @return size of the Map/Set object as ecma-value. */ ecma_value_t ecma_op_container_size (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - return ecma_make_uint32_value (map_object_p->size); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + return ecma_make_uint32_value (ECMA_CONTAINER_GET_SIZE (container_p)); } /* ecma_op_container_size */ /** - * The generic map prototype object's 'get' routine + * The generic Map/WeakMap prototype object's 'get' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg) /**< key argument */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, LIT_MAGIC_STRING_MAP_UL); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - if (map_object_p->size == 0) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL && !ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_UNDEFINED; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) { return ECMA_VALUE_UNDEFINED; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - if (property_p == NULL || ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (entry_p == NULL) { return ECMA_VALUE_UNDEFINED; } - return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + return ecma_copy_value (((ecma_container_pair_t *) entry_p)->value); } /* ecma_op_container_get */ /** - * The generic map/set prototype object's 'has' routine + * The generic Map/Set prototype object's 'has' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -355,32 +659,105 @@ ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg, /**< key argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - if (map_object_p->size == 0) + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 + && !ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_FALSE; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + + if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) { return ECMA_VALUE_FALSE; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - return ecma_make_boolean_value (property_p != NULL - && !ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); + return ecma_make_boolean_value (entry_p != NULL); } /* ecma_op_container_has */ /** - * The generic map prototype object's 'set' and set prototype object's 'add' routine + * Set a weak reference from a container to a key object + */ +static void +ecma_op_container_set_weak (ecma_object_t *const key_p, /**< key object */ + ecma_extended_object_t *const container_p) /**< container */ +{ + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (key_p))) + { + ecma_fast_array_convert_to_normal (key_p); + } + + ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); + ecma_property_t *property_p = ecma_find_named_property (key_p, weak_refs_string_p); + ecma_collection_t *refs_p; + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (key_p, + weak_refs_string_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + &property_p); + ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); + refs_p = ecma_new_collection (); + ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p); + } + else + { + refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); + } + + const ecma_value_t container_value = ecma_make_object_value ((ecma_object_t *) container_p); + for (uint32_t i = 0; i < refs_p->item_count; i++) + { + if (ecma_is_value_empty (refs_p->buffer_p[i])) + { + refs_p->buffer_p[i] = container_value; + return; + } + } + + ecma_collection_push_back (refs_p, container_value); +} /* ecma_op_container_set_weak */ + +/** + * Helper method for the Map.prototype.set and Set.prototype.add methods to swap the sign of the given value if needed + * + * See also: + * ECMA-262 v6, 23.2.3.1 step 6 + * ECMA-262 v6, 23.1.3.9 step 6 + * + * @return ecma value + */ +static ecma_value_t +ecma_op_container_set_noramlize_zero (ecma_value_t this_arg) /*< this arg */ +{ + if (ecma_is_value_number (this_arg)) + { + ecma_number_t number_value = ecma_get_number_from_value (this_arg); + + if (JERRY_UNLIKELY (ecma_number_is_zero (number_value) && ecma_number_is_negative (number_value))) + { + return ecma_make_integer_value (0); + } + } + + return this_arg; +} /* ecma_op_container_set_noramlize_zero */ + +/** + * The generic Map prototype object's 'set' and Set prototype object's 'add' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -391,44 +768,52 @@ ecma_op_container_set (ecma_value_t this_arg, /**< this argument */ ecma_value_t value_arg, /**< value argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - - if (property_p == NULL) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 + && !ecma_is_value_object (key_arg)) { - ecma_property_value_t *value_p = ecma_create_named_data_property (internal_obj_p, - prop_name_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - value_p->value = ecma_copy_value_if_not_object (value_arg); - map_object_p->size++; + return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object")); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); + + if (entry_p == NULL) + { + ecma_op_internal_buffer_append (container_p, + ecma_op_container_set_noramlize_zero (key_arg), + value_arg, + lit_id); + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0) + { + ecma_object_t *key_p = ecma_get_object_from_value (key_arg); + ecma_op_container_set_weak (key_p, map_object_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ } else { - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) - { - map_object_p->size++; - } - ecma_named_data_property_assign_value (internal_obj_p, ECMA_PROPERTY_VALUE_PTR (property_p), value_arg); + ecma_op_internal_buffer_update (entry_p, ecma_op_container_set_noramlize_zero (value_arg), lit_id); } - ecma_deref_ecma_string (prop_name_p); - ecma_ref_object ((ecma_object_t *) &map_object_p->header); + ecma_ref_object ((ecma_object_t *) map_object_p); return this_arg; } /* ecma_op_container_set */ /** - * The generic map/set prototype object's 'forEach' routine + * The generic Map/Set prototype object's 'forEach' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -440,7 +825,7 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ * invoke predicate */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { @@ -454,57 +839,27 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ JERRY_ASSERT (ecma_is_value_object (predicate)); ecma_object_t *func_object_p = ecma_get_object_from_value (predicate); - - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - - ecma_collection_t *props_p = ecma_op_object_get_property_names (internal_obj_p, ECMA_LIST_NO_OPTS); - - ecma_value_t *buffer_p = props_p->buffer_p; - ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - ecma_ref_object (internal_obj_p); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - for (uint32_t i = 0; i < props_p->item_count; i++) + uint8_t entry_size = ecma_op_container_entry_size (lit_id); + + for (uint32_t i = 0; i < ECMA_CONTAINER_ENTRY_COUNT (container_p); i += entry_size) { - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[i]); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - JERRY_ASSERT (property_p != NULL); + ecma_value_t *entry_p = ECMA_CONTAINER_START (container_p) + i; - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (ecma_is_value_empty (*entry_p)) { continue; } - ecma_value_t value = ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - ecma_value_t key_arg; + ecma_value_t key_arg = *entry_p; + ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - key_arg = value; - } - else if (ecma_prop_name_is_map_key (prop_name_p)) - { - key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - } - else - { - if (ECMA_IS_DIRECT_STRING (prop_name_p) - && ECMA_GET_DIRECT_STRING_TYPE (prop_name_p) == ECMA_DIRECT_STRING_ECMA_INTEGER) - { - key_arg = ecma_make_uint32_value ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p)); - } - else - { - key_arg = buffer_p[i]; - } - } - - ecma_value_t call_args[] = { value, key_arg }; - - ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 2); - - ecma_free_value (value); + ecma_value_t call_args[] = { value_arg, key_arg, this_arg }; + ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); if (ECMA_IS_VALUE_ERROR (call_value)) { @@ -515,9 +870,6 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ ecma_free_value (call_value); } - ecma_deref_object (internal_obj_p); - ecma_collection_free (props_p); - return ret_value; } /* ecma_op_container_foreach */ @@ -531,24 +883,20 @@ ecma_value_t ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL); - map_object_p->header.u.class_prop.u.value = ecma_make_object_value (internal_object_p); - map_object_p->size = 0; - - ecma_deref_object (internal_object_p); + ecma_op_container_free_entries ((ecma_object_t *) map_object_p); return ECMA_VALUE_UNDEFINED; } /* ecma_op_container_clear */ /** - * The generic map/set prototype object's 'delete' routine + * The generic Map/Set prototype object's 'delete' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -558,33 +906,115 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg, /**< key argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - if (property_p == NULL || ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (entry_p == NULL) { return ECMA_VALUE_FALSE; } - ecma_named_data_property_assign_value (internal_obj_p, ECMA_PROPERTY_VALUE_PTR (property_p), ECMA_VALUE_EMPTY); - map_object_p->size--; - + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); return ECMA_VALUE_TRUE; } /* ecma_op_container_delete */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +/** + * The generic WeakMap/WeakSet prototype object's 'delete' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< internal class id */ +{ + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + if (!ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_FALSE; + } + + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); + + if (entry_p == NULL) + { + return ECMA_VALUE_FALSE; + } + + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); + + ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); + ecma_op_container_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_p)); + + return ECMA_VALUE_TRUE; +} /* ecma_op_container_delete_weak */ + +/** + * Helper function to remove a weak reference to an object. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +void +ecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */ + ecma_value_t ref_holder) /**< key argument */ +{ + ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); + + ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p); + JERRY_ASSERT (property_p != NULL); + + ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + ECMA_PROPERTY_VALUE_PTR (property_p)->value); + for (uint32_t i = 0; i < refs_p->item_count; i++) + { + if (refs_p->buffer_p[i] == ref_holder) + { + refs_p->buffer_p[i] = ECMA_VALUE_EMPTY; + break; + } + } +} /* ecma_op_container_unref_weak */ + +/** + * Helper function to remove a key/value pair from a weak container object + */ +void +ecma_op_container_remove_weak_entry (ecma_object_t *object_p, /**< internal container object */ + ecma_value_t key_arg) /**< key */ +{ + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, map_object_p->u.class_prop.class_id); + + JERRY_ASSERT (entry_p != NULL); + + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, map_object_p->u.class_prop.class_id); +} /* ecma_op_container_remove_weak_entry */ + +#if ENABLED (JERRY_ES2015) /** * The Create{Set, Map}Iterator Abstract operation @@ -596,7 +1026,7 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ * Note: * Returned value must be freed with ecma_free_value. * - * @return set/map iterator object, if success + * @return Map/Set iterator object, if success * error - otherwise */ ecma_value_t @@ -607,7 +1037,7 @@ ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */ ecma_builtin_id_t proto_id, /**< prototype builtin id */ ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { @@ -620,6 +1050,60 @@ ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */ type); } /* ecma_op_container_create_iterator */ +/** + * Get the index of the iterator object. + * + * @return index of the iterator. + */ +static uint32_t +ecma_op_iterator_get_index (ecma_object_t *iter_obj_p) /**< iterator object pointer */ +{ + uint32_t index = ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index; + + if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT)) + { + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); + ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); + ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + return (uint32_t) (ecma_get_number_from_value (value_p->value)); + } + + return index; +} /* ecma_op_iterator_get_index */ + +/** + * Set the index of the iterator object. + */ +static void +ecma_op_iterator_set_index (ecma_object_t *iter_obj_p, /**< iterator object pointer */ + uint32_t index) /* iterator index to set */ +{ + if (JERRY_UNLIKELY (index >= ECMA_ITERATOR_INDEX_LIMIT)) + { + /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]] + property is stored as an internal property */ + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); + ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); + ecma_property_value_t *value_p; + + if (property_p == NULL) + { + value_p = ecma_create_named_data_property (iter_obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); + value_p->value = ecma_make_uint32_value (index); + } + else + { + value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + value_p->value = ecma_make_uint32_value (index); + } + } + else + { + ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index = (uint16_t) index; + } +} /* ecma_op_iterator_set_index */ + /** * The %{Set, Map}IteratorPrototype% object's 'next' routine * @@ -658,97 +1142,45 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); } - ecma_map_object_t *map_object_p = (ecma_map_object_t *) (ecma_get_object_from_value (iterated_value)); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value)); + lit_magic_string_id_t lit_id = map_object_p->u.class_prop.class_id; - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_collection_t *props_p = ecma_op_object_get_property_names (internal_obj_p, ECMA_LIST_NO_OPTS); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + uint32_t index = ecma_op_iterator_get_index (obj_p); - uint32_t length = props_p->item_count; - uint32_t index = ext_obj_p->u.pseudo_array.u1.iterator_index; - - if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT)) - { - /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]] - property is stored as an internal property */ - ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); - - ecma_property_t *property_p = ecma_find_named_property (obj_p, prop_name_p); - ecma_property_value_t *value_p; - - if (property_p == NULL) - { - value_p = ecma_create_named_data_property (obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); - value_p->value = ecma_make_uint32_value (index); - } - else - { - value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - index = (uint32_t) (ecma_get_number_from_value (value_p->value) + 1); - value_p->value = ecma_make_uint32_value (index); - } - } - else - { - ext_obj_p->u.pseudo_array.u1.iterator_index++; - } - - if (index >= length) + if (index == entry_count) { ext_obj_p->u.pseudo_array.u2.iterated_value = ECMA_VALUE_EMPTY; - ecma_collection_free (props_p); + return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); } + uint8_t entry_size = ecma_op_container_entry_size (lit_id); uint8_t iterator_kind = ext_obj_p->u.pseudo_array.extra_info; - - ecma_value_t *buffer_p = props_p->buffer_p; - + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - for (uint32_t i = 0; i < props_p->item_count; i++) + for (uint32_t i = index; i < entry_count; i += entry_size) { - if (index > 0) - { - index--; - continue; - } + ecma_value_t *entry_p = start_p + i; - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[i]); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - JERRY_ASSERT (property_p != NULL); - - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (ecma_is_value_empty (*entry_p)) { - if (i == props_p->item_count - 1) + if (i == (entry_count - entry_size)) { ret_value = ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); + break; } + continue; } - ecma_value_t value = ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - ecma_value_t key_arg; + ecma_op_iterator_set_index (obj_p, i + entry_size); - if (iterator_type == ECMA_PSEUDO_SET_ITERATOR) - { - key_arg = value; - } - else if (ecma_prop_name_is_map_key (prop_name_p)) - { - key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - } - else - { - if (ECMA_IS_DIRECT_STRING (prop_name_p) - && ECMA_GET_DIRECT_STRING_TYPE (prop_name_p) == ECMA_DIRECT_STRING_ECMA_INTEGER) - { - key_arg = ecma_make_uint32_value ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p)); - } - else - { - key_arg = buffer_p[i]; - } - } + ecma_value_t key_arg = *entry_p; + ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); if (iterator_kind == ECMA_ITERATOR_KEYS) { @@ -756,32 +1188,30 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ } else if (iterator_kind == ECMA_ITERATOR_VALUES) { - ret_value = ecma_create_iter_result_object (value, ECMA_VALUE_FALSE); + ret_value = ecma_create_iter_result_object (value_arg, ECMA_VALUE_FALSE); } else { JERRY_ASSERT (iterator_kind == ECMA_ITERATOR_KEYS_VALUES); ecma_value_t entry_array_value; - entry_array_value = ecma_create_array_from_iter_element (value, key_arg); + entry_array_value = ecma_create_array_from_iter_element (value_arg, key_arg); ret_value = ecma_create_iter_result_object (entry_array_value, ECMA_VALUE_FALSE); ecma_free_value (entry_array_value); } - ecma_free_value (value); break; } - ecma_collection_free (props_p); - return ret_value; } /* ecma_op_container_iterator_next */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ diff --git a/jerry-core/ecma/operations/ecma-container-object.h b/jerry-core/ecma/operations/ecma-container-object.h index 6959d2b9..ec30bb12 100644 --- a/jerry-core/ecma/operations/ecma-container-object.h +++ b/jerry-core/ecma/operations/ecma-container-object.h @@ -19,7 +19,7 @@ #include "ecma-globals.h" #include "ecma-builtins.h" -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** \addtogroup ecma ECMA * @{ @@ -28,18 +28,22 @@ * @{ */ +uint8_t ecma_op_container_entry_size (lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id); ecma_value_t ecma_op_container_size (ecma_value_t this_arg, lit_magic_string_id_t lit_id); -ecma_value_t ecma_op_container_get (ecma_value_t this_arg, ecma_value_t key_arg); +ecma_value_t ecma_op_container_get (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_foreach (ecma_value_t this_arg, ecma_value_t predicate, ecma_value_t predicate_this_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_has (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg, lit_magic_string_id_t lit_id); - ecma_value_t ecma_op_container_clear (ecma_value_t this_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_delete (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); +ecma_value_t ecma_op_container_delete_weak (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); +void ecma_op_container_unref_weak (ecma_object_t *object_p, ecma_value_t ref_holder); +void ecma_op_container_remove_weak_entry (ecma_object_t *container_p, ecma_value_t key_arg); +void ecma_op_container_free_entries (ecma_object_t *object_p); ecma_value_t ecma_op_container_create_iterator (ecma_value_t this_arg, uint8_t type, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id, ecma_pseudo_array_type_t iterator_type); ecma_value_t ecma_op_container_iterator_next (ecma_value_t this_val, ecma_pseudo_array_type_t iterator_type); @@ -49,6 +53,6 @@ ecma_value_t ecma_op_container_iterator_next (ecma_value_t this_val, ecma_pseudo * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ #endif /* !ECMA_CONTAINER_OBJECT_H */ diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c index c528a925..e2854267 100644 --- a/jerry-core/ecma/operations/ecma-conversion.c +++ b/jerry-core/ecma/operations/ecma-conversion.c @@ -80,36 +80,20 @@ bool ecma_op_same_value (ecma_value_t x, /**< ecma value */ ecma_value_t y) /**< ecma value */ { - const bool is_x_undefined = ecma_is_value_undefined (x); - const bool is_x_null = ecma_is_value_null (x); - const bool is_x_boolean = ecma_is_value_boolean (x); - const bool is_x_number = ecma_is_value_number (x); - const bool is_x_string = ecma_is_value_string (x); - const bool is_x_object = ecma_is_value_object (x); - - const bool is_y_undefined = ecma_is_value_undefined (y); - const bool is_y_null = ecma_is_value_null (y); - const bool is_y_boolean = ecma_is_value_boolean (y); - const bool is_y_number = ecma_is_value_number (y); - const bool is_y_string = ecma_is_value_string (y); - const bool is_y_object = ecma_is_value_object (y); - - const bool is_types_equal = ((is_x_undefined && is_y_undefined) - || (is_x_null && is_y_null) - || (is_x_boolean && is_y_boolean) - || (is_x_number && is_y_number) - || (is_x_string && is_y_string) - || (is_x_object && is_y_object)); - - if (!is_types_equal) - { - return false; - } - else if (is_x_undefined || is_x_null) + if (x == y) { return true; } - else if (is_x_number) + + ecma_type_t type_of_x = ecma_get_value_type_field (x); + + if (type_of_x != ecma_get_value_type_field (y) + || type_of_x == ECMA_TYPE_DIRECT) + { + return false; + } + + if (ecma_is_value_number (x)) { ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); @@ -119,49 +103,30 @@ ecma_op_same_value (ecma_value_t x, /**< ecma value */ if (is_x_nan || is_y_nan) { - /* - * If both are NaN - * return true; - * else - * one of the numbers is NaN, and another - is not - * return false; - */ - return (is_x_nan && is_y_nan); + return is_x_nan && is_y_nan; } - else if (ecma_number_is_zero (x_num) - && ecma_number_is_zero (y_num) - && ecma_number_is_negative (x_num) != ecma_number_is_negative (y_num)) + + if (ecma_number_is_zero (x_num) + && ecma_number_is_zero (y_num) + && ecma_number_is_negative (x_num) != ecma_number_is_negative (y_num)) { return false; } - else - { - return (x_num == y_num); - } + + return (x_num == y_num); } - else if (is_x_string) + + if (ecma_is_value_string (x)) { ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } - else if (is_x_boolean) - { - return (ecma_is_value_true (x) == ecma_is_value_true (y)); - } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - else if (ecma_is_value_symbol (x)) - { - return x == y; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - else - { - JERRY_ASSERT (is_x_object); - return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); - } + JERRY_ASSERT (ecma_is_value_object (x) || ECMA_ASSERT_VALUE_IS_SYMBOL (x)); + + return false; } /* ecma_op_same_value */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) @@ -315,12 +280,12 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */ ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_make_number_value (ecma_string_to_number (str_p)); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_is_value_symbol (value)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number.")); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if (ecma_is_value_object (value)) { @@ -416,12 +381,12 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/ return ECMA_VALUE_EMPTY; } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_is_value_symbol (value)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number.")); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (ecma_is_value_boolean (value)); @@ -430,16 +395,16 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/ } /* ecma_get_number */ /** - * ToString operation helper function. + * ToString operation. * * See also: * ECMA-262 v5, 9.8 * * @return NULL - if the conversion fails - * ecma-string - otherwise + * pointer to the string descriptor - otherwise */ -static ecma_string_t * -ecma_to_op_string_helper (ecma_value_t value) /**< ecma value */ +ecma_string_t * +ecma_op_to_string (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); @@ -452,7 +417,7 @@ ecma_to_op_string_helper (ecma_value_t value) /**< ecma value */ return NULL; } - ecma_string_t *ret_string_p = ecma_to_op_string_helper (prim_value); + ecma_string_t *ret_string_p = ecma_op_to_string (prim_value); ecma_free_value (prim_value); @@ -491,13 +456,13 @@ ecma_to_op_string_helper (ecma_value_t value) /**< ecma value */ { return ecma_get_magic_string (LIT_MAGIC_STRING_NULL); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) else if (ecma_is_value_symbol (value)) { ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a string.")); return NULL; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) @@ -506,31 +471,6 @@ ecma_to_op_string_helper (ecma_value_t value) /**< ecma value */ } return ecma_get_magic_string (LIT_MAGIC_STRING_FALSE); -} /* ecma_to_op_string_helper */ - -/** - * ToString operation. - * - * See also: - * ECMA-262 v5, 9.8 - * - * @return ecma value - * Returned value must be freed with ecma_free_value - */ -ecma_value_t -ecma_op_to_string (ecma_value_t value) /**< ecma value */ -{ - ecma_check_value_type_is_spec_defined (value); - - ecma_string_t *string_p = ecma_to_op_string_helper (value); - - if (JERRY_UNLIKELY (string_p == NULL)) - { - /* Note: At this point the error has already been thrown. */ - return ECMA_VALUE_ERROR; - } - - return ecma_make_string_value (string_p); } /* ecma_op_to_string */ /** @@ -544,16 +484,16 @@ ecma_op_to_prop_name (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_is_value_symbol (value)) { ecma_string_t *symbol_p = ecma_get_symbol_from_value (value); ecma_ref_ecma_string (symbol_p); return symbol_p; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ - return ecma_to_op_string_helper (value); + return ecma_op_to_string (value); } /* ecma_op_to_prop_name */ /** @@ -582,12 +522,12 @@ ecma_op_to_object (ecma_value_t value) /**< ecma value */ { return ecma_copy_value (value); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) else if (ecma_is_value_symbol (value)) { return ecma_op_create_symbol_object (value); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ else { if (ecma_is_value_undefined (value) @@ -654,38 +594,42 @@ ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_des } else { - /* 4. */ +#if !ENABLED (JERRY_ES2015) JERRY_ASSERT (src_prop_desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)); - - /* a. */ - if (src_prop_desc_p->get_p == NULL) +#else /* ENABLED (JERRY_ES2015) */ + if (src_prop_desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)) +#endif /* ENABLED (JERRY_ES2015) */ { - prop_desc.value = ECMA_VALUE_UNDEFINED; - } - else - { - prop_desc.value = ecma_make_object_value (src_prop_desc_p->get_p); - } + /* a. */ + if (src_prop_desc_p->get_p == NULL) + { + prop_desc.value = ECMA_VALUE_UNDEFINED; + } + else + { + prop_desc.value = ecma_make_object_value (src_prop_desc_p->get_p); + } - completion = ecma_op_object_define_own_property (obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_GET), - &prop_desc); - JERRY_ASSERT (ecma_is_value_true (completion)); + completion = ecma_op_object_define_own_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_GET), + &prop_desc); + JERRY_ASSERT (ecma_is_value_true (completion)); - /* b. */ - if (src_prop_desc_p->set_p == NULL) - { - prop_desc.value = ECMA_VALUE_UNDEFINED; - } - else - { - prop_desc.value = ecma_make_object_value (src_prop_desc_p->set_p); - } + /* b. */ + if (src_prop_desc_p->set_p == NULL) + { + prop_desc.value = ECMA_VALUE_UNDEFINED; + } + else + { + prop_desc.value = ecma_make_object_value (src_prop_desc_p->set_p); + } - completion = ecma_op_object_define_own_property (obj_p, - ecma_get_magic_string (LIT_MAGIC_STRING_SET), - &prop_desc); - JERRY_ASSERT (ecma_is_value_true (completion)); + completion = ecma_op_object_define_own_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_SET), + &prop_desc); + JERRY_ASSERT (ecma_is_value_true (completion)); + } } prop_desc.value = ecma_make_boolean_value (src_prop_desc_p->flags & ECMA_PROP_IS_ENUMERABLE); @@ -923,7 +867,7 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ * conversion error otherwise */ ecma_value_t -ecma_op_to_integer (ecma_value_t value, /**< ecma value*/ +ecma_op_to_integer (ecma_value_t value, /**< ecma value */ ecma_number_t *number_p) /**< [out] ecma number */ { if (ECMA_IS_VALUE_ERROR (value)) @@ -972,7 +916,7 @@ ecma_op_to_integer (ecma_value_t value, /**< ecma value*/ * conversion error otherwise */ ecma_value_t -ecma_op_to_length (ecma_value_t value, /**< ecma value*/ +ecma_op_to_length (ecma_value_t value, /**< ecma value */ uint32_t *length) /**< [out] ecma number */ { /* 1 */ @@ -1025,6 +969,70 @@ ecma_op_to_length (ecma_value_t value, /**< ecma value*/ #endif /* ENABLED (JERRY_ES2015) */ } /* ecma_op_to_length */ +#if ENABLED (JERRY_ES2015) +/** + * CreateListFromArrayLike operation. + * Different types are not handled yet. + * + * See also: + * ECMA-262 v6, 7.3.17 + * + * @return ecma_collection_t if successful + * NULL otherwise + */ +ecma_collection_t * +ecma_op_create_list_from_array_like (ecma_value_t arr, /**< array value */ + bool prop_names_only) /**< true - accept only property names + false - otherwise */ +{ + /* 1. */ + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (arr)); + + /* 3. */ + if (!ecma_is_value_object (arr)) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an Object.")); + return NULL; + } + ecma_object_t *obj_p = ecma_get_object_from_value (arr); + + /* 4. 5. */ + ecma_length_t len; + if (ECMA_IS_VALUE_ERROR (ecma_op_object_get_length (obj_p, &len))) + { + return NULL; + } + + /* 6. */ + ecma_collection_t *list_ptr = ecma_new_collection (); + + /* 7. 8. */ + for (uint32_t idx = 0; idx < len; idx++) + { + ecma_value_t next = ecma_op_object_get_by_uint32_index (obj_p, idx); + if (ECMA_IS_VALUE_ERROR (next)) + { + ecma_collection_free (list_ptr); + return NULL; + } + + if (prop_names_only + && !ecma_is_value_prop_name (next)) + { + ecma_free_value (next); + ecma_collection_free (list_ptr); + ecma_raise_type_error (ECMA_ERR_MSG ("Property name is neither Symbol nor String.")); + return NULL; + } + + ecma_collection_push_back (list_ptr, next); + } + + /* 9. */ + return list_ptr; +} /* ecma_op_create_list_from_array_like */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-conversion.h b/jerry-core/ecma/operations/ecma-conversion.h index 61e51177..dd3dd64e 100644 --- a/jerry-core/ecma/operations/ecma-conversion.h +++ b/jerry-core/ecma/operations/ecma-conversion.h @@ -32,7 +32,7 @@ */ typedef enum { - ECMA_PREFERRED_TYPE_NO, /**< no preferred type is specified */ + ECMA_PREFERRED_TYPE_NO = 0, /**< no preferred type is specified */ ECMA_PREFERRED_TYPE_NUMBER, /**< Number */ ECMA_PREFERRED_TYPE_STRING /**< String */ } ecma_preferred_type_hint_t; @@ -46,11 +46,14 @@ ecma_value_t ecma_op_to_primitive (ecma_value_t value, ecma_preferred_type_hint_ bool ecma_op_to_boolean (ecma_value_t value); ecma_value_t ecma_op_to_number (ecma_value_t value); ecma_value_t ecma_get_number (ecma_value_t value, ecma_number_t *number_p); -ecma_value_t ecma_op_to_string (ecma_value_t value); +ecma_string_t *ecma_op_to_string (ecma_value_t value); ecma_string_t *ecma_op_to_prop_name (ecma_value_t value); ecma_value_t ecma_op_to_object (ecma_value_t value); ecma_value_t ecma_op_to_integer (ecma_value_t value, ecma_number_t *number_p); ecma_value_t ecma_op_to_length (ecma_value_t value, uint32_t *length); +#if ENABLED (JERRY_ES2015) +ecma_collection_t *ecma_op_create_list_from_array_like (ecma_value_t arr, bool prop_names_only); +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_desc_p); ecma_value_t ecma_op_to_property_descriptor (ecma_value_t obj_value, ecma_property_descriptor_t *out_prop_desc_p); diff --git a/jerry-core/ecma/operations/ecma-dataview-object.c b/jerry-core/ecma/operations/ecma-dataview-object.c index 877b6223..85cac962 100644 --- a/jerry-core/ecma/operations/ecma-dataview-object.c +++ b/jerry-core/ecma/operations/ecma-dataview-object.c @@ -66,28 +66,34 @@ ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments li } /* 4 - 6. */ - int32_t offset = 0; + uint32_t offset = 0; if (arguments_list_len > 1) { - ecma_number_t number_offset; - ecma_value_t number_offset_value = ecma_get_number (arguments_list_p[1], &number_offset); - - if (ECMA_IS_VALUE_ERROR (number_offset_value)) + ecma_number_t number_offset, offset_num; + if (ECMA_IS_VALUE_ERROR (ecma_get_number (arguments_list_p[1], &number_offset))) { - return number_offset_value; + return ECMA_VALUE_ERROR; + } + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arguments_list_p[1], &offset_num))) + { + return ECMA_VALUE_ERROR; } - offset = ecma_number_to_int32 (number_offset); - /* 7. */ - if (number_offset != offset || offset < 0) + if (number_offset != offset_num || offset_num < 0) { return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); } + + offset = (uint32_t) offset_num; } - /* 8. TODO: Throw TypeError, when Detached ArrayBuffer will be supported. */ + /* 8. */ + if (ecma_arraybuffer_is_detached (buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } /* 9. */ ecma_length_t buffer_byte_length = ecma_arraybuffer_get_length (buffer_p); @@ -103,8 +109,7 @@ ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments li if (arguments_list_len > 2) { /* 12.a */ - ecma_number_t byte_length; - ecma_value_t byte_length_value = ecma_get_number (arguments_list_p[2], &byte_length); + ecma_value_t byte_length_value = ecma_op_to_length (arguments_list_p[2], &viewByteLength); /* 12.b */ if (ECMA_IS_VALUE_ERROR (byte_length_value)) @@ -112,30 +117,6 @@ ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments li return byte_length_value; } - int32_t byte_length_int32 = ecma_number_to_int32 (byte_length); - - if (ecma_number_is_nan (byte_length)) - { - viewByteLength = 0; - } - else if (ecma_number_is_infinity (byte_length)) - { - if (ecma_number_is_negative (byte_length)) - { - return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid DataView length")); - } - - viewByteLength = UINT32_MAX; - } - else if (byte_length_int32 <= 0) - { - viewByteLength = 0; - } - else - { - viewByteLength = JERRY_MIN ((ecma_length_t) byte_length_int32, UINT32_MAX); - } - /* 12.c */ if ((ecma_number_t) offset + viewByteLength > buffer_byte_length) { @@ -268,7 +249,7 @@ ecma_op_dataview_get_set_view_value (ecma_value_t view, /**< the operation's 'vi /* 3 - 5. */ ecma_number_t number_index; - ecma_value_t number_index_value = ecma_get_number (request_index, &number_index); + ecma_value_t number_index_value = ecma_op_to_integer (request_index, &number_index); if (ECMA_IS_VALUE_ERROR (number_index_value)) { @@ -291,6 +272,10 @@ ecma_op_dataview_get_set_view_value (ecma_value_t view, /**< the operation's 'vi /* 9. */ ecma_object_t *buffer_p = view_p->buffer_p; JERRY_ASSERT (ecma_object_class_is (buffer_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + if (ecma_arraybuffer_is_detached (buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } /* 10. */ uint32_t view_offset = view_p->byte_offset; @@ -344,6 +329,26 @@ ecma_op_dataview_get_set_view_value (ecma_value_t view, /**< the operation's 'vi return ECMA_VALUE_UNDEFINED; } /* ecma_op_dataview_get_set_view_value */ +/** + * Check if the value is dataview + * + * @return true - if value is a DataView object + * false - otherwise + */ +bool +ecma_is_dataview (ecma_value_t value) /**< the target need to be checked */ +{ + if (!ecma_is_value_object (value)) + { + return false; + } + + ecma_dataview_object_t *dataview_object_p = (ecma_dataview_object_t *) ecma_get_object_from_value (value); + + return (ecma_get_object_type (&dataview_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS + && dataview_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_DATAVIEW_UL); +} /* ecma_is_dataview */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-dataview-object.h b/jerry-core/ecma/operations/ecma-dataview-object.h index 3bc658ac..f2e52f92 100644 --- a/jerry-core/ecma/operations/ecma-dataview-object.h +++ b/jerry-core/ecma/operations/ecma-dataview-object.h @@ -32,6 +32,7 @@ ecma_dataview_object_t *ecma_op_dataview_get_object (ecma_value_t this_arg); ecma_value_t ecma_op_dataview_get_set_view_value (ecma_value_t view, ecma_value_t request_index, ecma_value_t little_endian, ecma_value_t value_to_set, ecma_typedarray_type_t id); +bool ecma_is_dataview (ecma_value_t value); /** * @} diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index 15a95083..09984d25 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -46,7 +46,7 @@ ecma_op_eval (ecma_string_t *code_p, /**< code string */ { ecma_value_t ret_value; -#if ENABLED (JERRY_BUILTIN_EVAL_DISABLED) +#if defined (JERRY_BUILTIN_EVAL_DISABLED) && ENABLED (JERRY_BUILTIN_EVAL_DISABLED) JERRY_UNUSED(code_p); JERRY_UNUSED(parse_opts); ret_value = ECMA_VALUE_UNDEFINED; @@ -103,9 +103,9 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_EVAL); #endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) */ -#if ENABLED (JERRY_ES2015_CLASS) - ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS (); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) + ECMA_CLEAR_LOCAL_PARSE_OPTS (); +#endif /* ENABLED (JERRY_ES2015) */ ecma_value_t parse_status = parser_parse_script (NULL, 0, diff --git a/jerry-core/ecma/operations/ecma-exceptions.c b/jerry-core/ecma/operations/ecma-exceptions.c index 19c013c6..56cd63ca 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.c +++ b/jerry-core/ecma/operations/ecma-exceptions.c @@ -238,8 +238,7 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */ error_obj_p = ecma_new_standard_error (error_type); } - JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (ecma_make_object_value (error_obj_p)); return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error */ @@ -258,7 +257,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er { JERRY_ASSERT (format != NULL); - ecma_string_t *error_msg_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); const char *start_p = format; const char *end_p = format; @@ -274,13 +273,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er /* Concat template string. */ if (end_p > start_p) { - const lit_utf8_byte_t *chars_p = (const lit_utf8_byte_t *) start_p; - lit_utf8_size_t chars_size = (lit_utf8_size_t) (end_p - start_p); - - error_msg_p = ecma_append_chars_to_string (error_msg_p, - chars_p, - chars_size, - lit_utf8_string_length (chars_p, chars_size)); + ecma_stringbuilder_append_raw (&builder, (lit_utf8_byte_t *) start_p, (lit_utf8_size_t) (end_p - start_p)); } /* Convert an argument to string without side effects. */ @@ -293,21 +286,22 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er lit_magic_string_id_t class_name = ecma_object_get_class_name (arg_object_p); arg_string_p = ecma_get_magic_string (class_name); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) else if (ecma_is_value_symbol (arg_val)) { ecma_value_t symbol_desc_value = ecma_get_symbol_descriptive_string (arg_val); arg_string_p = ecma_get_string_from_value (symbol_desc_value); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ else { - ecma_value_t str_val = ecma_op_to_string (arg_val); - arg_string_p = ecma_get_string_from_value (str_val); + arg_string_p = ecma_op_to_string (arg_val); + JERRY_ASSERT (arg_string_p != NULL); } /* Concat argument. */ - error_msg_p = ecma_concat_ecma_strings (error_msg_p, arg_string_p); + ecma_stringbuilder_append (&builder, arg_string_p); + ecma_deref_ecma_string (arg_string_p); start_p = end_p + 1; @@ -321,20 +315,16 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er /* Concat reset of template string. */ if (start_p < end_p) { - const lit_utf8_byte_t *chars_p = (const lit_utf8_byte_t *) start_p; - lit_utf8_size_t chars_size = (lit_utf8_size_t) (end_p - start_p); - - error_msg_p = ecma_append_chars_to_string (error_msg_p, - chars_p, - chars_size, - lit_utf8_string_length (chars_p, chars_size)); + ecma_stringbuilder_append_raw (&builder, (lit_utf8_byte_t *) start_p, (lit_utf8_size_t) (end_p - start_p)); } - ecma_object_t *error_obj_p = ecma_new_standard_error_with_message (error_type, error_msg_p); - ecma_deref_ecma_string (error_msg_p); + ecma_string_t *builder_str_p = ecma_stringbuilder_finalize (&builder); - JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + ecma_object_t *error_obj_p = ecma_new_standard_error_with_message (error_type, builder_str_p); + + ecma_deref_ecma_string (builder_str_p); + + jcontext_raise_exception (ecma_make_object_value (error_obj_p)); return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error_with_format */ diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index d1296f35..0ee43528 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -15,15 +15,16 @@ #include "ecma-alloc.h" #include "ecma-builtin-helpers.h" -#include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "lit-char-helpers.h" #include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-objects-arguments.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" #include "jcontext.h" @@ -34,21 +35,58 @@ * @{ */ +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) /** - * Checks whether the type is a normal or arrow function. + * Get the resource name from the compiled code header * - * @return true - if the type is a normal or arrow function; + * @return resource name as ecma-string + */ +ecma_value_t +ecma_op_resource_name (const ecma_compiled_code_t *bytecode_header_p) +{ + JERRY_ASSERT (bytecode_header_p != NULL); + + uint8_t *byte_p = (uint8_t *) bytecode_header_p; + byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; + + ecma_value_t *resource_name_p = (ecma_value_t *) byte_p; + resource_name_p -= ecma_compiled_code_get_formal_params (bytecode_header_p); + +#if ENABLED (JERRY_ES2015) + if (bytecode_header_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + { + resource_name_p--; + } +#endif /* ENABLED (JERRY_ES2015) */ + + return resource_name_p[-1]; +} /* ecma_op_resource_name */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + +/** + * IsCallable operation. + * + * See also: ECMA-262 v5, 9.11 + * + * @return true - if the given object is callable; * false - otherwise */ inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_is_normal_or_arrow_function (ecma_object_type_t type) /**< object type */ +ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */ { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - return (type == ECMA_OBJECT_TYPE_FUNCTION || type == ECMA_OBJECT_TYPE_ARROW_FUNCTION); -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - return (type == ECMA_OBJECT_TYPE_FUNCTION); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -} /* ecma_is_normal_or_arrow_function */ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + + const ecma_object_type_t type = ecma_get_object_type (obj_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) + { + return ecma_op_is_callable (((ecma_proxy_object_t *) obj_p)->target); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return type >= ECMA_OBJECT_TYPE_FUNCTION; +} /* ecma_op_object_is_callable */ /** * IsCallable operation. @@ -61,25 +99,47 @@ ecma_is_normal_or_arrow_function (ecma_object_type_t type) /**< object type */ bool ecma_op_is_callable (ecma_value_t value) /**< ecma value */ { - if (!ecma_is_value_object (value)) - { - return false; - } + return (ecma_is_value_object (value) + && ecma_op_object_is_callable (ecma_get_object_from_value (value))); +} /* ecma_op_is_callable */ - ecma_object_t *obj_p = ecma_get_object_from_value (value); - - JERRY_ASSERT (obj_p != NULL); +/** + * Checks whether the given object implements [[Construct]]. + * + * @return true - if the given object is constructor; + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */ +{ JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); ecma_object_type_t type = ecma_get_object_type (obj_p); - return (type == ECMA_OBJECT_TYPE_FUNCTION -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - || type == ECMA_OBJECT_TYPE_ARROW_FUNCTION -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION - || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION); -} /* ecma_op_is_callable */ + while (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION) + { + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) obj_p; + + obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + bound_func_p->header.u.bound_function.target_function); + + type = ecma_get_object_type (obj_p); + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) + { + return ecma_is_constructor (((ecma_proxy_object_t *) obj_p)->target); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (type == ECMA_OBJECT_TYPE_FUNCTION) + { + return (!ecma_get_object_is_builtin (obj_p) || !ecma_builtin_function_is_routine (obj_p)); + } + + return (type >= ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); +} /* ecma_object_is_constructor */ /** * Checks whether the value is Object that implements [[Construct]]. @@ -90,26 +150,64 @@ ecma_op_is_callable (ecma_value_t value) /**< ecma value */ bool ecma_is_constructor (ecma_value_t value) /**< ecma value */ { - if (!ecma_is_value_object (value)) - { - return false; - } - - ecma_object_t *obj_p = ecma_get_object_from_value (value); - - JERRY_ASSERT (obj_p != NULL); - JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); - - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION) - { - return (!ecma_get_object_is_builtin (obj_p) - || !ecma_builtin_function_is_routine (obj_p)); - } - - return (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION - || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + return (ecma_is_value_object (value) + && ecma_object_is_constructor (ecma_get_object_from_value (value))); } /* ecma_is_constructor */ +/** + * Helper method to count and convert the arguments for the Function/GeneratorFunction constructor call. + * + * See also: + * ECMA 262 v5.1 15.3.2.1 steps 5.a-d + * ECMA 262 v6 19.2.1.1.1 steps 8 + * + * @return ecma value - concatenated arguments as a string. + * Returned value must be freed with ecma_free_value. + */ +static ecma_string_t * +ecma_op_create_dynamic_function_arguments_helper (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + if (arguments_list_len <= 1) + { + return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + } + + ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + return str_p; + } + + if (arguments_list_len == 2) + { + return str_p; + } + + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (str_p); + ecma_deref_ecma_string (str_p); + + for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++) + { + str_p = ecma_op_to_string (arguments_list_p[idx]); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + ecma_stringbuilder_destroy (&builder); + return str_p; + } + + ecma_stringbuilder_append_char (&builder, LIT_CHAR_COMMA); + ecma_stringbuilder_append (&builder, str_p); + ecma_deref_ecma_string (str_p); + } + + return ecma_stringbuilder_finalize (&builder); +} /* ecma_op_create_dynamic_function_arguments_helper */ + /** * Function object creation operation. * @@ -117,14 +215,15 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */ * * @return pointer to newly created Function object */ -ecma_object_t * +static ecma_object_t * ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ - const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ + const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */ + ecma_builtin_id_t proto_id) /**< builtin id of the prototype object */ { JERRY_ASSERT (ecma_is_lexical_environment (scope_p)); /* 1., 4., 13. */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id); size_t function_object_size = sizeof (ecma_extended_object_t); @@ -156,25 +255,22 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p; /* 9. */ - ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, scope_p); + ECMA_SET_NON_NULL_POINTER_TAG (ext_func_p->u.function.scope_cp, scope_p, 0); /* 10., 11., 12. */ #if ENABLED (JERRY_SNAPSHOT_EXEC) - if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) - { - ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); - } - else + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) { ext_func_p->u.function.bytecode_cp = ECMA_NULL_POINTER; ((ecma_static_function_t *) func_p)->bytecode_p = bytecode_data_p; } -#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ - ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + else #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ + { + ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + } /* 14., 15., 16., 17., 18. */ /* @@ -186,7 +282,153 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ return func_p; } /* ecma_op_create_function_object */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +/** + * CreateDynamicFunction operation + * + * See also: + * ECMA-262 v5, 15.3. + * ECMA-262 v6, 19.2.1.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * constructed function object - otherwise + */ +ecma_value_t +ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len, /**< number of arguments */ + ecma_parse_opts_t parse_opts) /**< parse options */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + ecma_string_t *arguments_str_p = ecma_op_create_dynamic_function_arguments_helper (arguments_list_p, + arguments_list_len); + + if (JERRY_UNLIKELY (arguments_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_string_t *function_body_str_p; + + if (arguments_list_len > 0) + { + function_body_str_p = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]); + + if (JERRY_UNLIKELY (function_body_str_p == NULL)) + { + ecma_deref_ecma_string (arguments_str_p); + return ECMA_VALUE_ERROR; + } + } + else + { + /* Very unlikely code path, not optimized. */ + function_body_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + } + + ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); + ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); + +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + ecma_compiled_code_t *bytecode_data_p = NULL; + + ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, + arguments_buffer_size, + function_body_buffer_p, + function_body_buffer_size, + parse_opts, + &bytecode_data_p); + + if (!ECMA_IS_VALUE_ERROR (ret_value)) + { + JERRY_ASSERT (ecma_is_value_true (ret_value)); + + ecma_object_t *global_env_p = ecma_get_global_environment (); + ecma_builtin_id_t fallback_proto = ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE; + +#if ENABLED (JERRY_ES2015) + ecma_object_t *new_target_p = JERRY_CONTEXT (current_new_target); + bool is_generator_func = parse_opts & ECMA_PARSE_GENERATOR_FUNCTION; + + if (is_generator_func) + { + fallback_proto = ECMA_BUILTIN_ID_GENERATOR; + } + + if (new_target_p == NULL) + { + if (is_generator_func) + { + new_target_p = ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_FUNCTION); + } + else + { + new_target_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION); + } + } + + ecma_object_t *proto = ecma_op_get_prototype_from_constructor (new_target_p, fallback_proto); + + if (JERRY_UNLIKELY (proto == NULL)) + { + ecma_bytecode_deref (bytecode_data_p); + ecma_deref_ecma_string (arguments_str_p); + ecma_deref_ecma_string (function_body_str_p); + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *func_obj_p = ecma_op_create_function_object (global_env_p, bytecode_data_p, fallback_proto); + +#if ENABLED (JERRY_ES2015) + ECMA_SET_NON_NULL_POINTER (func_obj_p->u2.prototype_cp, proto); + ecma_deref_object (proto); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_bytecode_deref (bytecode_data_p); + ret_value = ecma_make_object_value (func_obj_p); + } + + ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size); + ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size); + + ecma_deref_ecma_string (arguments_str_p); + ecma_deref_ecma_string (function_body_str_p); + + return ret_value; +} /* ecma_op_create_dynamic_function */ + +/** + * Function object creation operation. + * + * See also: ECMA-262 v5, 13.2 + * + * @return pointer to newly created Function object + */ +ecma_object_t * +ecma_op_create_simple_function_object (ecma_object_t *scope_p, /**< function's scope */ + const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ +{ + return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); +} /* ecma_op_create_simple_function_object */ + +#if ENABLED (JERRY_ES2015) + +/** + * GeneratorFunction object creation operation. + * + * See also: ECMA-262 v5, 13.2 + * + * @return pointer to newly created Function object + */ +ecma_object_t * +ecma_op_create_generator_function_object (ecma_object_t *scope_p, /**< function's scope */ + const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ +{ + return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_GENERATOR); +} /* ecma_op_create_generator_function_object */ /** * Arrow function object creation operation. @@ -213,33 +455,38 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc ecma_object_t *func_p = ecma_create_object (prototype_obj_p, arrow_function_object_size, - ECMA_OBJECT_TYPE_ARROW_FUNCTION); + ECMA_OBJECT_TYPE_FUNCTION); ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_p; - ECMA_SET_NON_NULL_POINTER (arrow_func_p->scope_cp, scope_p); + ECMA_SET_NON_NULL_POINTER_TAG (arrow_func_p->header.u.function.scope_cp, scope_p, 0); #if ENABLED (JERRY_SNAPSHOT_EXEC) - if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { - ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + arrow_func_p->header.u.function.bytecode_cp = ECMA_NULL_POINTER; + ((ecma_static_arrow_function_t *) func_p)->bytecode_p = bytecode_data_p; } else { - arrow_func_p->bytecode_cp = ECMA_NULL_POINTER; - ((ecma_static_arrow_function_t *) func_p)->bytecode_p = bytecode_data_p; +#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ + ECMA_SET_INTERNAL_VALUE_POINTER (arrow_func_p->header.u.function.bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); +#if ENABLED (JERRY_SNAPSHOT_EXEC) } -#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ - ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); + arrow_func_p->new_target = ECMA_VALUE_UNDEFINED; + + if (JERRY_CONTEXT (current_new_target) != NULL) + { + arrow_func_p->new_target = ecma_make_object_value (JERRY_CONTEXT (current_new_target)); + } return func_p; } /* ecma_op_create_arrow_function_object */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * External function object creation operation. @@ -296,99 +543,29 @@ ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< fun #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ } /* ecma_op_function_get_compiled_code */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - +#if ENABLED (JERRY_ES2015) /** - * Get compiled code of an arrow function object. + * Check whether the given object [[FunctionKind]] internal slot value is "generator". * - * @return compiled code + * @return true - if the given object is a generator function + * false - otherwise */ -inline const ecma_compiled_code_t * JERRY_ATTR_ALWAYS_INLINE -ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p) /**< arrow function pointer */ +bool +ecma_op_function_is_generator (ecma_object_t *obj_p) /**< object */ { -#if ENABLED (JERRY_SNAPSHOT_EXEC) - if (arrow_function_p->bytecode_cp != ECMA_NULL_POINTER) + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION + && !ecma_get_object_is_builtin (obj_p)) { - return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_function_p->bytecode_cp); + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) obj_p; + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_obj_p); + + return (bytecode_data_p->status_flags & CBC_CODE_FLAGS_GENERATOR) != 0; } - else - { - return ((ecma_static_arrow_function_t *) arrow_function_p)->bytecode_p; - } -#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ - return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_function_p->bytecode_cp); -#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ -} /* ecma_op_arrow_function_get_compiled_code */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + return false; +} /* ecma_op_function_is_generator */ -#if ENABLED (JERRY_ES2015_CLASS) -/** - * Helper function for implicit class constructors [[HasInstance]] check. - * - * @return ecma value - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -ecma_op_implicit_class_constructor_has_instance (ecma_object_t *func_obj_p, /**< Function object */ - ecma_value_t value) /**< argument 'V' */ -{ - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - - /* Since bound functions represents individual class constructor functions, we should check - that the given value is instance of either of the bound function chain elements. */ - do - { - ecma_object_t *v_obj_p = ecma_get_object_from_value (value); - - ecma_value_t prototype_obj_value = ecma_op_object_get_by_magic_id (func_obj_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (prototype_obj_value)) - { - return prototype_obj_value; - } - - if (!ecma_is_value_object (prototype_obj_value)) - { - ecma_free_value (prototype_obj_value); - return ecma_raise_type_error (ECMA_ERR_MSG ("Object expected.")); - } - - ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); - - while (true) - { - jmem_cpointer_t v_obj_cp = v_obj_p->u2.prototype_cp; - - if (v_obj_cp == JMEM_CP_NULL) - { - break; - } - - v_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, v_obj_cp); - - if (v_obj_p == prototype_obj_p) - { - ecma_deref_object (prototype_obj_p); - return ECMA_VALUE_TRUE; - } - } - - ecma_deref_object (prototype_obj_p); - - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; - - func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - } - while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - - return ECMA_VALUE_FALSE; -} /* ecma_op_implicit_class_constructor_has_instance */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * 15.3.5.3 implementation of [[HasInstance]] for Function objects @@ -414,21 +591,15 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); /* 1. 3. */ - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) func_obj_p; -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (ext_function_p->u.bound_function.args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR)) - { - return ecma_op_implicit_class_constructor_has_instance (func_obj_p, value); - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); + func_obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + bound_func_p->header.u.bound_function.target_function); } - JERRY_ASSERT (ecma_is_normal_or_arrow_function (ecma_get_object_type (func_obj_p)) - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION + || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION + || ECMA_OBJECT_IS_PROXY (func_obj_p)); ecma_object_t *v_obj_p = ecma_get_object_from_value (value); @@ -449,14 +620,40 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); JERRY_ASSERT (prototype_obj_p != NULL); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + ecma_value_t result = ECMA_VALUE_ERROR; +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_value_t result = ECMA_VALUE_FALSE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ while (true) { - jmem_cpointer_t v_obj_cp = v_obj_p->u2.prototype_cp; + jmem_cpointer_t v_obj_cp; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (v_obj_p)) + { + ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p); + + if (ECMA_IS_VALUE_ERROR (parent)) + { + break; + } + + v_obj_cp = ecma_proxy_object_prototype_to_cp (parent); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ if (v_obj_cp == JMEM_CP_NULL) { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + result = ECMA_VALUE_FALSE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ break; } @@ -473,223 +670,377 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * return result; } /* ecma_op_function_has_instance */ - -#if ENABLED (JERRY_ES2015_CLASS) -/** - * Indicates whether the class has been invoked with 'new'. - */ -#define ECMA_CLASS_CONSTRUCT_FLAG ((uintptr_t) 0x01u) -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) /** - * Sets the construct flag in the arguments list pointer. + * GetSuperConstructor operation for class methods * - * @return arguments list pointer with the construct flag - */ -static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_set_construct_flag (const ecma_value_t *arguments_list_p) /**< original arguments list pointer */ -{ - /* Any ecma value list must be aligned to 4 byte. */ - JERRY_ASSERT ((((uintptr_t) arguments_list_p) & 0x3) == 0); - -#if ENABLED (JERRY_ES2015_CLASS) - arguments_list_p = (const ecma_value_t *)(((uintptr_t) arguments_list_p) | ECMA_CLASS_CONSTRUCT_FLAG); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - return arguments_list_p; -} /* ecma_op_function_set_construct_flag */ - -/** - * Clears the construct flag in the arguments list pointer. + * See also: ECMAScript v6, 12.3.5.2 * - * @return arguments list pointer without the construct flag + * @return ECMA_VALUE_ERROR - if the operation fails + * super constructor - otherwise */ -static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_clear_construct_flag (const ecma_value_t *arguments_list_p) /**< modified arguments list pointer */ +ecma_value_t +ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function object */ { -#if ENABLED (JERRY_ES2015_CLASS) - arguments_list_p = (const ecma_value_t *)(((uintptr_t) arguments_list_p) & ~ECMA_CLASS_CONSTRUCT_FLAG); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + ecma_object_t *super_ctor_p; - return arguments_list_p; -} /* ecma_op_function_clear_construct_flag */ - -/** - * Returns true if the construct flag is set. - * - * @return true, if construct flag is set, false otherwise - */ -static inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_has_construct_flag (const ecma_value_t *arguments_list_p) /**< modified arguments list pointer */ -{ -#if ENABLED (JERRY_ES2015_CLASS) - return (((uintptr_t) arguments_list_p) & ECMA_CLASS_CONSTRUCT_FLAG); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ - JERRY_UNUSED (arguments_list_p); - return false; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -} /* ecma_op_function_has_construct_flag */ - -#if ENABLED (JERRY_ES2015_CLASS) -/** - * Returns the closest declarative lexical enviroment to the super object bound lexical enviroment. - * - * @return the found lexical enviroment - */ -static ecma_object_t * -ecma_op_find_super_declerative_lex_env (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - JERRY_ASSERT (lex_env_p != NULL); - JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) != ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); - - while (true) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (func_obj_p)) { - jmem_cpointer_t lex_env_outer_cp = lex_env_p->u2.outer_reference_cp; + ecma_value_t super_ctor = ecma_proxy_object_get_prototype_of (func_obj_p); - if (lex_env_outer_cp != JMEM_CP_NULL) + if (ECMA_IS_VALUE_ERROR (super_ctor)) { - ecma_object_t *lex_env_outer_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_outer_cp); - - if (ecma_get_lex_env_type (lex_env_outer_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) - { - JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); - return lex_env_p; - } - - lex_env_p = lex_env_outer_p; + return super_ctor; } - else - { - return NULL; - } - } -} /* ecma_op_find_super_declerative_lex_env */ -/** - * Returns with the current class this_binding property - * - * @return NULL - if the property was not found - * the found property - otherwise - */ -static ecma_property_t * -ecma_op_get_class_this_binding_property (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - JERRY_ASSERT (lex_env_p); - JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p)); - - lex_env_p = ecma_op_find_super_declerative_lex_env (lex_env_p); - ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING); - - return lex_env_p == NULL ? NULL : ecma_find_named_property (lex_env_p, name_p); -} /* ecma_op_get_class_this_binding_property */ - -/** - * Checks whether the 'super(...)' has been called. - * - * @return true - if the 'super (...)' has been called - * false - otherwise - */ -inline bool JERRY_ATTR_PURE -ecma_op_is_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - return (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); -} /* ecma_op_is_super_called */ - -/** - * Sets the value of 'super(...)' has been called. - */ -inline void -ecma_op_set_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL); - ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY (property_p); -} /* ecma_op_set_super_called */ - -/** - * Sets the class context this_binding value. - */ -void -ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, /**< starting lexical enviroment */ - ecma_value_t this_binding) /**< 'this' argument's value */ -{ - JERRY_ASSERT (ecma_is_value_object (this_binding)); - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - ecma_property_value_t *value_p; - - if (property_p) - { - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); - value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + super_ctor_p = ecma_is_value_null (super_ctor) ? NULL : ecma_get_object_from_value (super_ctor); } else { - ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING); - value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); - ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (func_obj_p); + if (proto_cp == JMEM_CP_NULL) + { + super_ctor_p = NULL; + } + else + { + super_ctor_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (super_ctor_p); + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p)) + { + if (super_ctor_p != NULL) + { + ecma_deref_object (super_ctor_p); + } + return ecma_raise_type_error (ECMA_ERR_MSG ("Super binding must be a constructor.")); } - value_p->value = this_binding; -} /* ecma_op_set_class_this_binding */ + return ecma_make_object_value (super_ctor_p); +} /* ecma_op_function_get_super_constructor */ +#endif /* ENABLED (JERRY_ES2015) */ /** - * Gets the class context this binding value. + * Ordinary internal method: GetPrototypeFromConstructor (constructor, intrinsicDefaultProto) * - * @return the class context this binding value - */ -ecma_value_t -ecma_op_get_class_this_binding (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - - ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - - JERRY_ASSERT (ecma_is_value_object (value_p->value)); - return value_p->value; -} /* ecma_op_get_class_this_binding */ - -/** - * Dummy external function for implicit constructor call. + * See also: ECMAScript v6, 9.1.15 * - * @return ECMA_VALUE_ERROR - TypeError + * @return NULL - if the operation fail (exception on the global context is raised) + * pointer to the prototype object - otherwise */ -ecma_value_t -ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */ - const ecma_value_t this_val, /**< this_arg of the function */ - const ecma_value_t args_p[], /**< argument list */ - const ecma_length_t args_count) /**< argument number */ +ecma_object_t * +ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< constructor to get prototype from */ + ecma_builtin_id_t default_proto_id) /**< intrinsicDefaultProto */ { - JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); -} /* ecma_op_function_implicit_constructor_handler_cb */ + JERRY_ASSERT (ecma_object_is_constructor (ctor_obj_p)); + JERRY_ASSERT (default_proto_id < ECMA_BUILTIN_ID__COUNT); + + ecma_value_t proto = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_PROTOTYPE); + + if (ECMA_IS_VALUE_ERROR (proto)) + { + return NULL; + } + + ecma_object_t *proto_obj_p; + + if (!ecma_is_value_object (proto)) + { + ecma_free_value (proto); + proto_obj_p = ecma_builtin_get (default_proto_id); + ecma_ref_object (proto_obj_p); + } + else + { + proto_obj_p = ecma_get_object_from_value (proto); + } + + return proto_obj_p; +} /* ecma_op_get_prototype_from_constructor */ /** - * Sets the completion value [[Prototype]] based on the this_arg value + * Perform a JavaScript function object method call. + * + * The input function object should be a pure JavaScript method + * + * @return the result of the function call. */ -void -ecma_op_set_class_prototype (ecma_value_t completion_value, /**< completion_value */ - ecma_value_t this_arg) /**< this argument*/ +static ecma_value_t +ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ + ecma_value_t this_arg_value, /**< 'this' argument's value */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ { - JERRY_ASSERT (ecma_is_value_object (completion_value)); - JERRY_ASSERT (ecma_is_value_object (this_arg)); + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION); - ecma_object_t *completion_obj_p = ecma_get_object_from_value (completion_value); - jmem_cpointer_t prototype_obj_cp = ecma_get_object_from_value (this_arg)->u2.prototype_cp; + if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p))) + { + return ecma_builtin_dispatch_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } - JERRY_ASSERT (prototype_obj_cp != JMEM_CP_NULL); + /* Entering Function Code (ECMA-262 v5, 10.4.3) */ + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; - completion_obj_p->u2.prototype_cp = prototype_obj_cp; -} /* ecma_op_set_class_prototype */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + ext_func_p->u.function.scope_cp); + + /* 8. */ + ecma_value_t this_binding = this_arg_value; + bool free_this_binding = false; + + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); + uint16_t status_flags = bytecode_data_p->status_flags; + +#if ENABLED (JERRY_ES2015) + bool is_construct_call = JERRY_CONTEXT (current_new_target) != NULL; + if (JERRY_UNLIKELY (status_flags & (CBC_CODE_FLAGS_CLASS_CONSTRUCTOR | CBC_CODE_FLAGS_GENERATOR))) + { + if (!is_construct_call && (status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); + } + + if ((status_flags & CBC_CODE_FLAGS_GENERATOR) && is_construct_call) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.")); + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + /* 1. */ +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_function_object_p = JERRY_CONTEXT (current_function_obj_p); + + if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; + + if (ecma_is_value_undefined (arrow_func_p->new_target)) + { + JERRY_CONTEXT (current_new_target) = NULL; + } + else + { + JERRY_CONTEXT (current_new_target) = ecma_get_object_from_value (arrow_func_p->new_target); + } + this_binding = arrow_func_p->this_binding; + } + else + { + JERRY_CONTEXT (current_function_obj_p) = func_obj_p; +#endif /* ENABLED (JERRY_ES2015) */ + if (!(status_flags & CBC_CODE_FLAGS_STRICT_MODE)) + { + if (ecma_is_value_undefined (this_binding) + || ecma_is_value_null (this_binding)) + { + /* 2. */ + this_binding = ecma_make_object_value (ecma_builtin_get_global ()); + } + else if (!ecma_is_value_object (this_binding)) + { + /* 3., 4. */ + this_binding = ecma_op_to_object (this_binding); + free_this_binding = true; + + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding)); + } + } +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ + + /* 5. */ + ecma_object_t *local_env_p; + if (status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) + { + local_env_p = scope_p; + } + else + { + local_env_p = ecma_create_decl_lex_env (scope_p); + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_IS_ARGUMENTS_NEEDED) + { + ecma_op_create_arguments_object (func_obj_p, + local_env_p, + arguments_list_p, + arguments_list_len, + bytecode_data_p); + } +#if ENABLED (JERRY_ES2015) + // ECMAScript v6, 9.2.2.8 + if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + { + ecma_value_t lexical_this; + lexical_this = (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp) ? ECMA_VALUE_UNINITIALIZED + : this_binding); + ecma_op_init_this_binding (local_env_p, lexical_this); + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + ecma_value_t ret_value = vm_run (bytecode_data_p, + this_binding, + local_env_p, + arguments_list_p, + arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_function_obj_p) = old_function_object_p; + + /* ECMAScript v6, 9.2.2.13 */ + if (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) + { + if (!ECMA_IS_VALUE_ERROR (ret_value) && !ecma_is_value_object (ret_value)) + { + if (!ecma_is_value_undefined (ret_value)) + { + ecma_free_value (ret_value); + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only return object or undefined.")); + } + else + { + ret_value = ecma_op_get_this_binding (local_env_p); + } + } + } + +#endif /* ENABLED (JERRY_ES2015) */ + + if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)) + { + ecma_deref_object (local_env_p); + } + + if (JERRY_UNLIKELY (free_this_binding)) + { + ecma_free_value (this_binding); + } + + return ret_value; +} /* ecma_op_function_call_simple */ + +/** + * Perform a native C method call which was registered via the API. + * + * @return the result of the function call. + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_call_external (ecma_object_t *func_obj_p, /**< Function object */ + ecma_value_t this_arg_value, /**< 'this' argument's value */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ + +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; + JERRY_ASSERT (ext_func_obj_p->u.external_handler_cb != NULL); + + ecma_value_t ret_value = ext_func_obj_p->u.external_handler_cb (ecma_make_object_value (func_obj_p), + this_arg_value, + arguments_list_p, + arguments_list_len); + if (JERRY_UNLIKELY (ecma_is_value_error_reference (ret_value))) + { + ecma_raise_error_from_error_reference (ret_value); + return ECMA_VALUE_ERROR; + } + +#if ENABLED (JERRY_DEBUGGER) + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); +#endif /* ENABLED (JERRY_DEBUGGER) */ + return ret_value; +} /* ecma_op_function_call_external */ + +/** + * Append the bound arguments into the given collection + * + * Note: + * - The whole bound chain is resolved + * - The first element of the collection contains the bounded this value + * + * @return target function of the bound function + */ +JERRY_ATTR_NOINLINE static ecma_object_t * +ecma_op_bound_function_get_argument_list (ecma_object_t *func_obj_p, /**< bound bunction object */ + ecma_collection_t *list_p) /**< list of arguments */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) func_obj_p; + + func_obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + bound_func_p->header.u.bound_function.target_function); + + ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; + + ecma_length_t args_length = 1; + + if (ecma_is_value_integer_number (args_len_or_this)) + { + args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); + } + + /* 5. */ + if (args_length != 1) + { + const ecma_value_t *args_p = (const ecma_value_t *) (bound_func_p + 1); + list_p->buffer_p[0] = *args_p; + + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION) + { + func_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, list_p); + } + ecma_collection_append (list_p, args_p + 1, args_length - 1); + } + else + { + list_p->buffer_p[0] = args_len_or_this; + } + + return func_obj_p; +} /* ecma_op_bound_function_get_argument_list */ + +/** + * [[Call]] internal method for bound function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_call_bound (ecma_object_t *func_obj_p, /**< Function object */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; + + ecma_collection_t *bound_arg_list_p = ecma_new_collection (); + ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY); + + ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p); + + ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len); + + JERRY_ASSERT (!ecma_is_value_empty (bound_arg_list_p->buffer_p[0])); + + ecma_value_t ret_value = ecma_op_function_call (target_obj_p, + bound_arg_list_p->buffer_p[0], + bound_arg_list_p->buffer_p + 1, + (ecma_length_t) (bound_arg_list_p->item_count - 1)); + + ecma_collection_destroy (bound_arg_list_p); + + return ret_value; +} /* ecma_op_function_call_bound */ /** * [[Call]] implementation for Function objects, @@ -709,500 +1060,315 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - JERRY_ASSERT (ecma_op_is_callable (ecma_make_object_value (func_obj_p))); - - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION - || !ecma_op_function_has_construct_flag (arguments_list_p)); + JERRY_ASSERT (ecma_op_object_is_callable (func_obj_p)); ECMA_CHECK_STACK_USAGE (); - switch (ecma_get_object_type (func_obj_p)) + const ecma_object_type_t type = ecma_get_object_type (func_obj_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { - case ECMA_OBJECT_TYPE_FUNCTION: - { - if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p))) - { - JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p)); + return ecma_proxy_object_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - ecma_value_t ret_value = ecma_builtin_dispatch_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + if (JERRY_UNLIKELY (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL))) + { + JERRY_CONTEXT (current_new_target) = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ - return ret_value; - } + ecma_value_t result; - /* Entering Function Code (ECMA-262 v5, 10.4.3) */ - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; - - ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_func_p->u.function.scope_cp); - - /* 8. */ - ecma_value_t this_binding = this_arg_value; - bool free_this_binding = false; - - const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); - -#if ENABLED (JERRY_ES2015_CLASS) - bool is_class_constructor = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) != 0; - - if (is_class_constructor && !ecma_op_function_has_construct_flag (arguments_list_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0; - bool is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) != 0; - - /* 1. */ - if (!is_strict) - { - if (ecma_is_value_undefined (this_binding) - || ecma_is_value_null (this_binding)) - { - /* 2. */ - this_binding = ecma_make_object_value (ecma_builtin_get_global ()); - } - else if (!ecma_is_value_object (this_binding)) - { - /* 3., 4. */ - this_binding = ecma_op_to_object (this_binding); - free_this_binding = true; - - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding)); - } - } - - arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p); - - /* 5. */ - ecma_object_t *local_env_p; - if (is_no_lex_env) - { - local_env_p = scope_p; - } - else - { - local_env_p = ecma_create_decl_lex_env (scope_p); - if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) - { - ecma_op_create_arguments_object (func_obj_p, - local_env_p, - arguments_list_p, - arguments_list_len, - bytecode_data_p); - } -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (is_class_constructor)) - { - ecma_op_set_class_this_binding (local_env_p, this_binding); - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - } - - ecma_value_t ret_value = vm_run (bytecode_data_p, - this_binding, - local_env_p, - ECMA_PARSE_NO_OPTS, - arguments_list_p, - arguments_list_len); - - if (!is_no_lex_env) - { - ecma_deref_object (local_env_p); - } - - if (JERRY_UNLIKELY (free_this_binding)) - { - ecma_free_value (this_binding); - } - - return ret_value; - } - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - { - ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; - - ecma_value_t ret_value = ext_func_obj_p->u.external_handler_cb (ecma_make_object_value (func_obj_p), - this_arg_value, - arguments_list_p, - arguments_list_len); - - if (JERRY_UNLIKELY (ecma_is_value_error_reference (ret_value))) - { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true); - return ECMA_VALUE_ERROR; - } - -#if ENABLED (JERRY_DEBUGGER) - JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); -#endif /* ENABLED (JERRY_DEBUGGER) */ - return ret_value; - } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: - { - /* Entering Function Code (ES2015, 9.2.1) */ - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; - - ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, - arrow_func_p->scope_cp); - - bool is_no_lex_env; - - const ecma_compiled_code_t *bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); - - is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) != 0; - - ecma_object_t *local_env_p = scope_p; - - if (!is_no_lex_env) - { - local_env_p = ecma_create_decl_lex_env (scope_p); - - JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED)); - } - - ecma_value_t ret_value = vm_run (bytecode_data_p, - arrow_func_p->this_binding, - local_env_p, - ECMA_PARSE_NO_OPTS, - arguments_list_p, - arguments_list_len); - - if (!is_no_lex_env) - { - ecma_deref_object (local_env_p); - } - - return ret_value; - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - default: - { - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - break; - } + if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) + { + result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } + else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + result = ecma_op_function_call_external (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } + else + { + result = ecma_op_function_call_bound (func_obj_p, arguments_list_p, arguments_list_len); } - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ - ecma_extended_object_t *ext_function_p; - ecma_object_t *target_func_obj_p; - ecma_length_t args_length; - - do - { - /* 2-3. */ - ext_function_p = (ecma_extended_object_t *) func_obj_p; - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - /* 4. */ - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - if (!ecma_is_value_integer_number (args_len_or_this)) - { -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR)) - { - if (!ecma_op_function_has_construct_flag (arguments_list_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); - } - if (ecma_get_object_is_builtin (target_func_obj_p)) - { - arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p); - } - } - else - { -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - this_arg_value = args_len_or_this; -#if ENABLED (JERRY_ES2015_CLASS) - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - args_length = 1; - } - else - { - this_arg_value = *(ecma_value_t *) (ext_function_p + 1); - args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); - } - - JERRY_ASSERT (args_length > 0); - - if (args_length == 1) - { - func_obj_p = target_func_obj_p; - } - else - { -#if ENABLED (JERRY_ES2015_CLASS) - arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p)); - args_length--; - - ecma_length_t merged_args_list_len = args_length + arguments_list_len; - ecma_value_t ret_value; - - JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); - - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - - memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t)); - memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t)); - - /* 5. */ - ret_value = ecma_op_function_call (target_func_obj_p, - this_arg_value, - merged_args_list_p, - merged_args_list_len); - - JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p); - - return ret_value; - } - } - while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - - return ecma_op_function_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); + return result; } /* ecma_op_function_call */ /** - * [[Construct]] implementation: - * 13.2.2 - for Function objects, created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION), - * and externally defined host functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); - * 15.3.4.5.1 - for Function objects, created through 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION). + * [[Construct]] internal method for bound function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_construct_bound (ecma_object_t *func_obj_p, /**< Function object */ + ecma_object_t *new_target_p, /**< new target */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + ecma_collection_t *bound_arg_list_p = ecma_new_collection (); + ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY); + + ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p); + + ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len); + + if (func_obj_p == new_target_p) + { + new_target_p = target_obj_p; + } + + ecma_value_t ret_value = ecma_op_function_construct (target_obj_p, + new_target_p, + bound_arg_list_p->buffer_p + 1, + (ecma_length_t) (bound_arg_list_p->item_count - 1)); + + ecma_collection_destroy (bound_arg_list_p); + + return ret_value; +} /* ecma_op_function_construct_bound */ + +/** + * [[Construct]] internal method for external function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_construct_external (ecma_object_t *func_obj_p, /**< Function object */ + ecma_object_t *new_target_p, /**< new target */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + + if (JERRY_UNLIKELY (proto_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_object_t *new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_value_t this_arg = ecma_make_object_value (new_this_obj_p); + ecma_deref_object (proto_p); + +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t ret_value = ecma_op_function_call_external (func_obj_p, this_arg, arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) + { + ecma_deref_object (new_this_obj_p); + return ret_value; + } + + ecma_free_value (ret_value); + + return this_arg; +} /* ecma_op_function_construct_external */ + +/** + * General [[Construct]] implementation function objects + * + * See also: ECMAScript v6, 9.2.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ - ecma_value_t this_arg_value, /**< optional 'this' object value - * or ECMA_VALUE_UNDEFINED */ + ecma_object_t *new_target_p, /**< new target */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - JERRY_ASSERT (ecma_is_value_object (this_arg_value) - || this_arg_value == ECMA_VALUE_UNDEFINED); + const ecma_object_type_t type = ecma_get_object_type (func_obj_p); - ecma_object_t *target_func_obj_p = NULL; - - while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { - /* 1-3. */ - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; + return ecma_proxy_object_construct (func_obj_p, + new_target_p, + arguments_list_p, + arguments_list_len); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - /* 4. */ - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - ecma_length_t args_length = 1; - - if (ecma_is_value_integer_number (args_len_or_this)) - { - args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); - } - - JERRY_ASSERT (args_length > 0); - - /* 5. */ - if (args_length == 1) - { -#if ENABLED (JERRY_ES2015_CLASS) - if (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR && ecma_is_value_undefined (this_arg_value)) - { - break; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - func_obj_p = target_func_obj_p; - continue; - } - - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - ecma_value_t ret_value; - - args_length--; - ecma_length_t merged_args_list_len = args_length + arguments_list_len; - - JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); - - memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t)); - memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t)); - - /* 5. */ - ret_value = ecma_op_function_construct (target_func_obj_p, - this_arg_value, - merged_args_list_p, - merged_args_list_len); - - JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p); - - return ret_value; + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) + { + return ecma_op_function_construct_bound (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); } - ecma_object_type_t type = ecma_get_object_type (func_obj_p); - -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_ARROW_FUNCTION)) + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); + return ecma_op_function_construct_external (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_get_object_is_builtin (func_obj_p))) + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_FUNCTION); + + if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p))) { - if (ecma_builtin_function_is_routine (func_obj_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor.")); - } - - ecma_value_t ret_value = ecma_builtin_dispatch_construct (func_obj_p, - arguments_list_p, - arguments_list_len); - -#if ENABLED (JERRY_ES2015_CLASS) - if (!ecma_is_value_undefined (this_arg_value) && !ECMA_IS_VALUE_ERROR (ret_value)) - { - ecma_op_set_class_prototype (ret_value, this_arg_value); - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - return ret_value; + return ecma_builtin_dispatch_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); } ecma_object_t *new_this_obj_p = NULL; + ecma_value_t this_arg; + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_obj_p); - if (JERRY_LIKELY (this_arg_value == ECMA_VALUE_UNDEFINED)) + if (byte_code_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) { - /* 5. */ - ecma_value_t prototype_prop_value = ecma_op_object_get_by_magic_id (func_obj_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (prototype_prop_value)) + if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { - return prototype_prop_value; + return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); } - /* 1., 2., 4. */ - if (ecma_is_value_object (prototype_prop_value)) - { - /* 6. */ - new_this_obj_p = ecma_create_object (ecma_get_object_from_value (prototype_prop_value), - 0, - ECMA_OBJECT_TYPE_GENERAL); - } - else - { - /* 7. */ - ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); - - new_this_obj_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL); - } - - ecma_free_value (prototype_prop_value); - - this_arg_value = ecma_make_object_value (new_this_obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor.")); } - /* 8. */ - ecma_value_t ret_value; +#if ENABLED (JERRY_ES2015) + /* 6. */ + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; - switch (type) + /* 5. */ + if (!ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_obj_p->u.function.scope_cp)) { - case ECMA_OBJECT_TYPE_FUNCTION: +#endif /* ENABLED (JERRY_ES2015) */ + /* 5.a */ + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + + /* 5.b */ + if (JERRY_UNLIKELY (proto_p == NULL)) { - arguments_list_p = ecma_op_function_set_construct_flag (arguments_list_p); - - ret_value = ecma_op_function_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - break; + return ECMA_VALUE_ERROR; } -#if ENABLED (JERRY_ES2015_CLASS) - case ECMA_OBJECT_TYPE_BOUND_FUNCTION: - { - JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p)); - JERRY_ASSERT (target_func_obj_p != NULL); - ret_value = ecma_op_function_construct (target_func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - break; - } - case ECMA_OBJECT_TYPE_GENERAL: - { - /* Catch the special case when a the class extends value in null - and the class has no explicit constructor to raise TypeError.*/ - JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p)); - JERRY_ASSERT (func_obj_p->u2.prototype_cp != JMEM_CP_NULL); - JERRY_ASSERT ((ECMA_GET_NON_NULL_POINTER (ecma_object_t, func_obj_p->u2.prototype_cp) \ - == ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE))); - - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Super constructor null is not a constructor.")); - break; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - default: - { - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); - -#if ENABLED (JERRY_ES2015_CLASS) - ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; - - if (ext_func_obj_p->u.external_handler_cb == ecma_op_function_implicit_constructor_handler_cb) - { - ret_value = ECMA_VALUE_UNDEFINED; - break; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - ret_value = ecma_op_function_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - break; - } + new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_deref_object (proto_p); + this_arg = ecma_make_object_value (new_this_obj_p); +#if ENABLED (JERRY_ES2015) } + else + { + this_arg = ECMA_VALUE_UNDEFINED; + } +#endif /* ENABLED (JERRY_ES2015) */ - /* 9. */ + ecma_value_t ret_value = ecma_op_function_call_simple (func_obj_p, this_arg, arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + /* 13.a */ if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) { +#if ENABLED (JERRY_ES2015) if (new_this_obj_p != NULL) { ecma_deref_object (new_this_obj_p); } +#else /* !ENABLED (JERRY_ES2015) */ + ecma_deref_object (new_this_obj_p); +#endif /* ENABLED (JERRY_ES2015) */ return ret_value; } - ecma_fast_free_value (ret_value); + /* 13.b */ + ecma_free_value (ret_value); + return this_arg; +} /* ecma_op_function_construct */ - if (JERRY_UNLIKELY (new_this_obj_p == NULL)) +/** + * Lazy instantiation of 'prototype' property for non-builtin and external functions + * + * @return pointer to newly instantiated property + */ +static ecma_property_t * +ecma_op_lazy_instantiate_prototype_object (ecma_object_t *object_p) /**< the function object */ +{ + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION + || ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + /* ECMA-262 v5, 13.2, 16-18 */ + + ecma_object_t *proto_object_p = NULL; + bool init_constructor = true; + +#if ENABLED (JERRY_ES2015) + if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { - ecma_ref_object (ecma_get_object_from_value (this_arg_value)); + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); + + if (byte_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + { + proto_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + init_constructor = false; + } + else if (byte_code_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) + { + return NULL; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) + if (proto_object_p == NULL) +#endif /* ENABLED (JERRY_ES2015) */ + { + proto_object_p = ecma_op_create_object_object_noarg (); } - return this_arg_value; -} /* ecma_op_function_construct */ + /* 17. */ + if (init_constructor) + { + ecma_property_value_t *constructor_prop_value_p; + constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + + constructor_prop_value_p->value = ecma_make_object_value (object_p); + } + + /* 18. */ + ecma_property_t *prototype_prop_p; + ecma_property_value_t *prototype_prop_value_p; + prototype_prop_value_p = ecma_create_named_data_property (object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE), + ECMA_PROPERTY_FLAG_WRITABLE, + &prototype_prop_p); + + prototype_prop_value_p->value = ecma_make_object_value (proto_object_p); + + ecma_deref_object (proto_object_p); + + return prototype_prop_p; +} /* ecma_op_lazy_instantiate_prototype_object */ /** * Lazy instantiation of non-builtin ecma function object's properties @@ -1221,58 +1387,66 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< { JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); - if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)) +#if ENABLED (JERRY_ES2015) + if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH)) { - /* ECMA-262 v5, 13.2, 16-18 */ + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) + { + /* Initialize 'length' property */ + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); + uint32_t len; + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p; + len = args_p->argument_end; + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p; + len = args_p->argument_end; + } - /* 16. */ - ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); + /* Set tag bit to represent initialized 'length' property */ + ECMA_SET_FIRST_BIT_TO_POINTER_TAG (ext_func_p->u.function.scope_cp); + ecma_property_t *value_prop_p; + ecma_property_value_t *value_p = ecma_create_named_data_property (object_p, + property_name_p, + ECMA_PROPERTY_FLAG_CONFIGURABLE, + &value_prop_p); + value_p->value = ecma_make_uint32_value (len); + return value_prop_p; + } - /* 17. */ - ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); + return NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ - ecma_property_value_t *constructor_prop_value_p; - constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, - magic_string_constructor_p, - ECMA_PROPERTY_CONFIGURABLE_WRITABLE, - NULL); - - constructor_prop_value_p->value = ecma_make_object_value (object_p); - - /* 18. */ - ecma_property_t *prototype_prop_p; - ecma_property_value_t *prototype_prop_value_p; - prototype_prop_value_p = ecma_create_named_data_property (object_p, - property_name_p, - ECMA_PROPERTY_FLAG_WRITABLE, - &prototype_prop_p); - - prototype_prop_value_p->value = ecma_make_object_value (proto_object_p); - - ecma_deref_object (proto_object_p); - - return prototype_prop_p; + if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE) + && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + return ecma_op_lazy_instantiate_prototype_object (object_p); } if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER) || ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS)) { const ecma_compiled_code_t *bytecode_data_p; -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION) - { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); - } - else - { -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); +#if ENABLED (JERRY_ES2015) + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)) + { + ecma_property_t *value_prop_p; + /* The property_name_p argument contans the name. */ + ecma_property_value_t *value_p = ecma_create_named_data_property (object_p, + property_name_p, + ECMA_PROPERTY_FIXED, + &value_prop_p); + value_p->value = ECMA_VALUE_NULL; + return value_prop_p; + } +#else /* !ENABLED (JERRY_ES2015) */ if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) { ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); @@ -1287,6 +1461,8 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< &caller_prop_p); return caller_prop_p; } +#endif /* ENABLED (JERRY_ES2015) */ + } return NULL; @@ -1309,15 +1485,7 @@ ecma_op_external_function_try_to_lazy_instantiate_property (ecma_object_t *objec if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)) { - ecma_property_t *prototype_prop_p; - ecma_property_value_t *prototype_prop_value_p; - prototype_prop_value_p = ecma_create_named_data_property (object_p, - property_name_p, - ECMA_PROPERTY_FLAG_WRITABLE, - &prototype_prop_p); - - prototype_prop_value_p->value = ECMA_VALUE_UNDEFINED; - return prototype_prop_p; + return ecma_op_lazy_instantiate_prototype_object (object_p); } return NULL; @@ -1340,41 +1508,56 @@ ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p if (ecma_string_is_length (property_name_p)) { - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; - ecma_object_t *target_func_obj_p; - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; + ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this; ecma_integer_value_t length = 0; + ecma_integer_value_t args_length = 1; + uint8_t length_attributes; - if (ecma_object_get_class_name (target_func_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL) + if (ecma_is_value_integer_number (args_len_or_this)) { - /* The property_name_p argument contans the 'length' string. */ - ecma_value_t get_len_value = ecma_op_object_get (target_func_obj_p, property_name_p); + args_length = ecma_get_integer_from_value (args_len_or_this); + } + +#if ENABLED (JERRY_ES2015) + if (ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (bound_func_p->header.u.bound_function.target_function)) + { + return NULL; + } + + length_attributes = ECMA_PROPERTY_FLAG_CONFIGURABLE; + length = bound_func_p->target_length - (args_length - 1); + + /* Set tag bit to represent initialized 'length' property */ + ECMA_SET_FIRST_BIT_TO_POINTER_TAG (bound_func_p->header.u.bound_function.target_function); +#else /* !ENABLED (JERRY_ES2015) */ + length_attributes = ECMA_PROPERTY_FIXED; + + ecma_object_t *target_func_p; + target_func_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, + bound_func_p->header.u.bound_function.target_function); + + if (ecma_object_get_class_name (target_func_p) == LIT_MAGIC_STRING_FUNCTION_UL) + { + /* The property_name_p argument contains the 'length' string. */ + ecma_value_t get_len_value = ecma_op_object_get (target_func_p, property_name_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value)); JERRY_ASSERT (ecma_is_value_integer_number (get_len_value)); - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - ecma_integer_value_t args_length = 1; - - if (ecma_is_value_integer_number (args_len_or_this)) - { - args_length = ecma_get_integer_from_value (args_len_or_this); - } - length = ecma_get_integer_from_value (get_len_value) - (args_length - 1); + } +#endif /* ENABLED (JERRY_ES2015) */ - if (length < 0) - { - length = 0; - } + if (length < 0) + { + length = 0; } ecma_property_t *len_prop_p; ecma_property_value_t *len_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, - ECMA_PROPERTY_FIXED, + length_attributes, &len_prop_p); len_prop_value_p->value = ecma_make_integer_value (length); @@ -1409,13 +1592,8 @@ ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p */ void ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functionobject */ - bool separate_enumerable, /**< true - list enumerable properties into - * main collection and non-enumerable - * to collection of 'skipped - * non-enumerable' properties, - * false - list all properties into main - * collection. - */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ ecma_collection_t *main_collection_p, /**< 'main' collection */ ecma_collection_t *non_enum_collection_p) /**< skipped * 'non-enumerable' @@ -1423,30 +1601,40 @@ ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functio { JERRY_UNUSED (main_collection_p); - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p; +#if ENABLED (JERRY_ES2015) + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) + { + /* Unintialized 'length' property is non-enumerable (ECMA-262 v6, 19.2.4.1) */ + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + } +#else /* !ENABLED (JERRY_ES2015) */ /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); +#endif /* ENABLED (JERRY_ES2015) */ + + const ecma_compiled_code_t *bytecode_data_p; + bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); + +#if ENABLED (JERRY_ES2015) + if (bytecode_data_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) + { + return; + } +#endif /* ENABLED (JERRY_ES2015) */ /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE)); - const ecma_compiled_code_t *bytecode_data_p; +#if ENABLED (JERRY_ES2015) + bool append_caller_and_arguments = !(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE); +#else /* !ENABLED (JERRY_ES2015) */ + bool append_caller_and_arguments = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE); +#endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION) - { - bytecode_data_p = ecma_op_arrow_function_get_compiled_code ((ecma_arrow_function_t *) object_p); - } - else - { - bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); - } -#else /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - - if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) + if (append_caller_and_arguments) { /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER)); @@ -1464,24 +1652,26 @@ ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functio * ecma_op_external_function_try_to_lazy_instantiate_property */ void -ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties - * into main collection and - * non-enumerable to collection - * of 'skipped non-enumerable' - * properties, - * false - list all properties into - * main collection. - */ - ecma_collection_t *main_collection_p, /**< 'main' collection */ - ecma_collection_t *non_enum_collection_p) /**< skipped - * collection */ +ecma_op_external_function_list_lazy_property_names (ecma_object_t *object_p, /**< function object */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ + ecma_collection_t *main_collection_p, /**< 'main' collection */ + ecma_collection_t *non_enum_collection_p) /**< skipped + * collection */ { JERRY_UNUSED (main_collection_p); - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p; - /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ - ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE)); +#if !ENABLED (JERRY_ES2015) + JERRY_UNUSED (object_p); +#else /* ENABLED (JERRY_ES2015) */ + if (!ecma_op_ordinary_object_has_own_property (object_p, ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE))) +#endif /* !ENABLED (JERRY_ES2015) */ + { + /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE)); + } } /* ecma_op_external_function_list_lazy_property_names */ /** @@ -1492,14 +1682,9 @@ ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, /* * ecma_op_bound_function_try_to_lazy_instantiate_property */ void -ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties - * into main collection and - * non-enumerable to collection - * of 'skipped non-enumerable' - * properties, - * false - list all properties into - * main collection. - */ +ecma_op_bound_function_list_lazy_property_names (ecma_object_t *object_p, /**< bound function object*/ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ ecma_collection_t *main_collection_p, /**< 'main' collection */ ecma_collection_t *non_enum_collection_p) /**< skipped * 'non-enumerable' @@ -1507,10 +1692,20 @@ ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, /**< { JERRY_UNUSED (main_collection_p); - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p; +#if ENABLED (JERRY_ES2015) + /* Unintialized 'length' property is non-enumerable (ECMA-262 v6, 19.2.4.1) */ + ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p; + if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (bound_func_p->header.u.bound_function.target_function)) + { + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (object_p); /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); +#endif /* ENABLED (JERRY_ES2015) */ /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER)); diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index b5be3358..25e47461 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -17,6 +17,7 @@ #define ECMA_FUNCTION_OBJECT_H #include "ecma-globals.h" +#include "ecma-builtins.h" #include "vm.h" /** \addtogroup ecma ECMA @@ -26,19 +27,17 @@ * @{ */ -bool ecma_is_normal_or_arrow_function (ecma_object_type_t type); +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) +ecma_value_t ecma_op_resource_name (const ecma_compiled_code_t *bytecode_header_p); +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ bool ecma_op_is_callable (ecma_value_t value); +bool ecma_op_object_is_callable (ecma_object_t *obj_p); bool ecma_is_constructor (ecma_value_t value); +bool ecma_object_is_constructor (ecma_object_t *obj_p); ecma_object_t * -ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); - -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) -ecma_object_t * -ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p, - ecma_value_t this_binding); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +ecma_op_create_simple_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); ecma_object_t * ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); @@ -46,33 +45,27 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); const ecma_compiled_code_t * ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p); -#if ENABLED (JERRY_ES2015_CLASS) -void -ecma_op_set_super_called (ecma_object_t *lex_env_p); +ecma_value_t +ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, + ecma_length_t arguments_list_len, + ecma_parse_opts_t opts); +#if ENABLED (JERRY_ES2015) +ecma_value_t +ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p); + +ecma_object_t * +ecma_op_create_generator_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); + +ecma_object_t * +ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p, + ecma_value_t this_binding); bool -ecma_op_is_super_called (ecma_object_t *lex_env_p); +ecma_op_function_is_generator (ecma_object_t *func_obj_p); +#endif /* ENABLED (JERRY_ES2015) */ -void -ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding); - -ecma_value_t -ecma_op_get_class_this_binding (ecma_object_t *lex_env_p); - -ecma_value_t -ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, - const ecma_value_t this_val, - const ecma_value_t args_p[], - const ecma_length_t args_count); - -void -ecma_op_set_class_prototype (ecma_value_t completion_value, ecma_value_t this_arg); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) -const ecma_compiled_code_t * -ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +ecma_object_t * +ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_id_t default_proto_id); ecma_value_t ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); @@ -82,7 +75,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_value_t -ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, +ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_object_t *new_target_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_property_t * @@ -96,17 +89,19 @@ ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p void ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, - bool separate_enumerable, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); void -ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, +ecma_op_external_function_list_lazy_property_names (ecma_object_t *object_p, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); void -ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, +ecma_op_bound_function_list_lazy_property_names (ecma_object_t *object_p, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index 44b7f73d..fc47534b 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -26,6 +26,7 @@ #include "ecma-function-object.h" #include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" +#include "ecma-reference.h" /** \addtogroup ecma ECMA * @{ @@ -61,26 +62,35 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme if (property_p != NULL) { *ref_base_lex_env_p = lex_env_p; - return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" + " initialized before reading their value.")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + return ecma_fast_copy_value (property_value_p->value); } break; } -#if ENABLED (JERRY_ES2015_CLASS) - case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND: +#if ENABLED (JERRY_ES2015) + case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: { break; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - - ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); + ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); if (ecma_is_value_found (result)) { + /* Note: the result may contains ECMA_VALUE_ERROR */ *ref_base_lex_env_p = lex_env_p; return result; } @@ -120,59 +130,62 @@ ecma_value_t ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */ ecma_string_t *property_name_p) /**< property name */ { - if (ecma_is_value_object (base_value)) - { - ecma_object_t *obj_p = ecma_get_object_from_value (base_value); - JERRY_ASSERT (obj_p != NULL - && !ecma_is_lexical_environment (obj_p)); + ecma_object_t *obj_p; - return ecma_op_object_get (obj_p, property_name_p); + if (JERRY_UNLIKELY (ecma_is_value_object (base_value))) + { + obj_p = ecma_get_object_from_value (base_value); } - - JERRY_ASSERT (ecma_is_value_boolean (base_value) - || ecma_is_value_number (base_value) - || ECMA_ASSERT_VALUE_IS_SYMBOL (base_value) - || ecma_is_value_string (base_value)); - - /* Fast path for the strings length property. The length of the string - can be obtained directly from the ecma-string. */ - if (ecma_is_value_string (base_value) && ecma_string_is_length (property_name_p)) + else { - ecma_string_t *string_p = ecma_get_string_from_value (base_value); + ecma_builtin_id_t id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE; - return ecma_make_uint32_value (ecma_string_get_length (string_p)); - } - - ecma_value_t object_base = ecma_op_to_object (base_value); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (object_base)); - - ecma_object_t *object_p = ecma_get_object_from_value (object_base); - JERRY_ASSERT (object_p != NULL - && !ecma_is_lexical_environment (object_p)); - - ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - - while (true) - { - ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p); - - if (ecma_is_value_found (value)) + if (JERRY_LIKELY (ecma_is_value_string (base_value))) { - ret_value = value; - break; + ecma_string_t *string_p = ecma_get_string_from_value (base_value); + + if (ecma_string_is_length (property_name_p)) + { + return ecma_make_uint32_value (ecma_string_get_length (string_p)); + } + + uint32_t index = ecma_string_get_array_index (property_name_p); + + if (index != ECMA_STRING_NOT_ARRAY_INDEX + && index < ecma_string_get_length (string_p)) + { + ecma_char_t char_at_idx = ecma_string_get_char_at_pos (string_p, index); + return ecma_make_string_value (ecma_new_ecma_string_from_code_unit (char_at_idx)); + } + +#if ENABLED (JERRY_BUILTIN_STRING) + id = ECMA_BUILTIN_ID_STRING_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_STRING) */ + } + else if (ecma_is_value_number (base_value)) + { +#if ENABLED (JERRY_BUILTIN_NUMBER) + id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + } +#if ENABLED (JERRY_ES2015) + else if (ecma_is_value_symbol (base_value)) + { + id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE; + } +#endif /* ENABLED (JERRY_ES2015) */ + else + { + JERRY_ASSERT (ecma_is_value_boolean (base_value)); +#if ENABLED (JERRY_BUILTIN_BOOLEAN) + id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ } - if (object_p->u2.prototype_cp == JMEM_CP_NULL) - { - break; - } - - object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); + obj_p = ecma_builtin_get (id); } - ecma_free_value (object_base); - - return ret_value; + return ecma_op_object_get_with_receiver (obj_p, property_name_p, base_value); } /* ecma_op_get_value_object_base */ /** @@ -204,8 +217,24 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme { if (ecma_is_property_writable (*property_p)) { - ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value); + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" + " initialized before writing their value.")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_named_data_property_assign_value (lex_env_p, property_value_p, value); } +#if ENABLED (JERRY_ES2015) + else if (ecma_is_property_enumerable (*property_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned.")); + } +#endif /* ENABLED (JERRY_ES2015) */ else if (is_strict) { return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set.")); @@ -214,19 +243,28 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme } break; } -#if ENABLED (JERRY_ES2015_CLASS) - case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND: +#if ENABLED (JERRY_ES2015) + case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: { break; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (ecma_op_object_has_property (binding_obj_p, name_p)) + ecma_value_t has_property = ecma_op_object_has_property (binding_obj_p, name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_property)) + { + return has_property; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (has_property)) { ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index a2859c95..86fdb72c 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -26,6 +26,7 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-function-object.h" +#include "jcontext.h" /** \addtogroup ecma ECMA * @{ @@ -34,7 +35,8 @@ * @{ */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + /** * Implementation of 'CreateArrayFromList' specialized for iterators * @@ -185,7 +187,7 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ if (!has_method) { /* 2.a */ - method = ecma_op_get_method_by_symbol_id (value, LIT_MAGIC_STRING_ITERATOR); + method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ITERATOR); /* 2.b */ if (ECMA_IS_VALUE_ERROR (method)) @@ -246,20 +248,20 @@ ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ /* 1 - 2. */ ecma_object_t *obj_p = ecma_get_object_from_value (iterator); - ecma_value_t next = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT); + ecma_value_t func_next = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT); - if (ECMA_IS_VALUE_ERROR (next)) + if (ECMA_IS_VALUE_ERROR (func_next)) { - return next; + return func_next; } - if (!ecma_is_value_object (next) || !ecma_op_is_callable (next)) + if (!ecma_is_value_object (func_next) || !ecma_op_is_callable (func_next)) { - ecma_free_value (next); - return ecma_raise_type_error (ECMA_ERR_MSG ("Next is not callable.")); + ecma_free_value (func_next); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator next() is not callable.")); } - ecma_object_t *next_obj_p = ecma_get_object_from_value (next); + ecma_object_t *next_obj_p = ecma_get_object_from_value (func_next); bool has_value = !ecma_is_value_empty (value); @@ -273,58 +275,107 @@ ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ result = ecma_op_function_call (next_obj_p, iterator, NULL, 0); } - ecma_free_value (next); - - /* 3. */ - if (ECMA_IS_VALUE_ERROR (result)) - { - return result; - } - - /* 4. */ - if (!ecma_is_value_object (result)) - { - ecma_free_value (result); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object.")); - } + ecma_free_value (func_next); /* 5. */ return result; } /* ecma_op_iterator_next */ /** - * IteratorComplete operation + * IteratorReturn operation * - * See also: ECMA-262 v6, 7.4.3 + * See also: ECMA-262 v6, 14.4.14 (last part) * * Note: * Returned value must be freed with ecma_free_value. * - * @return ECMA_VALUE_{FALSE, TRUE} - if success + * @return iterator result object - if success * raised error - otherwise */ static ecma_value_t -ecma_op_iterator_complete (ecma_value_t iter_result) /**< iterator value */ +ecma_op_iterator_return (ecma_value_t iterator, /**< iterator value */ + ecma_value_t value) /**< the routines's value argument */ { - /* 1. */ - JERRY_ASSERT (ecma_is_value_object (iter_result)); + JERRY_ASSERT (ecma_is_value_object (iterator)); - /* 2. */ - ecma_object_t *obj_p = ecma_get_object_from_value (iter_result); + ecma_object_t *obj_p = ecma_get_object_from_value (iterator); + ecma_value_t func_return = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_RETURN); - ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE); - - if (ECMA_IS_VALUE_ERROR (done)) + if (ECMA_IS_VALUE_ERROR (func_return)) { - return done; + return func_return; } - bool is_done = ecma_op_to_boolean (done); + if (func_return == ECMA_VALUE_UNDEFINED) + { + return ecma_create_iter_result_object (value, true); + } - ecma_free_value (done); + if (!ecma_is_value_object (func_return) || !ecma_op_is_callable (func_return)) + { + ecma_free_value (func_return); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator return() is not callable.")); + } - return ecma_make_boolean_value (is_done); -} /* ecma_op_iterator_complete */ + ecma_object_t *return_obj_p = ecma_get_object_from_value (func_return); + + ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1); + ecma_free_value (func_return); + + return result; +} /* ecma_op_iterator_return */ + +/** + * IteratorThrow operation + * + * See also: ECMA-262 v6, 14.4.14 (last part) + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator result object - if success + * raised error - otherwise + */ +static ecma_value_t +ecma_op_iterator_throw (ecma_value_t iterator, /**< iterator value */ + ecma_value_t value) /**< the routines's value argument */ +{ + JERRY_ASSERT (ecma_is_value_object (iterator)); + + ecma_object_t *obj_p = ecma_get_object_from_value (iterator); + ecma_value_t func_throw = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_THROW); + + if (ECMA_IS_VALUE_ERROR (func_throw)) + { + return func_throw; + } + + if (func_throw == ECMA_VALUE_UNDEFINED) + { + ecma_value_t result = ecma_op_iterator_close (iterator); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_free_value (result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator throw() is not available.")); + } + + if (!ecma_is_value_object (func_throw) || !ecma_op_is_callable (func_throw)) + { + ecma_free_value (func_throw); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator throw() is not callable.")); + } + + ecma_object_t *return_obj_p = ecma_get_object_from_value (func_throw); + + ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1); + ecma_free_value (func_throw); + + return result; +} /* ecma_op_iterator_throw */ /** * IteratorValue operation @@ -347,6 +398,99 @@ ecma_op_iterator_value (ecma_value_t iter_result) /**< iterator value */ return ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_VALUE); } /* ecma_op_iterator_value */ +/** + * IteratorClose operation + * + * See also: ECMA-262 v6, 7.4.6 + * + * @return ECMA_VALUE_EMPTY - if "return" is succesfully invoked, + * and the operation is called with normal completion + * ECMA_VALUE_ERROR - otherwise + */ +ecma_value_t +ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */ +{ + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (iterator)); + + /* 2. */ + ecma_value_t completion = ECMA_VALUE_EMPTY; + + if (jcontext_has_pending_exception ()) + { + completion = jcontext_take_exception (); + } + + /* 3. */ + ecma_value_t return_method = ecma_op_get_method_by_magic_id (iterator, LIT_MAGIC_STRING_RETURN); + + /* 4. */ + if (ECMA_IS_VALUE_ERROR (return_method)) + { + ecma_free_value (completion); + return return_method; + } + + /* 5. */ + if (ecma_is_value_undefined (return_method)) + { + if (ecma_is_value_empty (completion)) + { + return ECMA_VALUE_UNDEFINED; + } + + jcontext_raise_exception (completion); + return ECMA_VALUE_ERROR; + } + + /* 6. */ + ecma_object_t *return_obj_p = ecma_get_object_from_value (return_method); + ecma_value_t inner_result = ecma_op_function_call (return_obj_p, iterator, NULL, 0); + ecma_deref_object (return_obj_p); + + /* 7. */ + if (!ecma_is_value_empty (completion)) + { + if (ECMA_IS_VALUE_ERROR (inner_result)) + { + jcontext_release_exception (); + } + else + { + ecma_free_value (inner_result); + } + + jcontext_raise_exception (completion); + return ECMA_VALUE_ERROR; + } + + /* 8. */ + if (ECMA_IS_VALUE_ERROR (inner_result)) + { + ecma_free_value (completion); + return inner_result; + } + + /* 9. */ + bool is_object = ecma_is_value_object (inner_result); + ecma_free_value (inner_result); + + if (!is_object) + { + ecma_free_value (completion); + return ecma_raise_type_error (ECMA_ERR_MSG ("method 'return' is not callable.")); + } + + /* 10. */ + if (ecma_is_value_empty (completion)) + { + return ECMA_VALUE_UNDEFINED; + } + + jcontext_raise_exception (completion); + return ECMA_VALUE_ERROR; +} /* ecma_op_iterator_close */ + /** * IteratorStep operation * @@ -370,8 +514,15 @@ ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ return result; } + if (!ecma_is_value_object (result)) + { + ecma_free_value (result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object.")); + } + /* 3. */ - ecma_value_t done = ecma_op_iterator_complete (result); + ecma_object_t *obj_p = ecma_get_object_from_value (result); + ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE); /* 4. */ if (ECMA_IS_VALUE_ERROR (done)) @@ -380,10 +531,11 @@ ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ return done; } + bool is_done = ecma_op_to_boolean (done); ecma_free_value (done); /* 5. */ - if (ecma_is_value_true (done)) + if (is_done) { ecma_free_value (result); return ECMA_VALUE_FALSE; @@ -393,7 +545,65 @@ ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ return result; } /* ecma_op_iterator_step */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +/** + * Perform a command specified by the command argument + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_iterator_do (ecma_iterator_command_type_t command, /**< command to be executed */ + ecma_value_t iterator, /**< iterator object */ + ecma_value_t value, /**< the routines's value argument */ + bool *done_p) /**< it contains the logical value of the done property */ +{ + ecma_value_t result; + + if (command == ECMA_ITERATOR_NEXT) + { + result = ecma_op_iterator_next (iterator, value); + } + else if (command == ECMA_ITERATOR_RETURN) + { + result = ecma_op_iterator_return (iterator, value); + } + else + { + JERRY_ASSERT (command == ECMA_ITERATOR_THROW); + result = ecma_op_iterator_throw (iterator, value); + } + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + if (!ecma_is_value_object (result)) + { + ecma_free_value (result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object.")); + } + + ecma_object_t *obj_p = ecma_get_object_from_value (result); + ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE); + + if (ECMA_IS_VALUE_ERROR (done)) + { + ecma_free_value (result); + return done; + } + + *done_p = ecma_op_to_boolean (done); + ecma_free_value (done); + + return result; +} /* ecma_op_iterator_do */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-iterator-object.h b/jerry-core/ecma/operations/ecma-iterator-object.h index d4b81e61..70f46e19 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.h +++ b/jerry-core/ecma/operations/ecma-iterator-object.h @@ -18,7 +18,7 @@ #include "ecma-globals.h" -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) /** \addtogroup ecma ECMA * @{ @@ -27,6 +27,16 @@ * @{ */ +/** + * Generator resume execution flags. + */ +typedef enum +{ + ECMA_ITERATOR_NEXT, /**< generator should continue its execution */ + ECMA_ITERATOR_RETURN, /**< generator should perform a return operation */ + ECMA_ITERATOR_THROW, /**< generator should perform a throw operation */ +} ecma_iterator_command_type_t; + /** * Maximum value of [[%Iterator%NextIndex]] until it can be stored * in an ecma pseudo array object structure element. @@ -49,10 +59,17 @@ ecma_op_get_iterator (ecma_value_t value, ecma_value_t method); ecma_value_t ecma_op_iterator_value (ecma_value_t iter_result); +ecma_value_t +ecma_op_iterator_close (ecma_value_t iterator); + ecma_value_t ecma_op_iterator_step (ecma_value_t iterator); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +ecma_value_t +ecma_op_iterator_do (ecma_iterator_command_type_t command, ecma_value_t iterator, + ecma_value_t value, bool *done_p); + +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index a5b86555..fed814b7 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -23,6 +23,11 @@ #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) +/** + * Mask for job queue type. + */ +#define ECMA_JOB_QUEURE_TYPE_MASK ((uintptr_t) 0x07) + /** \addtogroup ecma ECMA * @{ * @@ -35,7 +40,9 @@ */ typedef struct { - ecma_value_t reaction; /**< the PromiseReaction */ + ecma_job_queue_item_t header; /**< job queue item header */ + ecma_value_t capability; /**< capability object */ + ecma_value_t handler; /**< handler function */ ecma_value_t argument; /**< argument for the reaction */ } ecma_job_promise_reaction_t; @@ -44,8 +51,9 @@ typedef struct */ typedef struct { + ecma_job_queue_item_t header; /**< job queue item header */ ecma_value_t promise; /**< promise to be resolved */ - ecma_value_t thenable; /**< thenbale object */ + ecma_value_t thenable; /**< thenable object */ ecma_value_t then; /**< 'then' function */ } ecma_job_promise_resolve_thenable_t; @@ -59,23 +67,26 @@ void ecma_job_queue_init (void) } /* ecma_job_queue_init */ /** - * Create a PromiseReactionJob. + * Get the type of the job. * - * @return pointer to the PromiseReactionJob + * @return type of the job */ -static ecma_job_promise_reaction_t * -ecma_create_promise_reaction_job (ecma_value_t reaction, /**< PromiseReaction */ - ecma_value_t argument) /**< argument for the reaction */ +static inline ecma_job_queue_item_type_t JERRY_ATTR_ALWAYS_INLINE +ecma_job_queue_get_type (ecma_job_queue_item_t *job_p) /**< the job */ { - JERRY_ASSERT (ecma_is_value_object (reaction)); + return (ecma_job_queue_item_type_t) (job_p->next_and_type & ECMA_JOB_QUEURE_TYPE_MASK); +} /* ecma_job_queue_get_type */ - ecma_job_promise_reaction_t *job_p; - job_p = (ecma_job_promise_reaction_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_reaction_t)); - job_p->reaction = ecma_copy_value (reaction); - job_p->argument = ecma_copy_value (argument); - - return job_p; -} /* ecma_create_promise_reaction_job */ +/** + * Get the next job of the job queue. + * + * @return next job + */ +static inline ecma_job_queue_item_t *JERRY_ATTR_ALWAYS_INLINE +ecma_job_queue_get_next (ecma_job_queue_item_t *job_p) /**< the job */ +{ + return (ecma_job_queue_item_t *) (job_p->next_and_type & ~ECMA_JOB_QUEURE_TYPE_MASK); +} /* ecma_job_queue_get_next */ /** * Free the heap and the member of the PromiseReactionJob. @@ -85,36 +96,13 @@ ecma_free_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< points { JERRY_ASSERT (job_p != NULL); - ecma_free_value (job_p->reaction); + ecma_free_value (job_p->capability); + ecma_free_value (job_p->handler); ecma_free_value (job_p->argument); jmem_heap_free_block (job_p, sizeof (ecma_job_promise_reaction_t)); } /* ecma_free_promise_reaction_job */ -/** - * Create a PromiseResolveThenableJob - * - * @return pointer to the PromiseResolveThenableJob - */ -static ecma_job_promise_resolve_thenable_t * -ecma_create_promise_resolve_thenable_job (ecma_value_t promise, /**< promise to be resolved */ - ecma_value_t thenable, /**< thenable object */ - ecma_value_t then) /**< 'then' function */ -{ - JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); - JERRY_ASSERT (ecma_is_value_object (thenable)); - JERRY_ASSERT (ecma_op_is_callable (then)); - - ecma_job_promise_resolve_thenable_t *job_p; - job_p = (ecma_job_promise_resolve_thenable_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_resolve_thenable_t)); - - job_p->promise = ecma_copy_value (promise); - job_p->thenable = ecma_copy_value (thenable); - job_p->then = ecma_copy_value (then); - - return job_p; -} /* ecma_create_promise_resolve_thenable_job */ - /** * Free the heap and the member of the PromiseResolveThenableJob. */ @@ -140,20 +128,15 @@ ecma_free_promise_resolve_thenable_job (ecma_job_promise_resolve_thenable_t *job * Returned value must be freed with ecma_free_value */ static ecma_value_t -ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ +ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the job to be operated */ { - ecma_job_promise_reaction_t *job_p = (ecma_job_promise_reaction_t *) obj_p; - ecma_object_t *reaction_p = ecma_get_object_from_value (job_p->reaction); - - ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *handler_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER); ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); /* 2. */ - ecma_value_t capability = ecma_op_object_get (reaction_p, capability_str_p); + ecma_value_t capability = job_p->capability; /* 3. */ - ecma_value_t handler = ecma_op_object_get (reaction_p, handler_str_p); + ecma_value_t handler = job_p->handler; JERRY_ASSERT (ecma_is_value_boolean (handler) || ecma_op_is_callable (handler)); @@ -179,7 +162,7 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ { if (ECMA_IS_VALUE_ERROR (handler_result)) { - handler_result = JERRY_CONTEXT (error_value); + handler_result = jcontext_take_exception (); } /* 7. */ @@ -208,8 +191,6 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ } ecma_free_value (handler_result); - ecma_free_value (handler); - ecma_free_value (capability); ecma_free_promise_reaction_job (job_p); return status; @@ -224,25 +205,25 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ * Returned value must be freed with ecma_free_value */ static ecma_value_t -ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be operated */ +ecma_process_promise_resolve_thenable_job (ecma_job_promise_resolve_thenable_t *job_p) /**< the job to be operated */ { - ecma_job_promise_resolve_thenable_t *job_p = (ecma_job_promise_resolve_thenable_t *) obj_p; ecma_object_t *promise_p = ecma_get_object_from_value (job_p->promise); - ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (promise_p); + ecma_promise_resolving_functions_t funcs; + ecma_promise_create_resolving_functions (promise_p, &funcs, true); ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); ecma_op_object_put (promise_p, str_resolve_p, - funcs->resolve, + funcs.resolve, false); ecma_op_object_put (promise_p, str_reject_p, - funcs->reject, + funcs.reject, false); - ecma_value_t argv[] = { funcs->resolve, funcs->reject }; + ecma_value_t argv[] = { funcs.resolve, funcs.reject }; ecma_value_t ret; ecma_value_t then_call_result = ecma_op_function_call (ecma_get_object_from_value (job_p->then), job_p->thenable, @@ -253,9 +234,9 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera if (ECMA_IS_VALUE_ERROR (then_call_result)) { - then_call_result = JERRY_CONTEXT (error_value); + then_call_result = jcontext_take_exception (); - ret = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), + ret = ecma_op_function_call (ecma_get_object_from_value (funcs.reject), ECMA_VALUE_UNDEFINED, &then_call_result, 1); @@ -263,7 +244,7 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera ecma_free_value (then_call_result); } - ecma_promise_free_resolving_functions (funcs); + ecma_promise_free_resolving_functions (&funcs); ecma_free_promise_resolve_thenable_job (job_p); return ret; @@ -273,23 +254,21 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera * Enqueue a Promise job into the jobqueue. */ static void -ecma_enqueue_job (ecma_job_handler_t handler, /**< the handler for the job */ - void *job_p) /**< the job */ +ecma_enqueue_job (ecma_job_queue_item_t *job_p) /**< the job */ { - ecma_job_queueitem_t *item_p = jmem_heap_alloc_block (sizeof (ecma_job_queueitem_t)); - item_p->job_p = job_p; - item_p->handler = handler; - item_p->next_p = NULL; + JERRY_ASSERT (job_p->next_and_type <= ECMA_JOB_QUEURE_TYPE_MASK); if (JERRY_CONTEXT (job_queue_head_p) == NULL) { - JERRY_CONTEXT (job_queue_head_p) = item_p; - JERRY_CONTEXT (job_queue_tail_p) = item_p; + JERRY_CONTEXT (job_queue_head_p) = job_p; + JERRY_CONTEXT (job_queue_tail_p) = job_p; } else { - JERRY_CONTEXT (job_queue_tail_p)->next_p = item_p; - JERRY_CONTEXT (job_queue_tail_p) = item_p; + JERRY_ASSERT ((JERRY_CONTEXT (job_queue_tail_p)->next_and_type & ~ECMA_JOB_QUEURE_TYPE_MASK) == 0); + + JERRY_CONTEXT (job_queue_tail_p)->next_and_type |= (uintptr_t) job_p; + JERRY_CONTEXT (job_queue_tail_p) = job_p; } } /* ecma_enqueue_job */ @@ -297,11 +276,18 @@ ecma_enqueue_job (ecma_job_handler_t handler, /**< the handler for the job */ * Enqueue a PromiseReactionJob into the jobqueue. */ void -ecma_enqueue_promise_reaction_job (ecma_value_t reaction, /**< PromiseReaction */ +ecma_enqueue_promise_reaction_job (ecma_value_t capability, /**< capability object */ + ecma_value_t handler, /**< handler function */ ecma_value_t argument) /**< argument for the reaction */ { - ecma_job_promise_reaction_t *job_p = ecma_create_promise_reaction_job (reaction, argument); - ecma_enqueue_job (ecma_process_promise_reaction_job, job_p); + ecma_job_promise_reaction_t *job_p; + job_p = (ecma_job_promise_reaction_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_reaction_t)); + job_p->header.next_and_type = ECMA_JOB_PROMISE_REACTION; + job_p->capability = ecma_copy_value (capability); + job_p->handler = ecma_copy_value (handler); + job_p->argument = ecma_copy_value (argument); + + ecma_enqueue_job (&job_p->header); } /* ecma_enqueue_promise_reaction_job */ /** @@ -312,10 +298,18 @@ ecma_enqueue_promise_resolve_thenable_job (ecma_value_t promise, /**< promise to ecma_value_t thenable, /**< thenable object */ ecma_value_t then) /**< 'then' function */ { - ecma_job_promise_resolve_thenable_t *job_p = ecma_create_promise_resolve_thenable_job (promise, - thenable, - then); - ecma_enqueue_job (ecma_process_promise_resolve_thenable_job, job_p); + JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); + JERRY_ASSERT (ecma_is_value_object (thenable)); + JERRY_ASSERT (ecma_op_is_callable (then)); + + ecma_job_promise_resolve_thenable_t *job_p; + job_p = (ecma_job_promise_resolve_thenable_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_resolve_thenable_t)); + job_p->header.next_and_type = ECMA_JOB_PROMISE_THENABLE; + job_p->promise = ecma_copy_value (promise); + job_p->thenable = ecma_copy_value (thenable); + job_p->then = ecma_copy_value (then); + + ecma_enqueue_job (&job_p->header); } /* ecma_enqueue_promise_resolve_thenable_job */ /** @@ -332,15 +326,26 @@ ecma_process_all_enqueued_jobs (void) while (JERRY_CONTEXT (job_queue_head_p) != NULL && !ECMA_IS_VALUE_ERROR (ret)) { - ecma_job_queueitem_t *item_p = JERRY_CONTEXT (job_queue_head_p); - JERRY_CONTEXT (job_queue_head_p) = JERRY_CONTEXT (job_queue_head_p)->next_p; + ecma_job_queue_item_t *job_p = JERRY_CONTEXT (job_queue_head_p); + JERRY_CONTEXT (job_queue_head_p) = ecma_job_queue_get_next (job_p); - void *job_p = item_p->job_p; - ecma_job_handler_t handler = item_p->handler; - jmem_heap_free_block (item_p, sizeof (ecma_job_queueitem_t)); + ecma_fast_free_value (ret); - ecma_free_value (ret); - ret = handler (job_p); + switch (ecma_job_queue_get_type (job_p)) + { + case ECMA_JOB_PROMISE_REACTION: + { + ret = ecma_process_promise_reaction_job ((ecma_job_promise_reaction_t *) job_p); + break; + } + default: + { + JERRY_ASSERT (ecma_job_queue_get_type (job_p) == ECMA_JOB_PROMISE_THENABLE); + + ret = ecma_process_promise_resolve_thenable_job ((ecma_job_promise_resolve_thenable_t *) job_p); + break; + } + } } return ret; @@ -354,12 +359,24 @@ ecma_free_all_enqueued_jobs (void) { while (JERRY_CONTEXT (job_queue_head_p) != NULL) { - ecma_job_queueitem_t *item_p = JERRY_CONTEXT (job_queue_head_p); - JERRY_CONTEXT (job_queue_head_p) = item_p->next_p; - void *job_p = item_p->job_p; - jmem_heap_free_block (item_p, sizeof (ecma_job_queueitem_t)); + ecma_job_queue_item_t *job_p = JERRY_CONTEXT (job_queue_head_p); + JERRY_CONTEXT (job_queue_head_p) = ecma_job_queue_get_next (job_p); - ecma_free_promise_reaction_job (job_p); + switch (ecma_job_queue_get_type (job_p)) + { + case ECMA_JOB_PROMISE_REACTION: + { + ecma_free_promise_reaction_job ((ecma_job_promise_reaction_t *) job_p); + break; + } + default: + { + JERRY_ASSERT (ecma_job_queue_get_type (job_p) == ECMA_JOB_PROMISE_THENABLE); + + ecma_free_promise_resolve_thenable_job ((ecma_job_promise_resolve_thenable_t *) job_p); + break; + } + } } } /* ecma_free_all_enqueued_jobs */ diff --git a/jerry-core/ecma/operations/ecma-jobqueue.h b/jerry-core/ecma/operations/ecma-jobqueue.h index 26077682..5436fa4d 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.h +++ b/jerry-core/ecma/operations/ecma-jobqueue.h @@ -26,23 +26,25 @@ */ /** - * Jerry job handler function type + * Job queue item types. */ -typedef ecma_value_t (*ecma_job_handler_t) (void *job_p); +typedef enum +{ + ECMA_JOB_PROMISE_REACTION, /**< promise reaction job */ + ECMA_JOB_PROMISE_THENABLE, /**< promise thenable job */ +} ecma_job_queue_item_type_t; /** * Description of the job queue item. */ -typedef struct ecma_job_queueitem_t +typedef struct { - struct ecma_job_queueitem_t *next_p; /**< points to next item */ - ecma_job_handler_t handler; /**< the handler for the job*/ - void *job_p; /**< points to the job */ -} ecma_job_queueitem_t; + uintptr_t next_and_type; /**< next and type members of a queue item */ +} ecma_job_queue_item_t; void ecma_job_queue_init (void); -void ecma_enqueue_promise_reaction_job (ecma_value_t reaction, ecma_value_t argument); +void ecma_enqueue_promise_reaction_job (ecma_value_t capability, ecma_value_t handler, ecma_value_t argument); void ecma_enqueue_promise_resolve_thenable_job (ecma_value_t promise, ecma_value_t thenable, ecma_value_t then); void ecma_free_all_enqueued_jobs (void); diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index 5ac38b03..c0dc6efc 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -37,25 +37,35 @@ * Initialize Global environment */ void -ecma_init_global_lex_env (void) +ecma_init_global_environment (void) { ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, glob_obj_p, ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_lex_env_cp), global_lex_env_p); -} /* ecma_init_global_lex_env */ + ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_env_cp), global_lex_env_p); +#if ENABLED (JERRY_ES2015) + ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_lex_env_p); +#endif /* ENABLED (JERRY_ES2015) */ +} /* ecma_init_global_environment */ /** * Finalize Global environment */ void -ecma_finalize_global_lex_env (void) +ecma_finalize_global_environment (void) { - ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_lex_env_cp))); - JERRY_CONTEXT (ecma_global_lex_env_cp) = JMEM_CP_NULL; -} /* ecma_finalize_global_lex_env */ +#if ENABLED (JERRY_ES2015) + if (JERRY_CONTEXT (ecma_global_scope_cp) != JERRY_CONTEXT (ecma_global_env_cp)) + { + ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp))); + } + JERRY_CONTEXT (ecma_global_scope_cp) = JMEM_CP_NULL; +#endif /* ENABLED (JERRY_ES2015) */ + ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp))); + JERRY_CONTEXT (ecma_global_env_cp) = JMEM_CP_NULL; +} /* ecma_finalize_global_environment */ /** * Get reference to Global lexical environment @@ -66,10 +76,43 @@ ecma_finalize_global_lex_env (void) ecma_object_t * ecma_get_global_environment (void) { - JERRY_ASSERT (JERRY_CONTEXT (ecma_global_lex_env_cp) != JMEM_CP_NULL); - return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_lex_env_cp)); + JERRY_ASSERT (JERRY_CONTEXT (ecma_global_env_cp) != JMEM_CP_NULL); + return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp)); } /* ecma_get_global_environment */ +#if ENABLED (JERRY_ES2015) +/** + * Create the global lexical block on top of the global environment. + */ +void +ecma_create_global_lexical_block (void) +{ + if (JERRY_CONTEXT (ecma_global_scope_cp) == JERRY_CONTEXT (ecma_global_env_cp)) + { + ecma_object_t *global_scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ()); + global_scope_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK; + ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_scope_p); + } +} /* ecma_create_global_lexical_block */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Get reference to Global lexical scope + * without increasing its reference count. + * + * @return pointer to the object's instance + */ +ecma_object_t * +ecma_get_global_scope (void) +{ +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (JERRY_CONTEXT (ecma_global_scope_cp) != JMEM_CP_NULL); + return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp)); +#else /* !ENABLED (JERRY_ES2015) */ + return ecma_get_global_environment (); +#endif /* !ENABLED (JERRY_ES2015) */ +} /* ecma_get_global_scope */ + /** * @} */ @@ -81,7 +124,7 @@ ecma_get_global_environment (void) * * @return true / false */ -bool +ecma_value_t ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { @@ -94,16 +137,14 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - return (property_p != NULL); + return ecma_make_boolean_value (property_p != NULL); } - else - { - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - return ecma_op_object_has_property (binding_obj_p, name_p); - } + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + + return ecma_op_object_has_property (binding_obj_p, name_p); } /* ecma_op_has_binding */ /** @@ -143,7 +184,7 @@ ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environme ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (!ecma_get_object_extensible (binding_obj_p)) + if (!ecma_op_ordinary_object_is_extensible (binding_obj_p)) { return ECMA_VALUE_EMPTY; } @@ -198,6 +239,12 @@ ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment { ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value); } +#if ENABLED (JERRY_ES2015) + else if (ecma_is_property_enumerable (*property_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned.")); + } +#endif /* ENABLED (JERRY_ES2015) */ else if (is_strict) { return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set.")); @@ -256,6 +303,11 @@ ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + if (!ecma_is_value_found (result)) { if (is_strict) @@ -278,8 +330,8 @@ ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ * See also: ECMA-262 v5, 10.2.1 * * @return ecma value - * Return value is simple and so need not be freed. - * However, ecma_free_value may be called for it, but it is a no-op. + * Return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the binding can be deleted */ ecma_value_t ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */ @@ -289,7 +341,6 @@ ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */ && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p); @@ -382,6 +433,144 @@ ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environ prop_value_p->value = ecma_copy_value_if_not_object (value); } /* ecma_op_create_immutable_binding */ +#if ENABLED (JERRY_ES2015) +/** + * InitializeBinding operation. + * + * See also: ECMA-262 v6, 8.1.1.1.4 + */ +void +ecma_op_initialize_binding (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_string_t *name_p, /**< argument N */ + ecma_value_t value) /**< argument V */ +{ + JERRY_ASSERT (lex_env_p != NULL + && ecma_is_lexical_environment (lex_env_p)); + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p); + JERRY_ASSERT (prop_p != NULL); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); + + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + JERRY_ASSERT (prop_value_p->value == ECMA_VALUE_UNINITIALIZED); + + prop_value_p->value = ecma_copy_value_if_not_object (value); +} /* ecma_op_initialize_binding */ + +/** + * BindThisValue operation for an empty lexical environment + * + * See also: ECMA-262 v6, 8.1.1.3.1 + */ +void +ecma_op_init_this_binding (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_value_t this_binding) /**< this binding value */ +{ + JERRY_ASSERT (lex_env_p != NULL); + JERRY_ASSERT (ecma_is_value_object (this_binding) || this_binding == ECMA_VALUE_UNINITIALIZED); + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + + ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p, + prop_name_p, + ECMA_PROPERTY_FIXED, + NULL); + prop_value_p->value = this_binding; +} /* ecma_op_init_this_binding */ + +/** + * GetThisEnvironment operation. + * + * See also: ECMA-262 v6, 8.3.2 + * + * @return property pointer for the internal [[ThisBindingValue]] property + */ +ecma_property_t * +ecma_op_get_this_property (ecma_object_t *lex_env_p) /**< lexical environment */ +{ + JERRY_ASSERT (lex_env_p != NULL); + + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + while (true) + { + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, prop_name_p); + + if (prop_p != NULL) + { + return prop_p; + } + } + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } +} /* ecma_op_get_this_property */ + +/** + * GetThisBinding operation. + * + * See also: ECMA-262 v6, 8.1.1.3.4 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ecma-object - otherwise + */ +ecma_value_t +ecma_op_get_this_binding (ecma_object_t *lex_env_p) /**< lexical environment */ +{ + JERRY_ASSERT (lex_env_p != NULL); + + ecma_property_t *prop_p = ecma_op_get_this_property (lex_env_p); + JERRY_ASSERT (prop_p != NULL); + + ecma_value_t this_value = ECMA_PROPERTY_VALUE_PTR (prop_p)->value; + + if (this_value == ECMA_VALUE_UNINITIALIZED) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " + "accessing 'this' or returning from it.")); + } + + ecma_ref_object (ecma_get_object_from_value (this_value)); + + return this_value; +} /* ecma_op_get_this_binding */ + +/** + * BindThisValue operation. + * + * See also: ECMA-262 v6, 8.1.1.3.1 + */ +void +ecma_op_bind_this_value (ecma_property_t *prop_p, /**< [[ThisBindingValue]] internal property */ + ecma_value_t this_binding) /**< this binding value */ +{ + JERRY_ASSERT (prop_p != NULL); + JERRY_ASSERT (ecma_is_value_object (this_binding)); + JERRY_ASSERT (!ecma_op_this_binding_is_initialized (prop_p)); + + ECMA_PROPERTY_VALUE_PTR (prop_p)->value = this_binding; +} /* ecma_op_bind_this_value */ + +/** + * Get the environment record [[ThisBindingStatus]] internal property. + * + * See also: ECMA-262 v6, 8.1.1.3 + * + * @return true - if the status is "initialzed" + * false - otherwise + */ +bool +ecma_op_this_binding_is_initialized (ecma_property_t *prop_p) /**< [[ThisBindingValue]] internal property */ +{ + JERRY_ASSERT (prop_p != NULL); + + return ECMA_PROPERTY_VALUE_PTR (prop_p)->value != ECMA_VALUE_UNINITIALIZED; +} /* ecma_op_this_binding_is_initialized */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index 7ff5c98b..6f260ad4 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -30,9 +30,13 @@ * @{ */ -void ecma_init_global_lex_env (void); -void ecma_finalize_global_lex_env (void); +void ecma_init_global_environment (void); +void ecma_finalize_global_environment (void); ecma_object_t *ecma_get_global_environment (void); +ecma_object_t *ecma_get_global_scope (void); +#if ENABLED (JERRY_ES2015) +void ecma_create_global_lexical_block (void); +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) void ecma_module_add_lex_env (ecma_object_t *lex_env_p); @@ -51,7 +55,7 @@ ecma_value_t ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, ecma_stri bool is_strict, ecma_value_t value); /* ECMA-262 v5, Table 17. Abstract methods of Environment Records */ -bool ecma_op_has_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p); +ecma_value_t ecma_op_has_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p); ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, bool is_deletable); ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value, bool is_strict); @@ -62,6 +66,25 @@ ecma_value_t ecma_op_implicit_this_value (ecma_object_t *lex_env_p); /* ECMA-262 v5, Table 18. Additional methods of Declarative Environment Records */ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value); +#if ENABLED (JERRY_ES2015) +void ecma_op_initialize_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value); + +void +ecma_op_init_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding); + +ecma_property_t * +ecma_op_get_this_property (ecma_object_t *lex_env_p); + +bool +ecma_op_this_binding_is_initialized (ecma_property_t *prop_p); + +ecma_value_t +ecma_op_get_this_binding (ecma_object_t *lex_env_p); + +void +ecma_op_bind_this_value (ecma_property_t *prop_p, ecma_value_t this_binding); +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects-arguments.c b/jerry-core/ecma/operations/ecma-objects-arguments.c index e6528fb7..2c3023a5 100644 --- a/jerry-core/ecma/operations/ecma-objects-arguments.c +++ b/jerry-core/ecma/operations/ecma-objects-arguments.c @@ -68,7 +68,9 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function ecma_object_t *obj_p; - if (!is_strict && arguments_number > 0 && formal_params_number > 0) + if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) + && arguments_number > 0 + && formal_params_number > 0) { size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); @@ -138,6 +140,22 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); +#if ENABLED (JERRY_ES2015) + /* ECMAScript v6, 9.4.4.6.7, 9.4.4.7.22 */ + ecma_string_t *symbol_p = ecma_op_get_global_symbol (LIT_GLOBAL_SYMBOL_ITERATOR); + + prop_value_p = ecma_create_named_data_property (obj_p, + symbol_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + ecma_deref_ecma_string (symbol_p); + prop_value_p->value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_INTRINSIC_OBJECT), + LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES); + + JERRY_ASSERT (ecma_is_value_object (prop_value_p->value)); + ecma_deref_object (ecma_get_object_from_value (prop_value_p->value)); +#endif /* ENABLED (JERRY_ES2015) */ + /* 13. */ if (!is_strict) { diff --git a/jerry-core/ecma/operations/ecma-objects-general.c b/jerry-core/ecma/operations/ecma-objects-general.c index b8b2ebc8..a0b8517b 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.c +++ b/jerry-core/ecma/operations/ecma-objects-general.c @@ -22,6 +22,7 @@ #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-objects-general.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" /** \addtogroup ecma ECMA @@ -184,6 +185,36 @@ ecma_op_general_object_delete (ecma_object_t *obj_p, /**< the object */ return ECMA_VALUE_FALSE; } /* ecma_op_general_object_delete */ +/** + * Property invocation order during [[DefaultValue]] operation with string hint + */ +static const lit_magic_string_id_t to_primitive_string_hint_method_names[2] = +{ + LIT_MAGIC_STRING_TO_STRING_UL, /**< toString operation */ + LIT_MAGIC_STRING_VALUE_OF_UL, /**< valueOf operation */ +}; + +/** + * Property invocation order during [[DefaultValue]] operation with non string hint + */ +static const lit_magic_string_id_t to_primitive_non_string_hint_method_names[2] = +{ + LIT_MAGIC_STRING_VALUE_OF_UL, /**< valueOf operation */ + LIT_MAGIC_STRING_TO_STRING_UL, /**< toString operation */ +}; + +#if ENABLED (JERRY_ES2015) +/** + * Hints for the ecma general object's toPrimitve operation + */ +static const lit_magic_string_id_t hints[3] = +{ + LIT_MAGIC_STRING_DEFAULT, /**< "default" hint */ + LIT_MAGIC_STRING_NUMBER, /**< "number" hint */ + LIT_MAGIC_STRING_STRING, /**< "string" hint */ +}; +#endif /* ENABLED (JERRY_ES2015) */ + /** * [[DefaultValue]] ecma general object's operation * @@ -201,6 +232,47 @@ ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); +#if ENABLED (JERRY_ES2015) + ecma_value_t obj_value = ecma_make_object_value (obj_p); + + ecma_value_t exotic_to_prim = ecma_op_get_method_by_symbol_id (obj_value, + LIT_GLOBAL_SYMBOL_TO_PRIMITIVE); + + if (ECMA_IS_VALUE_ERROR (exotic_to_prim)) + { + return exotic_to_prim; + } + + if (!ecma_is_value_undefined (exotic_to_prim)) + { + ecma_object_t *call_func_p = ecma_get_object_from_value (exotic_to_prim); + ecma_value_t argument = ecma_make_magic_string_value (hints[hint]); + + ecma_value_t result = ecma_op_function_call (call_func_p, + obj_value, + &argument, + 1); + + ecma_free_value (exotic_to_prim); + + if (ECMA_IS_VALUE_ERROR (result) + || !ecma_is_value_object (result)) + { + return result; + } + + ecma_free_value (result); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type in [[DefaultValue]].")); + } + + ecma_free_value (exotic_to_prim); + + if (hint == ECMA_PREFERRED_TYPE_NO) + { + hint = ECMA_PREFERRED_TYPE_NUMBER; + } +#else /* !ENABLED (JERRY_ES2015) */ if (hint == ECMA_PREFERRED_TYPE_NO) { if (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_DATE_UL)) @@ -212,22 +284,31 @@ ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ hint = ECMA_PREFERRED_TYPE_NUMBER; } } +#endif /* ENABLED (JERRY_ES2015) */ - for (uint32_t i = 1; i <= 2; i++) + return ecma_op_general_object_ordinary_value (obj_p, hint); +} /* ecma_op_general_object_default_value */ + +/** + * Ecma general object's OrdinaryToPrimitive operation + * + * See also: + * ECMA-262 v6 7.1.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_general_object_ordinary_value (ecma_object_t *obj_p, /**< the object */ + ecma_preferred_type_hint_t hint) /**< hint on preferred result type */ +{ + const lit_magic_string_id_t *function_name_ids_p = (hint == ECMA_PREFERRED_TYPE_STRING + ? to_primitive_string_hint_method_names + : to_primitive_non_string_hint_method_names); + + for (uint32_t i = 0; i < 2; i++) { - lit_magic_string_id_t function_name_id; - - if ((i == 1 && hint == ECMA_PREFERRED_TYPE_STRING) - || (i == 2 && hint == ECMA_PREFERRED_TYPE_NUMBER)) - { - function_name_id = LIT_MAGIC_STRING_TO_STRING_UL; - } - else - { - function_name_id = LIT_MAGIC_STRING_VALUE_OF_UL; - } - - ecma_value_t function_value = ecma_op_object_get_by_magic_id (obj_p, function_name_id); + ecma_value_t function_value = ecma_op_object_get_by_magic_id (obj_p, function_name_ids_p[i]); if (ECMA_IS_VALUE_ERROR (function_value)) { @@ -259,7 +340,7 @@ ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ } return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type in [[DefaultValue]].")); -} /* ecma_op_general_object_default_value */ +} /* ecma_op_general_object_ordinary_value */ /** * Special type for ecma_op_general_object_define_own_property. @@ -282,10 +363,16 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob const ecma_property_descriptor_t *property_desc_p) /**< property * descriptor */ { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_define_own_property (object_p, property_name_p, property_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (property_name_p != NULL); ecma_property_types_t property_desc_type = ECMA_PROPERTY_TYPE_GENERIC; @@ -324,7 +411,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob if (current_prop == ECMA_PROPERTY_TYPE_NOT_FOUND || current_prop == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) { /* 3. */ - if (!ecma_get_object_extensible (object_p)) + if (!ecma_op_ordinary_object_is_extensible (object_p)) { /* 2. */ return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW); @@ -339,7 +426,6 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob JERRY_ASSERT (property_desc_type == ECMA_PROPERTY_TYPE_GENERIC || property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA); - ecma_property_value_t *new_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, prop_attributes, @@ -550,6 +636,152 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob #undef ECMA_PROPERTY_TYPE_GENERIC +#if ENABLED (JERRY_ES2015) +/** + * The IsCompatiblePropertyDescriptor method for Proxy object internal methods + * + * See also: + * ECMAScript v6, 9.1.6.2 + * + * @return bool + */ +bool +ecma_op_is_compatible_property_descriptor (const ecma_property_descriptor_t *desc_p, /**< target descriptor */ + const ecma_property_descriptor_t *current_p, /**< current descriptor */ + bool is_extensible) /**< true - if target object is extensible + false - otherwise */ +{ + JERRY_ASSERT (desc_p != NULL); + + /* 2. */ + if (current_p == NULL) + { + return is_extensible; + } + + /* 3. */ + if (desc_p->flags == 0) + { + return true; + } + + /* 4. */ + if ((current_p->flags & desc_p->flags) == desc_p->flags) + { + if ((current_p->flags & ECMA_PROP_IS_VALUE_DEFINED) + && ecma_op_same_value (current_p->value, desc_p->value)) + { + return true; + } + + if ((current_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED) + && current_p->get_p == desc_p->get_p + && current_p->set_p == desc_p->set_p)) + { + return true; + } + } + + /* 5. */ + if (!(current_p->flags & ECMA_PROP_IS_CONFIGURABLE)) + { + if (desc_p->flags & ECMA_PROP_IS_CONFIGURABLE) + { + return false; + } + if ((desc_p->flags & ECMA_PROP_IS_ENUMERABLE_DEFINED) + && ((current_p->flags & ECMA_PROP_IS_ENUMERABLE) != (desc_p->flags & ECMA_PROP_IS_ENUMERABLE))) + { + return false; + } + } + + const uint32_t accessor_desc_flags = (ECMA_PROP_IS_SET_DEFINED | ECMA_PROP_IS_GET_DEFINED); + const uint32_t data_desc_flags = (ECMA_PROP_IS_VALUE_DEFINED | ECMA_PROP_IS_WRITABLE_DEFINED); + + bool desc_is_accessor = (desc_p->flags & accessor_desc_flags) != 0; + bool desc_is_data = (desc_p->flags & data_desc_flags) != 0; + bool current_is_data = (current_p->flags & data_desc_flags) != 0; + + /* 6. */ + if (!desc_is_accessor && !desc_is_data) + { + return true; + } + + /* 7. */ + if (current_is_data != desc_is_data) + { + return (current_p->flags & ECMA_PROP_IS_CONFIGURABLE) != 0; + } + + /* 8. */ + if (current_is_data) + { + if (!(current_p->flags & ECMA_PROP_IS_CONFIGURABLE)) + { + if (!(current_p->flags & ECMA_PROP_IS_WRITABLE) + && (desc_p->flags & ECMA_PROP_IS_WRITABLE)) + { + return false; + } + + if (!(current_p->flags & ECMA_PROP_IS_WRITABLE) + && (desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED) + && !ecma_op_same_value (desc_p->value, current_p->value)) + { + return false; + } + } + + return true; + } + + JERRY_ASSERT ((current_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)) != 0); + JERRY_ASSERT ((desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)) != 0); + + /* 9. */ + if (!(current_p->flags & ECMA_PROP_IS_CONFIGURABLE)) + { + if ((desc_p->flags & ECMA_PROP_IS_SET_DEFINED) + && desc_p->set_p != current_p->set_p) + { + return false; + } + + if ((desc_p->flags & ECMA_PROP_IS_GET_DEFINED) + && desc_p->get_p != current_p->get_p) + { + return false; + } + } + + return true; +} /* ecma_op_is_compatible_property_descriptor */ + +/** + * CompletePropertyDescriptor method for proxy internal method + * + * See also: + * ECMA-262 v6, 6.2.4.5 + */ +void +ecma_op_to_complete_property_descriptor (ecma_property_descriptor_t *desc_p) /**< target descriptor */ +{ + /* 4. */ + if (!(desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED))) + { + /* a. */ + desc_p->flags |= ECMA_PROP_IS_VALUE_DEFINED; + } + /* 5. */ + else + { + desc_p->flags |= (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED); + } +} /* ecma_op_to_complete_property_descriptor */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects-general.h b/jerry-core/ecma/operations/ecma-objects-general.h index 74c1f3a4..7ab79719 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.h +++ b/jerry-core/ecma/operations/ecma-objects-general.h @@ -33,9 +33,18 @@ ecma_object_t *ecma_op_create_object_object_noarg_and_set_prototype (ecma_object ecma_value_t ecma_op_general_object_delete (ecma_object_t *obj_p, ecma_string_t *property_name_p, bool is_throw); ecma_value_t ecma_op_general_object_default_value (ecma_object_t *obj_p, ecma_preferred_type_hint_t hint); +ecma_value_t ecma_op_general_object_ordinary_value (ecma_object_t *obj_p, ecma_preferred_type_hint_t hint); ecma_value_t ecma_op_general_object_define_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p, const ecma_property_descriptor_t *property_desc_p); +#if ENABLED (JERRY_ES2015) +void ecma_op_to_complete_property_descriptor (ecma_property_descriptor_t *desc_p); + +bool ecma_op_is_compatible_property_descriptor (const ecma_property_descriptor_t *desc_p, + const ecma_property_descriptor_t *current_p, + bool is_extensible); +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 00c36bcb..cbac9047 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -19,12 +19,14 @@ #include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers.h" #include "ecma-function-object.h" #include "ecma-lex-env.h" #include "ecma-string-object.h" #include "ecma-objects-arguments.h" #include "ecma-objects-general.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "jcontext.h" #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -74,8 +76,13 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ { JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ JERRY_ASSERT (property_name_p != NULL); - JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS || property_ref_p != NULL); + JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS + || options == ECMA_PROPERTY_GET_HAS_OWN_PROP + || property_ref_p != NULL); ecma_object_type_t type = ecma_get_object_type (object_p); @@ -134,10 +141,10 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ property_ref_p->virtual_value = ecma_make_uint32_value (ext_object_p->u.array.length); } - return ext_object_p->u.array.length_prop; + return ext_object_p->u.array.u.length_prop & (ECMA_PROPERTY_TYPE_VIRTUAL | ECMA_PROPERTY_FLAG_WRITABLE); } - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_array_is_fast_array (ext_object_p)) { uint32_t index = ecma_string_get_array_index (property_name_p); @@ -164,21 +171,20 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ return ECMA_PROPERTY_TYPE_NOT_FOUND; } - break; } #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { /* ES2015 9.4.5.1 */ - if (ecma_is_typedarray (ecma_make_object_value (object_p))) + if (ecma_object_is_typedarray (object_p)) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_prop_name_is_symbol (property_name_p)) { break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint32_t array_index = ecma_string_get_array_index (property_name_p); @@ -239,32 +245,25 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ { if (ecma_get_object_is_builtin (object_p)) { - property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + if (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (object_p)) + { + property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p); + } + else + { + property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + } } - else if (ecma_is_normal_or_arrow_function (type)) + else if (type == ECMA_OBJECT_TYPE_FUNCTION) { +#if !ENABLED (JERRY_ES2015) if (ecma_string_is_length (property_name_p)) { if (options & ECMA_PROPERTY_GET_VALUE) { /* Get length virtual property. */ - const ecma_compiled_code_t *bytecode_data_p; - -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) - { - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); - } - else - { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); - } -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); uint32_t len; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) @@ -283,6 +282,7 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ return ECMA_PROPERTY_TYPE_VIRTUAL; } +#endif /* !ENABLED (JERRY_ES2015) */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); @@ -302,7 +302,7 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ } } else if (type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY - && property_ref_p != NULL) + && (options & ECMA_PROPERTY_GET_HAS_OWN_PROP)) { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -393,38 +393,43 @@ ecma_op_object_get_property (ecma_object_t *object_p, /**< the object */ } /* ecma_op_object_get_property */ /** - * Checks whether an object (excluding prototypes) has a named property + * Generic [[HasProperty]] operation * - * @return true - if property is found - * false - otherwise - */ -inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_op_object_has_own_property (ecma_object_t *object_p, /**< the object */ - ecma_string_t *property_name_p) /**< property name */ -{ - ecma_property_t property = ecma_op_object_get_own_property (object_p, - property_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); - - return property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; -} /* ecma_op_object_has_own_property */ - -/** - * Checks whether an object (including prototypes) has a named property + * See also: + * ECMAScript v6, 9.1.7.1 * - * @return true - if property is found - * false - otherwise + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - whether the property is found */ -inline bool JERRY_ATTR_ALWAYS_INLINE +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_op_object_has_property (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { - ecma_property_t property = ecma_op_object_get_property (object_p, - property_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); - return property != ECMA_PROPERTY_TYPE_NOT_FOUND; + while (true) + { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_has (object_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 2 - 3. */ + if (ecma_op_ordinary_object_has_own_property (object_p, property_name_p)) + { + return ECMA_VALUE_TRUE; + } + + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + /* 7. */ + if (proto_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_FALSE; + } + + object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + } } /* ecma_op_object_has_property */ /** @@ -444,6 +449,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); ecma_object_type_t type = ecma_get_object_type (object_p); @@ -492,7 +498,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ return ecma_make_uint32_value (ext_object_p->u.array.length); } - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode)) + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p))) { uint32_t index = ecma_string_get_array_index (property_name_p); @@ -540,14 +546,14 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ } #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) /* ES2015 9.4.5.4 */ - if (ecma_is_typedarray (ecma_make_object_value (object_p))) + if (ecma_object_is_typedarray (object_p)) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_prop_name_is_symbol (property_name_p)) { break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint32_t array_index = ecma_string_get_array_index (property_name_p); @@ -593,30 +599,23 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ { if (ecma_get_object_is_builtin (object_p)) { - property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + if (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (object_p)) + { + property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p); + } + else + { + property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + } } - else if (ecma_is_normal_or_arrow_function (type)) + else if (type == ECMA_OBJECT_TYPE_FUNCTION) { +#if !ENABLED (JERRY_ES2015) if (ecma_string_is_length (property_name_p)) { /* Get length virtual property. */ - const ecma_compiled_code_t *bytecode_data_p; - -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) - { - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); - } - else - { - ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); - } -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); uint32_t len; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) @@ -632,6 +631,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ return ecma_make_uint32_value (len); } +#endif /* !ENABLED (JERRY_ES2015) */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); @@ -734,6 +734,13 @@ ecma_op_object_find (ecma_object_t *object_p, /**< the object */ while (true) { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_find (object_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p); if (ecma_is_value_found (value)) @@ -765,8 +772,7 @@ ecma_op_object_get_own_data_prop (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); ecma_value_t result = ecma_op_object_find_own (ecma_make_object_value (object_p), object_p, @@ -800,31 +806,109 @@ ecma_op_object_get_own_data_prop (ecma_object_t *object_p, /**< the object */ * @return ecma value * Returned value must be freed with ecma_free_value */ -ecma_value_t +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_op_object_get (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { - ecma_value_t base_value = ecma_make_object_value (object_p); + return ecma_op_object_get_with_receiver (object_p, property_name_p, ecma_make_object_value (object_p)); +} /* ecma_op_object_get */ +/** + * [[Get]] operation of ecma object with the specified receiver + * + * This function returns the value of a named property, or undefined + * if the property is not found in the prototype chain. If the property + * is an accessor, it calls the "get" callback function and returns + * with its result (including error throws). + * + * See also: + * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_object_get_with_receiver (ecma_object_t *object_p, /**< the object */ + ecma_string_t *property_name_p, /**< property name */ + ecma_value_t receiver) /**< receiver to invoke getter function */ +{ while (true) { - ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_get (object_p, property_name_p, receiver); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + ecma_value_t value = ecma_op_object_find_own (receiver, object_p, property_name_p); if (ecma_is_value_found (value)) { return value; } - if (object_p->u2.prototype_cp == JMEM_CP_NULL) + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + if (proto_cp == JMEM_CP_NULL) { break; } - object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); + object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); } return ECMA_VALUE_UNDEFINED; -} /* ecma_op_object_get */ +} /* ecma_op_object_get_with_receiver */ + +/** + * [[Get]] operation of ecma object specified for uint32_t property index + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_object_get_by_uint32_index (ecma_object_t *object_p, /**< the object */ + uint32_t index) /**< property index */ +{ + if (JERRY_LIKELY (index <= ECMA_DIRECT_STRING_MAX_IMM)) + { + return ecma_op_object_get (object_p, ECMA_CREATE_DIRECT_UINT32_STRING (index)); + } + + ecma_string_t *index_str_p = ecma_new_non_direct_string_from_uint32 (index); + ecma_value_t ret_value = ecma_op_object_get (object_p, index_str_p); + ecma_deref_ecma_string (index_str_p); + + return ret_value; +} /* ecma_op_object_get_by_uint32_index */ + +/** + * Perform ToLength(O.[[Get]]("length")) operation + * + * The property is converted to uint32 during the operation + * + * @return ECMA_VALUE_ERROR - if there was any error during the operation + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +ecma_op_object_get_length (ecma_object_t *object_p, /**< the object */ + uint32_t *length_p) /**< [out] length value converted to uint32 */ +{ + if (JERRY_LIKELY (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY)) + { + *length_p = ecma_array_get_length (object_p); + return ECMA_VALUE_EMPTY; + } + + ecma_value_t len_value = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_LENGTH); + ecma_value_t len_number = ecma_op_to_length (len_value, length_p); + ecma_free_value (len_value); + + JERRY_ASSERT (ECMA_IS_VALUE_ERROR (len_number) || ecma_is_value_empty (len_number)); + + return len_number; +} /* ecma_op_object_get_length */ /** * [[Get]] operation of ecma object where the property name is a magic string @@ -847,7 +931,22 @@ ecma_op_object_get_by_magic_id (ecma_object_t *object_p, /**< the object */ return ecma_op_object_get (object_p, ecma_get_magic_string (property_id)); } /* ecma_op_object_get_by_magic_id */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) +/** + * [[Get]] a well-known symbol by the given property id + * + * @return pointer to the requested well-known symbol + */ +ecma_string_t * +ecma_op_get_global_symbol (lit_magic_string_id_t property_id) /**< property symbol id */ +{ + ecma_value_t symbol_value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_INTRINSIC_OBJECT), + property_id); + JERRY_ASSERT (ecma_is_value_symbol (symbol_value)); + + return ecma_get_symbol_from_value (symbol_value); +} /* ecma_op_get_global_symbol */ + /** * [[Get]] operation of ecma object where the property is a well-known symbol * @@ -858,32 +957,27 @@ ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, /**< the object */ lit_magic_string_id_t property_id) /**< property symbol id */ { - ecma_value_t symbol_value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_SYMBOL), - property_id); - JERRY_ASSERT (ecma_is_value_symbol (symbol_value)); - - ecma_string_t *symbol_p = ecma_get_symbol_from_value (symbol_value); + ecma_string_t *symbol_p = ecma_op_get_global_symbol (property_id); ecma_value_t ret_value = ecma_op_object_get (object_p, symbol_p); - ecma_deref_ecma_string (symbol_p); return ret_value; } /* ecma_op_object_get_by_symbol_id */ /** - * GetMethod operation the property is a well-known symbol + * GetMethod operation * * See also: ECMA-262 v6, 7.3.9 * * Note: * Returned value must be freed with ecma_free_value. * - * @return iterator fucntion object - if success + * @return iterator function object - if success * raised error - otherwise */ -ecma_value_t -ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */ - lit_magic_string_id_t property_id) /**< property symbol id */ +static ecma_value_t +ecma_op_get_method (ecma_value_t value, /**< ecma value */ + ecma_string_t *prop_name_p) /** property name */ { /* 2. */ ecma_value_t obj_value = ecma_op_to_object (value); @@ -894,7 +988,9 @@ ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */ } ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); - ecma_value_t func = ecma_op_object_get_by_symbol_id (obj_p, property_id); + ecma_value_t func; + + func = ecma_op_object_get (obj_p, prop_name_p); ecma_deref_object (obj_p); /* 3. */ @@ -918,8 +1014,48 @@ ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */ /* 6. */ return func; +} /* ecma_op_get_method */ + +/** + * GetMethod operation when the property is a well-known symbol + * + * See also: ECMA-262 v6, 7.3.9 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator function object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */ + lit_magic_string_id_t symbol_id) /**< property symbol id */ +{ + ecma_string_t *prop_name_p = ecma_op_get_global_symbol (symbol_id); + ecma_value_t ret_value = ecma_op_get_method (value, prop_name_p); + ecma_deref_ecma_string (prop_name_p); + + return ret_value; } /* ecma_op_get_method_by_symbol_id */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + +/** + * GetMethod operation when the property is a magic string + * + * See also: ECMA-262 v6, 7.3.9 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator function object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_get_method_by_magic_id (ecma_value_t value, /**< ecma value */ + lit_magic_string_id_t magic_id) /**< property magic id */ +{ + return ecma_op_get_method (value, ecma_get_magic_string (magic_id)); +} /* ecma_op_get_method_by_magic_id */ +#endif /* ENABLED (JERRY_ES2015) */ /** * [[Put]] ecma general object's operation specialized for uint32_ property index @@ -989,16 +1125,146 @@ ecma_op_object_put_by_number_index (ecma_object_t *object_p, /**< the object */ * Note: even if is_throw is false, the setter can throw an * error, and this function returns with that error. */ -ecma_value_t +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_op_object_put (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ ecma_value_t value, /**< ecma value */ bool is_throw) /**< flag that controls failure handling */ +{ + return ecma_op_object_put_with_receiver (object_p, + property_name_p, + value, + ecma_make_object_value (object_p), + is_throw); +} /* ecma_op_object_put */ + +#if ENABLED (JERRY_ES2015) +/** + * [[Set]] ( P, V, Receiver) operation part for ordinary objects + * + * See also: ECMAScript v6, 9.19.9 + * + * @return ecma value + * The returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_op_object_put_apply_receiver (ecma_value_t receiver, /**< receiver */ + ecma_string_t *property_name_p, /**< property name */ + ecma_value_t value, /**< value to set */ + bool is_throw) /**< flag that controls failure handling */ +{ + /* 5.b */ + if (!ecma_is_value_object (receiver)) + { + return ecma_reject (is_throw); + } + + ecma_object_t *receiver_obj_p = ecma_get_object_from_value (receiver); + + ecma_property_descriptor_t prop_desc; + /* 5.c */ + ecma_value_t status = ecma_op_object_get_own_property_descriptor (receiver_obj_p, + property_name_p, + &prop_desc); + + /* 5.d */ + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + /* 5.e */ + if (ecma_is_value_true (status)) + { + ecma_value_t result; + + /* 5.e.i - 5.e.ii */ + if (prop_desc.flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED) + || !(prop_desc.flags & ECMA_PROP_IS_WRITABLE)) + { + result = ecma_reject (is_throw); + } + else + { + /* 5.e.iii */ + JERRY_ASSERT (prop_desc.flags & ECMA_PROP_IS_VALUE_DEFINED); + ecma_free_value (prop_desc.value); + prop_desc.value = ecma_copy_value (value); + + /* 5.e.iv */ + result = ecma_op_object_define_own_property (receiver_obj_p, property_name_p, &prop_desc); + } + + ecma_free_property_descriptor (&prop_desc); + + return result; + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (receiver_obj_p)) + { + ecma_property_descriptor_t desc; + desc.flags = ECMA_NAME_DATA_PROPERTY_DESCRIPTOR_BITS; + desc.value = value; + return ecma_proxy_object_define_own_property (receiver_obj_p, property_name_p, &desc); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (receiver_obj_p))) + { + ecma_fast_array_convert_to_normal (receiver_obj_p); + } + + /* 5.f.i */ + ecma_property_value_t *new_prop_value_p; + new_prop_value_p = ecma_create_named_data_property (receiver_obj_p, + property_name_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + JERRY_ASSERT (ecma_is_value_undefined (new_prop_value_p->value)); + new_prop_value_p->value = ecma_copy_value_if_not_object (value); + + return ECMA_VALUE_TRUE; +} /* ecma_op_object_put_apply_receiver */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * [[Put]] ecma general object's operation with given receiver + * + * See also: + * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 + * ECMA-262 v5, 8.12.5 + * ECMA-262 v6, 9.1.9 + * Also incorporates [[CanPut]] ECMA-262 v5, 8.12.4 + * + * @return ecma value + * The returned value must be freed with ecma_free_value. + * + * Returns with ECMA_VALUE_TRUE if the operation is + * successful. Otherwise it returns with an error object + * or ECMA_VALUE_FALSE. + * + * Note: even if is_throw is false, the setter can throw an + * error, and this function returns with that error. + */ +ecma_value_t +ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ + ecma_string_t *property_name_p, /**< property name */ + ecma_value_t value, /**< ecma value */ + ecma_value_t receiver, /**< receiver */ + bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_set (object_p, property_name_p, value, receiver); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + #if defined(JERRY_FUNCTION_NAME) && !defined(__APPLE__) if (ecma_is_value_object(value)) { ecma_object_t* obj = ecma_get_object_from_value(value); @@ -1027,7 +1293,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (ecma_string_is_length (property_name_p)) { - if (ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_op_array_object_set_length (object_p, value, 0); } @@ -1035,20 +1301,26 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ return ecma_reject (is_throw); } - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode)) + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p))) { - if (JERRY_UNLIKELY (!ecma_get_object_extensible (object_p))) + if (JERRY_UNLIKELY (!ecma_op_ordinary_object_is_extensible (object_p))) { return ecma_reject (is_throw); } - if (ecma_fast_array_set_property (object_p, property_name_p, value)) + uint32_t index = ecma_string_get_array_index (property_name_p); + + if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) + { + ecma_fast_array_convert_to_normal (object_p); + } + else if (ecma_fast_array_set_property (object_p, index, value)) { return ECMA_VALUE_TRUE; } } - JERRY_ASSERT (!(ext_object_p->u.array.is_fast_mode)); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); break; } @@ -1082,14 +1354,14 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) /* ES2015 9.4.5.5 */ - if (ecma_is_typedarray (ecma_make_object_value (object_p))) + if (ecma_object_is_typedarray (object_p)) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_prop_name_is_symbol (property_name_p)) { break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint32_t array_index = ecma_string_get_array_index (property_name_p); @@ -1100,7 +1372,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (ECMA_IS_VALUE_ERROR (error)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return ecma_reject (is_throw); } @@ -1165,14 +1437,30 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (ecma_get_object_is_builtin (object_p)) { - property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + if (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (object_p)) + { + property_p = ecma_builtin_routine_try_to_instantiate_property (object_p, property_name_p); + } + else + { + property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); + } } - else if (ecma_is_normal_or_arrow_function (type)) + else if (type == ECMA_OBJECT_TYPE_FUNCTION) { +#if ENABLED (JERRY_ES2015) + /* Uninitialized 'length' property is non-writable (ECMA-262 v6, 19.2.4.1) */ + if ((ecma_string_is_length (property_name_p)) + && (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (((ecma_extended_object_t *) object_p)->u.function.scope_cp))) + { + return ecma_reject (is_throw); + } +#else /* !ENABLED (JERRY_ES2015) */ if (ecma_string_is_length (property_name_p)) { return ecma_reject (is_throw); } +#endif /* ENABLED (JERRY_ES2015) */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); @@ -1195,6 +1483,13 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ { if (ecma_is_property_writable (*property_p)) { +#if ENABLED (JERRY_ES2015) + if (ecma_make_object_value (object_p) != receiver) + { + return ecma_op_object_put_apply_receiver (receiver, property_name_p, value, is_throw); + } +#endif /* ENABLED (JERRY_ES2015) */ + /* There is no need for special casing arrays here because changing the * value of an existing property never changes the length of an array. */ ecma_named_data_property_assign_value (object_p, @@ -1216,10 +1511,23 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ { bool create_new_property = true; - if (object_p->u2.prototype_cp != JMEM_CP_NULL) + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + if (proto_cp != JMEM_CP_NULL) { ecma_property_ref_t property_ref = { NULL }; - ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); + ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (proto_p)) + { + return ecma_op_object_put_with_receiver (proto_p, + property_name_p, + value, + receiver, + is_throw); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_property_t inherited_property = ecma_op_object_get_property (proto_p, property_name_p, @@ -1241,7 +1549,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } if (create_new_property - && ecma_get_object_extensible (object_p)) + && ecma_op_ordinary_object_is_extensible (object_p)) { const ecma_object_type_t obj_type = ecma_get_object_type (object_p); @@ -1268,7 +1576,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (index < UINT32_MAX && index >= ext_object_p->u.array.length) { - if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } @@ -1277,6 +1585,10 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } } +#if ENABLED (JERRY_ES2015) + return ecma_op_object_put_apply_receiver (receiver, property_name_p, value, is_throw); +#endif /* ENABLED (JERRY_ES2015) */ + ecma_property_value_t *new_prop_value_p; new_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, @@ -1295,7 +1607,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } ecma_value_t ret_value = ecma_op_function_call (ECMA_GET_NON_NULL_POINTER (ecma_object_t, setter_cp), - ecma_make_object_value (object_p), + receiver, &value, 1); @@ -1306,7 +1618,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } return ret_value; -} /* ecma_op_object_put */ +} /* ecma_op_object_put_with_receiver */ /** * [[Delete]] ecma object's operation specialized for uint32_t property index @@ -1388,6 +1700,13 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ } } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_delete_property (obj_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p)); return ecma_op_general_object_delete (obj_p, @@ -1424,7 +1743,6 @@ ecma_op_object_default_value (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_PSEUDO_ARRAY] = &ecma_op_general_object_default_value - * [ECMA_OBJECT_TYPE_ARROW_FUNCTION] = &ecma_op_general_object_default_value * }; * * return default_value[type] (obj_p, property_name_p); @@ -1454,14 +1772,18 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ const ecma_object_type_t type = ecma_get_object_type (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_define_own_property (obj_p, property_name_p, property_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + switch (type) { case ECMA_OBJECT_TYPE_GENERAL: case ECMA_OBJECT_TYPE_CLASS: case ECMA_OBJECT_TYPE_FUNCTION: -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { @@ -1495,16 +1817,16 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) } /* ES2015 9.4.5.3 */ - if (ecma_is_typedarray (ecma_make_object_value (obj_p))) + if (ecma_object_is_typedarray (obj_p)) { -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_prop_name_is_symbol (property_name_p)) { return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint32_t array_index = ecma_string_get_array_index (property_name_p); if (array_index != ECMA_STRING_NOT_ARRAY_INDEX) @@ -1554,14 +1876,25 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ * [Enumerable], [Configurable] * }. * + * The output property descriptor will always be initialized to an empty descriptor. + * * @return true - if property found * false - otherwise */ -bool +ecma_value_t ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */ { + *prop_desc_p = ecma_make_empty_property_descriptor (); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_get_own_property_descriptor (object_p, property_name_p, prop_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_property_ref_t property_ref; ecma_property_t property = ecma_op_object_get_own_property (object_p, @@ -1571,11 +1904,9 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob if (property == ECMA_PROPERTY_TYPE_NOT_FOUND || property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) { - return false; + return ECMA_VALUE_FALSE; } - *prop_desc_p = ecma_make_empty_property_descriptor (); - uint32_t flags = ecma_is_property_enumerable (property) ? ECMA_PROP_IS_ENUMERABLE : ECMA_PROP_NO_OPTS; flags |= ecma_is_property_configurable (property) ? ECMA_PROP_IS_CONFIGURABLE: ECMA_PROP_NO_OPTS; @@ -1626,7 +1957,7 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob } } - return true; + return ECMA_VALUE_TRUE; } /* ecma_op_object_get_own_property_descriptor */ /** @@ -1645,17 +1976,13 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - const ecma_object_type_t type = ecma_get_object_type (obj_p); + JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p)); - if (ecma_is_normal_or_arrow_function (type) - || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION - || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION) + if (ecma_op_object_is_callable (obj_p)) { return ecma_op_function_has_instance (obj_p, value); } - JERRY_ASSERT_OBJECT_TYPE_IS_VALID (type); - return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function object.")); } /* ecma_op_object_has_instance */ @@ -1665,27 +1992,46 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ * See also: * ECMA-262 v5, 15.2.4.6; 3 * - * @return true - if the target object is prototype of the base object - * false - if the target object is not prototype of the base object + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_TRUE - if the target object is prototype of the base object + * ECMA_VALUE_FALSE - if the target object is not prototype of the base object */ -bool +ecma_value_t ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */ ecma_object_t *target_p) /**< target object */ { do { - jmem_cpointer_t target_cp = target_p->u2.prototype_cp; + jmem_cpointer_t target_cp; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (target_p)) + { + ecma_value_t target_proto = ecma_proxy_object_get_prototype_of (target_p); + + if (ECMA_IS_VALUE_ERROR (target_proto)) + { + return target_proto; + } + target_cp = ecma_proxy_object_prototype_to_cp (target_proto); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + target_cp = ecma_op_ordinary_object_get_prototype_of (target_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ if (target_cp == JMEM_CP_NULL) { - return false; + return ECMA_VALUE_FALSE; } target_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, target_cp); if (target_p == base_p) { - return true; + return ECMA_VALUE_TRUE; } } while (true); } /* ecma_op_object_is_prototype_of */ @@ -1702,7 +2048,8 @@ ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */ * property list, and the list is not reordered (in other words, properties are stored in order that is reversed * to the properties' addition order). * - * @return collection of strings - property names + * @return NULL - if the Proxy.[[OwnPropertyKeys]] operation raises error + * collection of property names - otherwise */ ecma_collection_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ @@ -1711,27 +2058,58 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - - if (ext_object_p->u.array.is_fast_mode) + /* Integrated a part of ECMA 262 v6 7.3.21 EnumerableOwnNames operation. */ + ecma_collection_t *proxy_keys = ecma_proxy_object_own_property_keys (obj_p); + if (JERRY_UNLIKELY (proxy_keys == NULL)) { - return ecma_fast_array_get_property_names (obj_p, opts); + return proxy_keys; } + ecma_collection_t *return_keys = ecma_new_collection (); + + /* Move valid elements to the output collection */ + for (uint32_t i = 0; i < proxy_keys->item_count; i++) + { + ecma_value_t entry = proxy_keys->buffer_p[i]; + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (entry); + bool prop_is_symbol = ecma_prop_name_is_symbol (prop_name_p); + + if (prop_is_symbol && ((opts & (ECMA_LIST_SYMBOLS | ECMA_LIST_SYMBOLS_ONLY)) != 0)) + { + ecma_collection_push_back (return_keys, entry); + } + else if (!prop_is_symbol && (opts & ECMA_LIST_SYMBOLS_ONLY) == 0) + { + ecma_collection_push_back (return_keys, entry); + } + else + { + ecma_free_value (entry); + } + } + + ecma_collection_destroy (proxy_keys); + return return_keys; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_op_object_is_fast_array (obj_p)) + { + return ecma_fast_array_get_property_names (obj_p, opts); } ecma_collection_t *ret_p = ecma_new_collection (); ecma_collection_t *skipped_non_enumerable_p = ecma_new_collection (); - const ecma_object_type_t type = ecma_get_object_type (obj_p); - const bool obj_is_builtin = ecma_get_object_is_builtin (obj_p); const bool is_enumerable_only = (opts & ECMA_LIST_ENUMERABLE) != 0; const bool is_array_indices_only = (opts & ECMA_LIST_ARRAY_INDICES) != 0; const bool is_with_prototype_chain = (opts & ECMA_LIST_PROTOTYPE) != 0; -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - const bool is_symbols_only = (opts & ECMA_LIST_SYMBOLS) != 0; -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#if ENABLED (JERRY_ES2015) + const bool is_symbols = (opts & ECMA_LIST_SYMBOLS) != 0; + const bool is_symbols_only = (opts & ECMA_LIST_SYMBOLS_ONLY) != 0; +#endif /* ENABLED (JERRY_ES2015) */ const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE; const size_t names_hashes_bitmap_size = ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size; @@ -1739,26 +2117,38 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ memset (names_hashes_bitmap, 0, names_hashes_bitmap_size * sizeof (names_hashes_bitmap[0])); - ecma_object_t *prototype_chain_iter_p = obj_p; - while (true) { + const ecma_object_type_t type = ecma_get_object_type (obj_p); + const bool obj_is_builtin = ecma_get_object_is_builtin (obj_p); ecma_length_t string_named_properties_count = 0; ecma_length_t array_index_named_properties_count = 0; - +#if ENABLED (JERRY_ES2015) + ecma_length_t symbol_named_properties_count = 0; +#endif /* ENABLED (JERRY_ES2015) */ ecma_collection_t *prop_names_p = ecma_new_collection (); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (JERRY_LIKELY (!is_symbols_only)) { -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if (obj_is_builtin) { - ecma_builtin_list_lazy_property_names (obj_p, - is_enumerable_only, - prop_names_p, - skipped_non_enumerable_p); + if (type == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (obj_p)) + { + ecma_builtin_routine_list_lazy_property_names (obj_p, + opts, + prop_names_p, + skipped_non_enumerable_p); + } + else + { + ecma_builtin_list_lazy_property_names (obj_p, + opts, + prop_names_p, + skipped_non_enumerable_p); + } } else { @@ -1767,7 +2157,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) - if (ecma_is_typedarray (ecma_make_object_value (obj_p))) + if (ecma_object_is_typedarray (obj_p)) { ecma_op_typedarray_list_lazy_property_names (obj_p, prop_names_p); } @@ -1775,28 +2165,36 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ break; } case ECMA_OBJECT_TYPE_FUNCTION: - #if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: - #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ { - ecma_op_function_list_lazy_property_names (obj_p, - is_enumerable_only, - prop_names_p, - skipped_non_enumerable_p); + if (!is_array_indices_only) + { + ecma_op_function_list_lazy_property_names (obj_p, + opts, + prop_names_p, + skipped_non_enumerable_p); + } break; } case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: { - ecma_op_external_function_list_lazy_property_names (is_enumerable_only, - prop_names_p, - skipped_non_enumerable_p); + if (!is_array_indices_only) + { + ecma_op_external_function_list_lazy_property_names (obj_p, + opts, + prop_names_p, + skipped_non_enumerable_p); + } break; } case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { - ecma_op_bound_function_list_lazy_property_names (is_enumerable_only, - prop_names_p, - skipped_non_enumerable_p); + if (!is_array_indices_only) + { + ecma_op_bound_function_list_lazy_property_names (obj_p, + opts, + prop_names_p, + skipped_non_enumerable_p); + } break; } case ECMA_OBJECT_TYPE_CLASS: @@ -1806,7 +2204,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_STRING_UL) { ecma_op_string_list_lazy_property_names (obj_p, - is_enumerable_only, + opts, prop_names_p, skipped_non_enumerable_p); } @@ -1816,7 +2214,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ case ECMA_OBJECT_TYPE_ARRAY: { ecma_op_array_list_lazy_property_names (obj_p, - is_enumerable_only, + opts, prop_names_p, skipped_non_enumerable_p); break; @@ -1829,11 +2227,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_value_t *buffer_p = prop_names_p->buffer_p; + uint32_t lazy_prop_name_count = prop_names_p->item_count; const size_t own_names_hashes_bitmap_size = ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size; JERRY_VLA (uint32_t, own_names_hashes_bitmap, own_names_hashes_bitmap_size); @@ -1843,10 +2242,25 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ { ecma_string_t *name_p = ecma_get_string_from_value (buffer_p[i]); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) + if (ecma_string_get_array_index (name_p) != ECMA_STRING_NOT_ARRAY_INDEX) + { + array_index_named_properties_count++; + } +#if ENABLED (JERRY_ES2015) + else if (ecma_prop_name_is_symbol (name_p)) + { + symbol_named_properties_count++; + } +#endif /* ENABLED (JERRY_ES2015) */ + else + { + string_named_properties_count++; + } + +#if ENABLED (JERRY_ES2015) /* Symbols are never lazy listed */ JERRY_ASSERT (!ecma_prop_name_is_symbol (name_p)); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ uint8_t hash = (uint8_t) ecma_string_hash (name_p); uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); @@ -1858,15 +2272,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } - jmem_cpointer_t prop_iter_cp = prototype_chain_iter_p->u1.property_list_cp; + jmem_cpointer_t prop_iter_cp = obj_p->u1.property_list_cp; - if (ecma_get_object_type (prototype_chain_iter_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) prototype_chain_iter_p)->u.array.is_fast_mode - && prop_iter_cp != JMEM_CP_NULL) + if (ecma_op_object_is_fast_array (obj_p) && prop_iter_cp != JMEM_CP_NULL) { - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) prototype_chain_iter_p; + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; uint32_t length = ext_obj_p->u.array.length; + array_index_named_properties_count = length - ecma_fast_array_get_hole_count (obj_p); ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, prop_iter_cp); @@ -1950,18 +2363,19 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (!(is_enumerable_only && !ecma_is_property_enumerable (*property_p))) { - #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - /* If is_symbols_only is false and prop_name is symbol - we should skip the current property e.g. for-in. - - Also if is_symbols_only is true and prop_name is not symbol - we should skip the current property e.g. Object.getOwnPropertySymbols. */ - if (JERRY_UNLIKELY (is_symbols_only != ecma_prop_name_is_symbol (name_p))) + #if ENABLED (JERRY_ES2015) + /* We skip the current property in the following cases: + 1. We don't want to list symbols (is_symbols and is_symbols_only are false) + and the current property is a symbol. + 2. We only want to list symbols (is_symbols_only is true) and the current + property is NOT a symbol. */ + bool is_symbol = ecma_prop_name_is_symbol (name_p); + if ((!(is_symbols || is_symbols_only) && is_symbol) || (is_symbols_only && !is_symbol)) { ecma_deref_ecma_string (name_p); continue; } - #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + #endif /* ENABLED (JERRY_ES2015) */ uint8_t hash = (uint8_t) ecma_string_hash (name_p); uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); @@ -1987,6 +2401,32 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (is_add) { + if (ecma_string_get_array_index (name_p) != ECMA_STRING_NOT_ARRAY_INDEX) + { + /* The name is a valid array index. */ + array_index_named_properties_count++; + } + else if (!is_array_indices_only) + { + #if ENABLED (JERRY_ES2015) + if (ecma_prop_name_is_symbol (name_p)) + { + symbol_named_properties_count++; + } + else + { + #endif /* ENABLED (JERRY_ES2015) */ + string_named_properties_count++; + #if ENABLED (JERRY_ES2015) + } + #endif /* ENABLED (JERRY_ES2015) */ + } + else + { + ecma_deref_ecma_string (name_p); + continue; + } + own_names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); ecma_collection_push_back (prop_names_p, ecma_make_prop_name_value (name_p)); @@ -2009,39 +2449,33 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } - buffer_p = prop_names_p->buffer_p; + ecma_length_t all_properties_count = array_index_named_properties_count + string_named_properties_count; - for (uint32_t i = 0; i < prop_names_p->item_count; i++) - { - ecma_string_t *name_p = ecma_get_prop_name_from_value (buffer_p[i]); +#if ENABLED (JERRY_ES2015) + all_properties_count += symbol_named_properties_count; +#endif /* ENABLED (JERRY_ES2015) */ - uint32_t index = ecma_string_get_array_index (name_p); + /* Second pass: collecting property names into an array. */ + JMEM_DEFINE_LOCAL_ARRAY (names_p, all_properties_count, ecma_string_t *); - if (index != ECMA_STRING_NOT_ARRAY_INDEX) - { - /* The name is a valid array index. */ - array_index_named_properties_count++; - } - else if (!is_array_indices_only) - { - string_named_properties_count++; - } - } + ecma_string_t **string_names_p = names_p + array_index_named_properties_count; +#if ENABLED (JERRY_ES2015) + ecma_string_t **symbol_names_p = string_names_p + string_named_properties_count; +#endif /* ENABLED (JERRY_ES2015) */ - /* Second pass: collecting property names into arrays. */ - JMEM_DEFINE_LOCAL_ARRAY (names_p, - array_index_named_properties_count + string_named_properties_count, - ecma_string_t *); - JMEM_DEFINE_LOCAL_ARRAY (array_index_names_p, array_index_named_properties_count, uint32_t); - - uint32_t name_pos = array_index_named_properties_count + string_named_properties_count; uint32_t array_index_name_pos = 0; + uint32_t string_name_pos = string_named_properties_count; + uint32_t lazy_string_name_pos = 0; +#if ENABLED (JERRY_ES2015) + uint32_t symbol_name_pos = symbol_named_properties_count; +#endif /* ENABLED (JERRY_ES2015) */ buffer_p = prop_names_p->buffer_p; for (uint32_t i = 0; i < prop_names_p->item_count; i++) { ecma_string_t *name_p = ecma_get_prop_name_from_value (buffer_p[i]); + ecma_ref_ecma_string (name_p); uint32_t index = ecma_string_get_array_index (name_p); @@ -2051,64 +2485,70 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ uint32_t insertion_pos = 0; while (insertion_pos < array_index_name_pos - && index < array_index_names_p[insertion_pos]) + && index > ecma_string_get_array_index (names_p[insertion_pos])) { insertion_pos++; } if (insertion_pos == array_index_name_pos) { - array_index_names_p[array_index_name_pos++] = index; + names_p[array_index_name_pos++] = name_p; } else { JERRY_ASSERT (insertion_pos < array_index_name_pos); - JERRY_ASSERT (index >= array_index_names_p[insertion_pos]); + JERRY_ASSERT (index <= ecma_string_get_array_index (names_p[insertion_pos])); uint32_t move_pos = array_index_name_pos++; while (move_pos > insertion_pos) { - array_index_names_p[move_pos] = array_index_names_p[move_pos - 1u]; + names_p[move_pos] = names_p[move_pos - 1u]; move_pos--; } - array_index_names_p[insertion_pos] = index; + names_p[insertion_pos] = name_p; } } - else if (!is_array_indices_only) +#if ENABLED (JERRY_ES2015) + else if (ecma_prop_name_is_symbol (name_p)) { - /* - * Filling from end to begin, as list of object's properties is sorted - * in order that is reverse to properties creation order - */ + // Put in the symbols in reverse order. + JERRY_ASSERT (symbol_name_pos > 0); + JERRY_ASSERT (symbol_name_pos <= symbol_named_properties_count); - JERRY_ASSERT (name_pos > 0 - && name_pos <= array_index_named_properties_count + string_named_properties_count); - ecma_ref_ecma_string (name_p); - names_p[--name_pos] = name_p; + symbol_names_p[--symbol_name_pos] = name_p; + } +#endif /* ENABLED (JERRY_ES2015) */ + else + { + // Put in the strings in reverse order. + JERRY_ASSERT (string_name_pos > 0); + JERRY_ASSERT (string_name_pos <= string_named_properties_count); + + if (i < lazy_prop_name_count) + { + string_names_p[lazy_string_name_pos++] = name_p; + } + else + { + string_names_p[--string_name_pos] = name_p; + } } } - for (uint32_t i = 0; i < array_index_named_properties_count; i++) - { - JERRY_ASSERT (name_pos > 0 - && name_pos <= array_index_named_properties_count + string_named_properties_count); - names_p[--name_pos] = ecma_new_ecma_string_from_uint32 (array_index_names_p[i]); - } - - JERRY_ASSERT (name_pos == 0); - - JMEM_FINALIZE_LOCAL_ARRAY (array_index_names_p); + JERRY_ASSERT (array_index_name_pos == array_index_named_properties_count); + JERRY_ASSERT (string_name_pos - lazy_string_name_pos == 0); +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (symbol_name_pos == 0); +#endif /* ENABLED (JERRY_ES2015) */ ecma_collection_free (prop_names_p); /* Third pass: * embedding own property names of current object of prototype chain to aggregate property names collection */ - for (uint32_t i = 0; - i < array_index_named_properties_count + string_named_properties_count; - i++) + for (uint32_t i = 0; i < all_properties_count; i++) { bool is_append = true; @@ -2171,14 +2611,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JMEM_FINALIZE_LOCAL_ARRAY (names_p); - - if (!is_with_prototype_chain || prototype_chain_iter_p->u2.prototype_cp == JMEM_CP_NULL) + if (!is_with_prototype_chain || obj_p->u2.prototype_cp == JMEM_CP_NULL) { break; } - prototype_chain_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, - prototype_chain_iter_p->u2.prototype_cp); + obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_p->u2.prototype_cp); } ecma_collection_free (skipped_non_enumerable_p); @@ -2215,26 +2653,44 @@ ecma_object_check_class_name_is_object (ecma_object_t *obj_p) /**< object */ || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE) #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ARRAY_PROTOTYPE_UNSCOPABLES) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ARRAY_ITERATOR_PROTOTYPE) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_ERROR_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_STRING_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_NUMBER_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_DATE_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_REGEXP_PROTOTYPE) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE) +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_MAP_PROTOTYPE) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_MAP_ITERATOR_PROTOTYPE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #if ENABLED (JERRY_ES2015_BUILTIN_SET) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SET_PROTOTYPE) -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SET_ITERATOR_PROTOTYPE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) - || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE) -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ @@ -2264,6 +2720,7 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ case ECMA_OBJECT_TYPE_CLASS: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; + return (lit_magic_string_id_t) ext_object_p->u.class_prop.class_id; } case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: @@ -2279,7 +2736,7 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ return (lit_magic_string_id_t) ext_obj_p->u.pseudo_array.u1.class_id; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) case ECMA_PSEUDO_ARRAY_ITERATOR: { return LIT_MAGIC_STRING_ARRAY_ITERATOR_UL; @@ -2292,13 +2749,13 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ { return LIT_MAGIC_STRING_MAP_ITERATOR_UL; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015) case ECMA_PSEUDO_STRING_ITERATOR: { return LIT_MAGIC_STRING_STRING_ITERATOR_UL; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (ext_obj_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); @@ -2310,9 +2767,6 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ break; } case ECMA_OBJECT_TYPE_FUNCTION: -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { @@ -2320,7 +2774,7 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ } default: { - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL); + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL || type == ECMA_OBJECT_TYPE_PROXY); if (ecma_get_object_is_builtin (obj_p)) { @@ -2334,12 +2788,25 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ return LIT_MAGIC_STRING_MATH_UL; } #endif /* ENABLED (JERRY_BUILTIN_MATH) */ +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) + case ECMA_BUILTIN_ID_REFLECT: + { + return LIT_MAGIC_STRING_REFLECT_UL; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ +#if ENABLED (JERRY_ES2015) + case ECMA_BUILTIN_ID_GENERATOR: + { + return LIT_MAGIC_STRING_GENERATOR_UL; + } +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_JSON) case ECMA_BUILTIN_ID_JSON: { return LIT_MAGIC_STRING_JSON_U; } #endif /* ENABLED (JERRY_BUILTIN_JSON) */ +#if !ENABLED (JERRY_ES2015) #if ENABLED (JERRY_BUILTIN_ERRORS) case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE: case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE: @@ -2352,6 +2819,13 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ { return LIT_MAGIC_STRING_ERROR_UL; } +#endif /* !ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_BUILTIN_ID_PROXY: + { + return LIT_MAGIC_STRING_FUNCTION_UL; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ default: { JERRY_ASSERT (ecma_object_check_class_name_is_object (obj_p)); @@ -2391,6 +2865,363 @@ ecma_object_class_is (ecma_object_t *object_p, /**< object */ return false; } /* ecma_object_class_is */ +/** + * Checks if the given argument has [[RegExpMatcher]] internal slot + * + * @return true - if the given argument is a regexp + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_object_is_regexp_object (ecma_value_t arg) /**< argument */ +{ + return (ecma_is_value_object (arg) + && ecma_object_class_is (ecma_get_object_from_value (arg), LIT_MAGIC_STRING_REGEXP_UL)); +} /* ecma_object_is_regexp_object */ + +#if ENABLED (JERRY_ES2015) +/** + * Object's IsConcatSpreadable operation, used for Array.prototype.concat + * It checks the argument's [Symbol.isConcatSpreadable] property value + * + * See also: + * ECMA-262 v6, 22.1.3.1.1; + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_TRUE - if the argument is concatSpreadable + * ECMA_VALUE_FALSE - otherwise + */ +ecma_value_t +ecma_op_is_concat_spreadable (ecma_value_t arg) /**< argument */ +{ + if (!ecma_is_value_object (arg)) + { + return ECMA_VALUE_FALSE; + } + + ecma_value_t spreadable = ecma_op_object_get_by_symbol_id (ecma_get_object_from_value (arg), + LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE); + + if (ECMA_IS_VALUE_ERROR (spreadable)) + { + return spreadable; + } + + if (!ecma_is_value_undefined (spreadable)) + { + const bool to_bool = ecma_op_to_boolean (spreadable); + ecma_free_value (spreadable); + return ecma_make_boolean_value (to_bool); + } + + return ecma_is_value_array (arg); +} /* ecma_op_is_concat_spreadable */ + +/** + * IsRegExp operation + * + * See also: + * ECMA-262 v6, 22.1.3.1.1; + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_TRUE - if the argument is regexp + * ECMA_VALUE_FALSE - otherwise + */ +ecma_value_t +ecma_op_is_regexp (ecma_value_t arg) /**< argument */ +{ + if (!ecma_is_value_object (arg)) + { + return ECMA_VALUE_FALSE; + } + + ecma_value_t is_regexp = ecma_op_object_get_by_symbol_id (ecma_get_object_from_value (arg), + LIT_GLOBAL_SYMBOL_MATCH); + + if (ECMA_IS_VALUE_ERROR (is_regexp)) + { + return is_regexp; + } + + if (!ecma_is_value_undefined (is_regexp)) + { + const bool to_bool = ecma_op_to_boolean (is_regexp); + ecma_free_value (is_regexp); + return ecma_make_boolean_value (to_bool); + } + + return ecma_make_boolean_value (ecma_object_is_regexp_object (arg)); +} /* ecma_op_is_regexp */ + +/** + * SpeciesConstructor operation + * See also: + * ECMA-262 v6, 7.3.20; + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */ + ecma_builtin_id_t default_constructor_id) /**< Builtin ID of default constructor */ +{ + ecma_object_t *default_constructor_p = ecma_builtin_get (default_constructor_id); + ecma_value_t constructor = ecma_op_object_get_by_magic_id (this_value, LIT_MAGIC_STRING_CONSTRUCTOR); + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_value_undefined (constructor)) + { + ecma_ref_object (default_constructor_p); + return ecma_make_object_value (default_constructor_p); + } + + if (!ecma_is_value_object (constructor)) + { + ecma_free_value (constructor); + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor must be an Object")); + } + + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + ecma_value_t species = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_GLOBAL_SYMBOL_SPECIES); + ecma_deref_object (ctor_object_p); + + if (ECMA_IS_VALUE_ERROR (species)) + { + return species; + } + + if (ecma_is_value_undefined (species) || ecma_is_value_null (species)) + { + ecma_ref_object (default_constructor_p); + return ecma_make_object_value (default_constructor_p); + } + + if (!ecma_is_constructor (species)) + { + ecma_free_value (species); + return ecma_raise_type_error (ECMA_ERR_MSG ("Species must be a Constructor")); + } + + return species; +} /* ecma_op_species_constructor */ + +/** + * 7.3.18 Abstract operation Invoke when property name is a magic string + * + * @return ecma_value result of the invoked function or raised error + * note: returned value must be freed with ecma_free_value + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_invoke_by_symbol_id (ecma_value_t object, /**< Object value */ + lit_magic_string_id_t symbol_id, /**< Symbol ID */ + ecma_value_t *args_p, /**< Argument list */ + ecma_length_t args_len) /**< Argument list length */ +{ + ecma_string_t *symbol_p = ecma_op_get_global_symbol (symbol_id); + ecma_value_t ret_value = ecma_op_invoke (object, symbol_p, args_p, args_len); + ecma_deref_ecma_string (symbol_p); + + return ret_value; +} /* ecma_op_invoke_by_symbol_id */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * 7.3.18 Abstract operation Invoke when property name is a magic string + * + * @return ecma_value result of the invoked function or raised error + * note: returned value must be freed with ecma_free_value + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_invoke_by_magic_id (ecma_value_t object, /**< Object value */ + lit_magic_string_id_t magic_string_id, /**< Magic string ID */ + ecma_value_t *args_p, /**< Argument list */ + ecma_length_t args_len) /**< Argument list length */ +{ + return ecma_op_invoke (object, ecma_get_magic_string (magic_string_id), args_p, args_len); +} /* ecma_op_invoke_by_magic_id */ + +/** + * 7.3.18 Abstract operation Invoke + * + * @return ecma_value result of the invoked function or raised error + * note: returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_invoke (ecma_value_t object, /**< Object value */ + ecma_string_t *property_name_p, /**< Property name */ + ecma_value_t *args_p, /**< Argument list */ + ecma_length_t args_len) /**< Argument list length */ +{ + /* 3. */ + ecma_value_t object_value = ecma_op_to_object (object); + if (ECMA_IS_VALUE_ERROR (object_value)) + { + return object_value; + } + + ecma_object_t *object_p = ecma_get_object_from_value (object_value); + ecma_value_t func = ecma_op_object_get (object_p, property_name_p); + + if (ECMA_IS_VALUE_ERROR (func)) + { + ecma_deref_object (object_p); + return func; + } + + /* 4. */ + if (!ecma_op_is_callable (func)) + { + ecma_free_value (func); + ecma_deref_object (object_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not callable")); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (func); + ecma_value_t call_result = ecma_op_function_call (func_obj_p, object, args_p, args_len); + ecma_deref_object (object_p); + ecma_deref_object (func_obj_p); + + return call_result; +} /* ecma_op_invoke */ + +/** + * Ordinary object [[GetPrototypeOf]] operation + * + * See also: + * ECMAScript v6, 9.1.1 + * + * @return the value of the [[Prototype]] internal slot of the given object. + */ +inline jmem_cpointer_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_get_prototype_of (ecma_object_t *obj_p) /**< object */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); + + return obj_p->u2.prototype_cp; +} /* ecma_op_ordinary_object_get_prototype_of */ + +/** + * Ordinary object [[SetPrototypeOf]] operation + * + * See also: + * ECMAScript v6, 9.1.2 + * + * @return ECMA_VALUE_FALSE - if the operation fails + * ECMA_VALUE_TRUE - otherwise + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_set_prototype_of (ecma_object_t *obj_p, /**< base object */ + ecma_value_t proto) /**< prototype object */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); + + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto)); + + /* 3. */ + ecma_object_t *current_proto_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (obj_p)); + ecma_object_t *new_proto_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto); + + /* 4. */ + if (new_proto_p == current_proto_p) + { + return ECMA_VALUE_TRUE; + } + + /* 2 - 5. */ + if (!ecma_op_ordinary_object_is_extensible (obj_p)) + { + return ECMA_VALUE_FALSE; + } + + /* 6. */ + ecma_object_t *iter_p = new_proto_p; + + /* 7 - 8. */ + while (true) + { + /* 8.a */ + if (iter_p == NULL) + { + break; + } + + /* 8.b */ + if (obj_p == iter_p) + { + return ECMA_VALUE_FALSE; + } + + /* 8.c.i */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (iter_p)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 8.c.ii */ + iter_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (iter_p)); + } + + /* 9. */ + ECMA_SET_POINTER (obj_p->u2.prototype_cp, new_proto_p); + + /* 10. */ + return ECMA_VALUE_TRUE; +} /* ecma_op_ordinary_object_set_prototype_of */ + +/** + * [[IsExtensible]] operation for Ordinary object. + * + * See also: + * ECMAScript v6, 9.1.2 + * + * @return true - if object is extensible + * false - otherwise + */ +inline bool JERRY_ATTR_PURE +ecma_op_ordinary_object_is_extensible (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + + return (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0; +} /* ecma_op_ordinary_object_is_extensible */ + +/** + * Set value of [[Extensible]] object's internal property. + */ +void JERRY_ATTR_NOINLINE +ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_EXTENSIBLE); +} /* ecma_op_ordinary_object_prevent_extensions */ + +/** + * Checks whether an object (excluding prototypes) has a named property + * + * @return true - if property is found + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, /**< the object */ + ecma_string_t *property_name_p) /**< property name */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + + ecma_property_t property = ecma_op_object_get_own_property (object_p, + property_name_p, + NULL, + ECMA_PROPERTY_GET_HAS_OWN_PROP); + + return property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; +} /* ecma_op_ordinary_object_has_own_property */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index c416ed2b..5f287bf0 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -16,6 +16,7 @@ #ifndef ECMA_OBJECTS_H #define ECMA_OBJECTS_H +#include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-globals.h" @@ -28,21 +29,31 @@ ecma_property_t ecma_op_object_get_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_property_ref_t *property_ref_p, uint32_t options); -bool ecma_op_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); -bool ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +bool ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +ecma_value_t ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find_own (ecma_value_t base_value, ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find_by_uint32_index (ecma_object_t *object_p, uint32_t index); ecma_value_t ecma_op_object_find_by_number_index (ecma_object_t *object_p, ecma_number_t index); ecma_value_t ecma_op_object_get_own_data_prop (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_get (ecma_object_t *object_p, ecma_string_t *property_name_p); +ecma_value_t ecma_op_object_get_with_receiver (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_value_t receiver); +ecma_value_t ecma_op_object_get_length (ecma_object_t *object_p, uint32_t *length_p); +ecma_value_t ecma_op_object_get_by_uint32_index (ecma_object_t *object_p, uint32_t index); ecma_value_t ecma_op_object_get_by_magic_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) +ecma_string_t *ecma_op_get_global_symbol (lit_magic_string_id_t property_id); ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); -ecma_value_t ecma_op_get_method_by_symbol_id (ecma_value_t value, lit_magic_string_id_t property_id); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +ecma_value_t ecma_op_get_method_by_symbol_id (ecma_value_t value, lit_magic_string_id_t symbol_id); +ecma_value_t ecma_op_get_method_by_magic_id (ecma_value_t value, lit_magic_string_id_t magic_id); +#endif /* ENABLED (JERRY_ES2015) */ +ecma_value_t ecma_op_object_put_with_receiver (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_value_t value, ecma_value_t receiver, bool is_throw); ecma_value_t ecma_op_object_put (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value, bool is_throw); +ecma_value_t ecma_op_object_put_with_receiver (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_value_t value, ecma_value_t receiver, bool is_throw); ecma_value_t ecma_op_object_put_by_uint32_index (ecma_object_t *object_p, uint32_t index, ecma_value_t value, bool is_throw); ecma_value_t ecma_op_object_put_by_number_index (ecma_object_t *object_p, ecma_number_t index, @@ -53,14 +64,31 @@ ecma_value_t ecma_op_object_delete_by_number_index (ecma_object_t *obj_p, ecma_n ecma_value_t ecma_op_object_default_value (ecma_object_t *obj_p, ecma_preferred_type_hint_t hint); ecma_value_t ecma_op_object_define_own_property (ecma_object_t *obj_p, ecma_string_t *property_name_p, const ecma_property_descriptor_t *property_desc_p); -bool ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, ecma_string_t *property_name_p, - ecma_property_descriptor_t *prop_desc_p); +ecma_value_t ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_property_descriptor_t *prop_desc_p); ecma_value_t ecma_op_object_has_instance (ecma_object_t *obj_p, ecma_value_t value); -bool ecma_op_object_is_prototype_of (ecma_object_t *base_p, ecma_object_t *target_p); +ecma_value_t ecma_op_object_is_prototype_of (ecma_object_t *base_p, ecma_object_t *target_p); ecma_collection_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, uint32_t opts); lit_magic_string_id_t ecma_object_get_class_name (ecma_object_t *obj_p); bool ecma_object_class_is (ecma_object_t *object_p, uint32_t class_id); +bool ecma_object_is_regexp_object (ecma_value_t arg); +#if ENABLED (JERRY_ES2015) +ecma_value_t ecma_op_is_concat_spreadable (ecma_value_t arg); +ecma_value_t ecma_op_is_regexp (ecma_value_t arg); +ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builtin_id_t default_constructor_id); +ecma_value_t ecma_op_invoke_by_symbol_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, + ecma_value_t *args_p, ecma_length_t args_len); +#endif /* ENABLED (JERRY_ES2015) */ +ecma_value_t ecma_op_invoke (ecma_value_t object, ecma_string_t *property_name_p, ecma_value_t *args_p, + ecma_length_t args_len); +ecma_value_t ecma_op_invoke_by_magic_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, + ecma_value_t *args_p, ecma_length_t args_len); + +jmem_cpointer_t ecma_op_ordinary_object_get_prototype_of (ecma_object_t *obj_p); +ecma_value_t ecma_op_ordinary_object_set_prototype_of (ecma_object_t *base_p, ecma_value_t proto); +bool JERRY_ATTR_PURE ecma_op_ordinary_object_is_extensible (ecma_object_t *object_p); +void ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p); /** * @} diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index d60a9487..dbcd0242 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -53,7 +53,7 @@ ecma_is_promise (ecma_object_t *obj_p) /**< points to object */ * @return ecma value of the promise result. * Returned value must be freed with ecma_free_value */ -static inline ecma_value_t +ecma_value_t ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */ { JERRY_ASSERT (ecma_is_promise (obj_p)); @@ -84,61 +84,30 @@ ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */ * * @return the state's enum value */ -static inline uint8_t JERRY_ATTR_ALWAYS_INLINE -ecma_promise_get_state (ecma_object_t *obj_p) /**< points to promise object */ +uint16_t +ecma_promise_get_flags (ecma_object_t *obj_p) /**< points to promise object */ { JERRY_ASSERT (ecma_is_promise (obj_p)); - return ((ecma_promise_object_t *) obj_p)->state; -} /* ecma_promise_get_state */ + return ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info; +} /* ecma_promise_get_flags */ /** * Set the PromiseState of promise. */ static inline void JERRY_ATTR_ALWAYS_INLINE ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */ - uint8_t state) /**< the state */ + bool is_fulfilled) /**< new flags */ { JERRY_ASSERT (ecma_is_promise (obj_p)); + JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); - ((ecma_promise_object_t *) obj_p)->state = state; + uint16_t flags_to_invert = (is_fulfilled ? (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED) + : ECMA_PROMISE_IS_PENDING); + + ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info ^= flags_to_invert; } /* ecma_promise_set_state */ -/** - * Get the bool value of alreadyResolved. - * - * @return bool value of alreadyResolved. - */ -static bool -ecma_get_already_resolved_bool_value (ecma_value_t already_resolved) /**< the alreadyResolved */ -{ - JERRY_ASSERT (ecma_is_value_object (already_resolved)); - - ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; - - JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); - - return ext_object_p->u.class_prop.u.value == ECMA_VALUE_TRUE; -} /* ecma_get_already_resolved_bool_value */ - -/** - * Set the value of alreadyResolved. - */ -static void -ecma_set_already_resolved_value (ecma_value_t already_resolved, /**< the alreadyResolved */ - bool value) /**< the value to set */ -{ - JERRY_ASSERT (ecma_is_value_object (already_resolved)); - - ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; - - JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); - - ext_object_p->u.class_prop.u.value = ecma_make_boolean_value (value); -} /* ecma_set_already_resolved_value */ - /** * Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction. * @@ -146,16 +115,84 @@ ecma_set_already_resolved_value (ecma_value_t already_resolved, /**< the already */ static void ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reactions */ - ecma_value_t value) /**< value for resolve or reject */ + ecma_value_t value, /**< value for resolve or reject */ + bool is_reject) /**< true if promise is rejected, false otherwise */ { ecma_value_t *buffer_p = reactions->buffer_p; + ecma_value_t *buffer_end_p = buffer_p + reactions->item_count; - for (uint32_t i = 0; i < reactions->item_count; i++) + while (buffer_p < buffer_end_p) { - ecma_enqueue_promise_reaction_job (buffer_p[i], value); + ecma_value_t capability_with_tag = *buffer_p++; + ecma_object_t *capability_obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, capability_with_tag); + ecma_value_t capability = ecma_make_object_value (capability_obj_p); + + if (!is_reject) + { + ecma_value_t handler = ECMA_VALUE_TRUE; + + if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag)) + { + handler = *buffer_p++; + } + + ecma_enqueue_promise_reaction_job (capability, handler, value); + } + else if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag)) + { + buffer_p++; + } + + if (is_reject) + { + ecma_value_t handler = ECMA_VALUE_FALSE; + + if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag)) + { + handler = *buffer_p++; + } + + ecma_enqueue_promise_reaction_job (capability, handler, value); + } + else if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag)) + { + buffer_p++; + } } } /* ecma_promise_trigger_reactions */ +/** + * Checks whether a resolver is called before. + * + * @return true if it was called before, false otherwise + */ +static bool +ecma_is_resolver_already_called (ecma_object_t *resolver_p, /**< resolver */ + ecma_object_t *promise_obj_p) /**< promise */ +{ + ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_property_t *property_p = ecma_find_named_property (resolver_p, str_already_resolved_p); + + if (property_p == NULL) + { + return (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_ALREADY_RESOLVED) != 0; + } + + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); + + ecma_value_t already_resolved = ECMA_PROPERTY_VALUE_PTR (property_p)->value; + ecma_object_t *object_p = ecma_get_object_from_value (already_resolved); + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS); + + ecma_extended_object_t *already_resolved_p = (ecma_extended_object_t *) object_p; + JERRY_ASSERT (already_resolved_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); + + ecma_value_t current_value = already_resolved_p->u.class_prop.u.value; + already_resolved_p->u.class_prop.u.value = ECMA_VALUE_TRUE; + + return current_value == ECMA_VALUE_TRUE; +} /* ecma_is_resolver_already_called */ + /** * Reject a Promise with a reason. * @@ -167,25 +204,22 @@ ecma_reject_promise (ecma_value_t promise, /**< promise */ { ecma_object_t *obj_p = ecma_get_object_from_value (promise); - JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); + JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); - ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_REJECTED); + ecma_promise_set_state (obj_p, false); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; /* GC can be triggered by ecma_new_collection so freeing the collection first and creating a new one might cause a heap after use event. */ - ecma_collection_t *reject_reactions = promise_p->reject_reactions; - ecma_collection_t *fulfill_reactions = promise_p->fulfill_reactions; + ecma_collection_t *reactions = promise_p->reactions; /* Fulfill reactions will never be triggered. */ - ecma_promise_trigger_reactions (reject_reactions, reason); + ecma_promise_trigger_reactions (reactions, reason, true); - promise_p->reject_reactions = ecma_new_collection (); - promise_p->fulfill_reactions = ecma_new_collection (); + promise_p->reactions = ecma_new_collection (); - ecma_collection_free_if_not_object (reject_reactions); - ecma_collection_free_if_not_object (fulfill_reactions); + ecma_collection_destroy (reactions); } /* ecma_reject_promise */ /** @@ -199,25 +233,22 @@ ecma_fulfill_promise (ecma_value_t promise, /**< promise */ { ecma_object_t *obj_p = ecma_get_object_from_value (promise); - JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); + JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); - ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_FULFILLED); + ecma_promise_set_state (obj_p, true); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; /* GC can be triggered by ecma_new_collection so freeing the collection first and creating a new one might cause a heap after use event. */ - ecma_collection_t *reject_reactions = promise_p->reject_reactions; - ecma_collection_t *fulfill_reactions = promise_p->fulfill_reactions; + ecma_collection_t *reactions = promise_p->reactions; /* Reject reactions will never be triggered. */ - ecma_promise_trigger_reactions (fulfill_reactions, value); + ecma_promise_trigger_reactions (reactions, value, false); - promise_p->reject_reactions = ecma_new_collection (); - promise_p->fulfill_reactions = ecma_new_collection (); + promise_p->reactions = ecma_new_collection (); - ecma_collection_free_if_not_object (reject_reactions); - ecma_collection_free_if_not_object (fulfill_reactions); + ecma_collection_destroy (reactions); } /* ecma_fulfill_promise */ /** @@ -235,33 +266,25 @@ ecma_promise_reject_handler (const ecma_value_t function, /**< the function itse { JERRY_UNUSED (this); - ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); - ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); - ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ - ecma_value_t promise = ecma_op_object_get (function_p, str_promise_p); + ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE); /* 1. */ - JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); - /* 3. */ - ecma_value_t already_resolved = ecma_op_object_get (function_p, str_already_resolved_p); + ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); + JERRY_ASSERT (ecma_is_promise (promise_obj_p)); - /* 4. */ - if (ecma_get_already_resolved_bool_value (already_resolved)) + /* 3., 4. */ + if (!ecma_is_resolver_already_called (function_p, promise_obj_p)) { - ecma_free_value (promise); - ecma_free_value (already_resolved); - return ECMA_VALUE_UNDEFINED; + /* 5. */ + ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED; + + /* 6. */ + ecma_value_t reject_value = (argc == 0) ? ECMA_VALUE_UNDEFINED : argv[0]; + ecma_reject_promise (promise, reject_value); } - /* 5. */ - ecma_set_already_resolved_value (already_resolved, true); - - /* 6. */ - ecma_value_t reject_value = (argc == 0) ? ECMA_VALUE_UNDEFINED : argv[0]; - ecma_reject_promise (promise, reject_value); ecma_free_value (promise); - ecma_free_value (already_resolved); return ECMA_VALUE_UNDEFINED; } /* ecma_promise_reject_handler */ @@ -280,25 +303,21 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its { JERRY_UNUSED (this); - ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); - ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); - ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ - ecma_value_t promise = ecma_op_object_get (function_p, str_promise_p); + ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE); /* 1. */ - JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); - /* 3. */ - ecma_value_t already_resolved = ecma_op_object_get (function_p, str_already_resolved_p); + ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); + JERRY_ASSERT (ecma_is_promise (promise_obj_p)); - /* 4. */ - if (ecma_get_already_resolved_bool_value (already_resolved)) + /* 3., 4. */ + if (ecma_is_resolver_already_called (function_p, promise_obj_p)) { goto end_of_resolve_function; } /* 5. */ - ecma_set_already_resolved_value (already_resolved, true); + ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED; /* If the argc is 0, then fulfill the `undefined`. */ if (argc == 0) @@ -325,12 +344,12 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its /* 8. */ ecma_value_t then = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (argv[0]), - LIT_MAGIC_STRING_THEN); + LIT_MAGIC_STRING_THEN); if (ECMA_IS_VALUE_ERROR (then)) { /* 9. */ - then = JERRY_CONTEXT (error_value); + then = jcontext_take_exception (); ecma_reject_promise (promise, then); } else if (!ecma_op_is_callable (then)) @@ -348,12 +367,11 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its end_of_resolve_function: ecma_free_value (promise); - ecma_free_value (already_resolved); return ECMA_VALUE_UNDEFINED; } /* ecma_promise_resolve_handler */ /** - * CapabilityiesExecutor Function. + * CapabilitiesExecutor Function. * * See also: ES2015 25.4.1.5.1 * @@ -409,6 +427,28 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object return ECMA_VALUE_UNDEFINED; } /* ecma_call_builtin_executor */ +/** + * Helper function for PromiseCreateResovingFucntions. + * + * See also: ES2015 25.4.1.3 2. - 7. + * + * @return pointer to the resolving function + */ +static ecma_value_t +ecma_promise_create_resolving_functions_helper (ecma_object_t *obj_p, /**< Promise Object */ + ecma_external_handler_t handler_cb) /**< Callback handler */ +{ + ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler_cb); + + ecma_op_object_put (func_obj_p, + str_promise_p, + ecma_make_object_value (obj_p), + false); + + return ecma_make_object_value (func_obj_p); +} /* ecma_promise_create_resolving_functions_helper */ + /** * Create a PromiseCreateResovingFucntions. * @@ -416,51 +456,40 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object * * @return pointer to the resolving functions */ -ecma_promise_resolving_functions_t * -ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promise object */ +void +ecma_promise_create_resolving_functions (ecma_object_t *object_p, /**< the promise object */ + ecma_promise_resolving_functions_t *funcs, /**< [out] resolving functions */ + bool create_already_resolved) /**< create already resolved flag */ { - /* 1. */ + /* 2. - 4. */ + funcs->resolve = ecma_promise_create_resolving_functions_helper (object_p, + ecma_promise_resolve_handler); + + /* 5. - 7. */ + funcs->reject = ecma_promise_create_resolving_functions_helper (object_p, + ecma_promise_reject_handler); + if (!create_already_resolved) + { + return; + } + ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE); - - ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_property_value_t *value_p; - /* 2. */ - ecma_object_t *resolve_p; - resolve_p = ecma_op_create_external_function_object (ecma_promise_resolve_handler); + value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->resolve), + str_already_resolved_p, + ECMA_PROPERTY_FIXED, + NULL); + value_p->value = already_resolved; - /* 3. */ - ecma_op_object_put (resolve_p, - str_promise_p, - ecma_make_object_value (object_p), - false); - /* 4. */ - ecma_op_object_put (resolve_p, - str_already_resolved_p, - already_resolved, - false); - /* 5. */ - ecma_object_t *reject_p; - reject_p = ecma_op_create_external_function_object (ecma_promise_reject_handler); - /* 6. */ - ecma_op_object_put (reject_p, - str_promise_p, - ecma_make_object_value (object_p), - false); - /* 7. */ - ecma_op_object_put (reject_p, - str_already_resolved_p, - already_resolved, - false); - - /* 8. */ - ecma_promise_resolving_functions_t *funcs = jmem_heap_alloc_block (sizeof (ecma_promise_resolving_functions_t)); - funcs->resolve = ecma_make_object_value (resolve_p); - funcs->reject = ecma_make_object_value (reject_p); + value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->reject), + str_already_resolved_p, + ECMA_PROPERTY_FIXED, + NULL); + value_p->value = already_resolved; ecma_free_value (already_resolved); - - return funcs; } /* ecma_promise_create_resolving_functions */ /** @@ -471,7 +500,6 @@ ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs { ecma_free_value (funcs->resolve); ecma_free_value (funcs->reject); - jmem_heap_free_block (funcs, sizeof (ecma_promise_resolving_functions_t)); } /* ecma_promise_free_resolving_functions */ /** @@ -486,36 +514,47 @@ ecma_value_t ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */ ecma_promise_executor_type_t type) /**< indicates the type of executor */ { + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL); /* 3. */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE); - ecma_object_t *object_p = ecma_create_object (prototype_obj_p, + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), + ECMA_BUILTIN_ID_PROMISE_PROTOTYPE); + + if (JERRY_UNLIKELY (proto_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + /* Calling ecma_new_collection might trigger a GC call, so this + * allocation is performed before the object is constructed. */ + ecma_collection_t *reactions = ecma_new_collection (); + + ecma_object_t *object_p = ecma_create_object (proto_p, sizeof (ecma_promise_object_t), ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (proto_p); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_PROMISE_UL; + /* 5 */ + ext_object_p->u.class_prop.extra_info = ECMA_PROMISE_IS_PENDING; ext_object_p->u.class_prop.u.value = ECMA_VALUE_UNDEFINED; ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) object_p; - promise_object_p->fulfill_reactions = NULL; - promise_object_p->reject_reactions = NULL; - /* 5 */ - ecma_promise_set_state (object_p, ECMA_PROMISE_STATE_PENDING); /* 6-7. */ - promise_object_p->fulfill_reactions = ecma_new_collection (); - promise_object_p->reject_reactions = ecma_new_collection (); + promise_object_p->reactions = reactions; /* 8. */ - ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (object_p); + ecma_promise_resolving_functions_t funcs; + ecma_promise_create_resolving_functions (object_p, &funcs, false); ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); ecma_op_object_put (object_p, str_resolve_p, - funcs->resolve, + funcs.resolve, false); ecma_op_object_put (object_p, str_reject_p, - funcs->reject, + funcs.reject, false); /* 9. */ @@ -525,7 +564,7 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function { JERRY_ASSERT (ecma_op_is_callable (executor)); - ecma_value_t argv[] = { funcs->resolve, funcs->reject }; + ecma_value_t argv[] = { funcs.resolve, funcs.reject }; completion = ecma_op_function_call (ecma_get_object_from_value (executor), ECMA_VALUE_UNDEFINED, argv, @@ -536,8 +575,8 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function JERRY_ASSERT (ecma_is_value_object (executor)); completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor), - funcs->resolve, - funcs->reject); + funcs.resolve, + funcs.reject); } else { @@ -550,14 +589,14 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function if (ECMA_IS_VALUE_ERROR (completion)) { /* 10.a. */ - completion = JERRY_CONTEXT (error_value); - status = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), + completion = jcontext_take_exception (); + status = ecma_op_function_call (ecma_get_object_from_value (funcs.reject), ECMA_VALUE_UNDEFINED, &completion, 1); } - ecma_promise_free_resolving_functions (funcs); + ecma_promise_free_resolving_functions (&funcs); ecma_free_value (completion); /* 10.b. */ @@ -573,6 +612,71 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function return ecma_make_object_value (object_p); } /* ecma_op_create_promise_object */ +/** + * 25.4.1.5.1 GetCapabilitiesExecutor Functions + * + * Checks and sets a promiseCapability's resolve and reject properties. + * + * @return ECMA_VALUE_UNDEFINED or TypeError + * returned value must be freed with ecma_free_value + */ +static ecma_value_t +ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED (this_val); + /* 1. */ + ecma_value_t capability = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (function_obj), + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); + JERRY_ASSERT (ecma_is_value_object (capability)); + + /* 2. */ + ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); + + /* 3. */ + ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + + if (!ecma_is_value_undefined (resolve)) + { + ecma_free_value (resolve); + ecma_deref_object (capability_obj_p); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined")); + } + + /* 4. */ + ecma_value_t reject = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + + if (!ecma_is_value_undefined (reject)) + { + ecma_free_value (reject); + ecma_deref_object (capability_obj_p); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined")); + } + + /* 5. */ + ecma_op_object_put (capability_obj_p, + ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE), + args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED, + false); + + /* 6. */ + ecma_op_object_put (capability_obj_p, + ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT), + args_count > 1 ? args_p[1] : ECMA_VALUE_UNDEFINED, + false); + + ecma_deref_object (capability_obj_p); + + /* 7. */ + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_get_capabilities_executor_cb */ + /** * Create a new PromiseCapability. * @@ -582,16 +686,22 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_promise_new_capability (void) +ecma_promise_new_capability (ecma_value_t constructor) { + /* 1. */ + if (!ecma_is_constructor (constructor)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability")); + } + + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); /* 3. */ ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); /* 4. */ - ecma_object_t *executor_p; - executor_p = ecma_op_create_object_object_noarg (); + ecma_object_t *executor_p = ecma_op_create_external_function_object (ecma_op_get_capabilities_executor_cb); ecma_value_t executor = ecma_make_object_value (executor_p); /* 5. */ ecma_op_object_put (executor_p, @@ -600,7 +710,18 @@ ecma_promise_new_capability (void) false); /* 6. */ - ecma_value_t promise = ecma_op_create_promise_object (executor, ECMA_PROMISE_EXECUTOR_OBJECT); + ecma_value_t promise = ecma_op_function_construct (constructor_obj_p, + constructor_obj_p, + &executor, + 1); + ecma_deref_object (executor_p); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (promise)) + { + ecma_deref_object (capability_p); + return promise; + } /* 10. */ ecma_op_object_put (capability_p, @@ -608,17 +729,8 @@ ecma_promise_new_capability (void) promise, false); - ecma_deref_object (executor_p); - - /* 7. */ - if (ECMA_IS_VALUE_ERROR (promise)) - { - ecma_free_value (promise); - ecma_deref_object (capability_p); - return promise; - } - ecma_free_value (promise); + /* 8. */ ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p); @@ -647,6 +759,85 @@ ecma_promise_new_capability (void) return ecma_make_object_value (capability_p); } /* ecma_promise_new_capability */ +/** + * The common function for 'reject' and 'resolve'. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ + ecma_value_t value, /**< rejected or resolved value */ + bool is_resolve) /**< the operation is resolve */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + if (is_resolve + && ecma_is_value_object (value) + && ecma_is_promise (ecma_get_object_from_value (value))) + { + ecma_object_t *object_p = ecma_get_object_from_value (value); + ecma_value_t constructor = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_CONSTRUCTOR); + + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + /* The this_arg must be an object. */ + bool is_same_value = (constructor == this_arg); + ecma_free_value (constructor); + + if (is_same_value) + { + return ecma_copy_value (value); + } + } + + ecma_value_t capability = ecma_promise_new_capability (this_arg); + + if (ECMA_IS_VALUE_ERROR (capability)) + { + return capability; + } + + ecma_string_t *property_str_p; + + if (is_resolve) + { + property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + } + else + { + property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + } + + ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); + + ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), + ECMA_VALUE_UNDEFINED, + &value, + 1); + + ecma_free_value (func); + + if (ECMA_IS_VALUE_ERROR (call_ret)) + { + return call_ret; + } + + ecma_free_value (call_ret); + + ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); + ecma_free_value (capability); + + return promise; +} /* ecma_promise_reject_or_resolve */ + /** * It performs the "then" operation on promiFulfilled * and onRejected as its settlement actions. @@ -662,8 +853,6 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * ecma_value_t on_rejected, /**< on_rejected function */ ecma_value_t result_capability) /**< promise capability */ { - ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *handler_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER); ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); /* 3. boolean true indicates "indentity" */ @@ -678,57 +867,56 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * on_rejected = ECMA_VALUE_FALSE; } - /* 5-6. */ - ecma_object_t *fulfill_reaction_p = ecma_op_create_object_object_noarg (); - ecma_object_t *reject_reaction_p = ecma_op_create_object_object_noarg (); - ecma_op_object_put (fulfill_reaction_p, - capability_str_p, - result_capability, - false); - ecma_op_object_put (fulfill_reaction_p, - handler_str_p, - on_fulfilled, - false); + ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); + ecma_promise_object_t *promise_p = (ecma_promise_object_t *) promise_obj_p; - ecma_op_object_put (reject_reaction_p, - capability_str_p, - result_capability, - false); - ecma_op_object_put (reject_reaction_p, - handler_str_p, - on_rejected, - false); + uint16_t flags = ecma_promise_get_flags (promise_obj_p); - ecma_object_t *obj_p = ecma_get_object_from_value (promise); - ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; - - if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING) + if (flags & ECMA_PROMISE_IS_PENDING) { /* 7. */ - ecma_collection_push_back (promise_p->fulfill_reactions, ecma_make_object_value (fulfill_reaction_p)); - ecma_collection_push_back (promise_p->reject_reactions, ecma_make_object_value (reject_reaction_p)); + ecma_value_t capability_with_tag; + ECMA_SET_NON_NULL_POINTER_TAG (capability_with_tag, ecma_get_object_from_value (result_capability), 0); + + if (on_fulfilled != ECMA_VALUE_TRUE) + { + ECMA_SET_FIRST_BIT_TO_POINTER_TAG (capability_with_tag); + } + + if (on_rejected != ECMA_VALUE_FALSE) + { + ECMA_SET_SECOND_BIT_TO_POINTER_TAG (capability_with_tag); + } + + ecma_collection_push_back (promise_p->reactions, capability_with_tag); + + if (on_fulfilled != ECMA_VALUE_TRUE) + { + ecma_collection_push_back (promise_p->reactions, on_fulfilled); + } + + if (on_rejected != ECMA_VALUE_FALSE) + { + ecma_collection_push_back (promise_p->reactions, on_rejected); + } } - else if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_FULFILLED) + else if (flags & ECMA_PROMISE_IS_FULFILLED) { /* 8. */ - ecma_value_t value = ecma_promise_get_result (obj_p); - ecma_enqueue_promise_reaction_job (ecma_make_object_value (fulfill_reaction_p), value); + ecma_value_t value = ecma_promise_get_result (promise_obj_p); + ecma_enqueue_promise_reaction_job (result_capability, on_fulfilled, value); ecma_free_value (value); } else { /* 9. */ - ecma_value_t reason = ecma_promise_get_result (obj_p); - ecma_enqueue_promise_reaction_job (ecma_make_object_value (reject_reaction_p), reason); + ecma_value_t reason = ecma_promise_get_result (promise_obj_p); + ecma_enqueue_promise_reaction_job (result_capability, on_rejected, reason); ecma_free_value (reason); } /* 10. */ - ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p); - - ecma_deref_object (fulfill_reaction_p); - ecma_deref_object (reject_reaction_p); - return ret; + return ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p); } /* ecma_promise_do_then */ /** @@ -755,7 +943,14 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */ return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise.")); } - ecma_value_t result_capability = ecma_promise_new_capability (); + ecma_value_t species = ecma_op_species_constructor (obj, ECMA_BUILTIN_ID_PROMISE); + if (ECMA_IS_VALUE_ERROR (species)) + { + return species; + } + + ecma_value_t result_capability = ecma_promise_new_capability (species); + ecma_free_value (species); if (ECMA_IS_VALUE_ERROR (result_capability)) { diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h index 2e71b622..18bfa103 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.h +++ b/jerry-core/ecma/operations/ecma-promise-object.h @@ -31,11 +31,10 @@ */ typedef enum { - ECMA_PROMISE_STATE_PENDING, /**< pending state */ - ECMA_PROMISE_STATE_FULFILLED, /**< fulfilled state */ - ECMA_PROMISE_STATE_REJECTED, /** rejected state */ - ECMA_PROMISE_STATE__COUNT /**< number of states */ -} ecma_promise_state_t; + ECMA_PROMISE_IS_PENDING = (1 << 0), /**< pending state */ + ECMA_PROMISE_IS_FULFILLED = (1 << 1), /**< fulfilled state */ + ECMA_PROMISE_ALREADY_RESOLVED = (1 << 2), /**< already resolved */ +} ecma_promise_flags_t; /** * Indicates the type of the executor in promise construct. @@ -62,22 +61,36 @@ typedef struct */ typedef struct { - ecma_extended_object_t ecma_extended_object_t; /**< extended object part */ - uint8_t state; /**< promise state, see ecma_promise_state_t */ - ecma_collection_t *fulfill_reactions; /**< list of PromiseFullfillReactions */ - ecma_collection_t *reject_reactions; /**< list of PromiseRejectReactions */ + ecma_extended_object_t header; /**< extended object part */ + ecma_collection_t *reactions; /**< list of promise reactions */ } ecma_promise_object_t; +/* The Promise reaction is a compressed structure, where each item can + * be a sequence of up to three ecma object values as seen below: + * + * [ Capability ][ Optional fullfilled callback ][ Optional rejected callback ] + * [ Async function callback ] + * + * The first member is an object, which lower bits specify the type of the reaction: + * bit 2 is not set: callback reactions + * The first two objects specify the resolve/reject functions of the promise + * returned by the `then` operation which can be used to chain event handlers. + * + * bit 0: has a fullfilled callback + * bit 1: has a rejected callback + * + * bit 2 is set: async function callback + */ + bool ecma_is_promise (ecma_object_t *obj_p); -ecma_value_t -ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type); -ecma_value_t ecma_promise_new_capability (void); -ecma_value_t -ecma_promise_then (ecma_value_t promise, - ecma_value_t on_fulfilled, - ecma_value_t on_rejected); -ecma_promise_resolving_functions_t * -ecma_promise_create_resolving_functions (ecma_object_t *object_p); +ecma_value_t ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type); +uint16_t ecma_promise_get_flags (ecma_object_t *promise_p); +ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p); +ecma_value_t ecma_promise_new_capability (ecma_value_t constructor); +ecma_value_t ecma_promise_reject_or_resolve (ecma_value_t this_arg, ecma_value_t value, bool is_resolve); +ecma_value_t ecma_promise_then (ecma_value_t promise, ecma_value_t on_fulfilled, ecma_value_t on_rejected); +void ecma_promise_create_resolving_functions (ecma_object_t *object_p, ecma_promise_resolving_functions_t *funcs, + bool create_already_resolved); void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs); /** diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c new file mode 100644 index 00000000..9e1fe8e7 --- /dev/null +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -0,0 +1,1818 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-alloc.h" +#include "ecma-array-object.h" +#include "ecma-builtins.h" +#include "ecma-builtin-object.h" +#include "ecma-exceptions.h" +#include "ecma-function-object.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-objects.h" +#include "ecma-objects-general.h" +#include "ecma-proxy-object.h" +#include "jcontext.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmaproxyobject ECMA Proxy object related routines + * @{ + */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Check whether the argument satifies the requrements of [[ProxyTarget]] or [[ProxyHandler]] + * + * See also: + * ES2015 9.5.15.1-2 + * ES2015 9.5.15.3-4 + * + * @return true - if the arguments can be a valid [[ProxyTarget]] or [[ProxyHandler]] + * false - otherwise + */ +static bool +ecma_proxy_validate (ecma_value_t argument) /**< argument to validate */ +{ + if (ecma_is_value_object (argument)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (argument); + + return (!ECMA_OBJECT_IS_PROXY (obj_p) + || !ecma_is_value_null (((ecma_proxy_object_t *) obj_p)->handler)); + } + + return false; +} /* ecma_proxy_validate */ + +/** + * ProxyCreate operation for create a new proxy object + * + * See also: + * ES2015 9.5.15 + * + * @return created Proxy object as an ecma-value - if success + * raised error - otherwise + */ +ecma_object_t * +ecma_proxy_create (ecma_value_t target, /**< proxy target */ + ecma_value_t handler) /**< proxy handler */ +{ + /* 1 - 4. */ + if (!ecma_proxy_validate (target) || !ecma_proxy_validate (handler)) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Cannot create proxy with a non-object target or handler")); + return NULL; + } + + /* 5 - 6. */ + ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + sizeof (ecma_proxy_object_t), + ECMA_OBJECT_TYPE_PROXY); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 8. */ + proxy_obj_p->target = target; + /* 9. */ + proxy_obj_p->handler = handler; + + /* 10. */ + return obj_p; +} /* ecma_proxy_create */ + +/** + * Definition of Proxy Revocation Function + * + * See also: + * ES2015 26.2.2.1.1 + * + * @return ECMA_VALUE_UNDEFINED + */ +ecma_value_t +ecma_proxy_revoke_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_3 (this_val, args_p, args_count); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj); + + /* 1. */ + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p; + + /* 2. */ + if (ecma_is_value_null (rev_proxy_p->proxy)) + { + return ECMA_VALUE_UNDEFINED; + } + + /* 4. */ + ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) ecma_get_object_from_value (rev_proxy_p->proxy); + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY ((ecma_object_t *) proxy_p)); + + /* 3. */ + rev_proxy_p->proxy = ECMA_VALUE_NULL; + + /* 5. */ + proxy_p->target = ECMA_VALUE_NULL; + + /* 6. */ + proxy_p->handler = ECMA_VALUE_NULL; + + /* 7. */ + return ECMA_VALUE_UNDEFINED; +} /* ecma_proxy_revoke_cb */ + +/** + * Proxy.revocable operation for create a new revocable proxy object + * + * See also: + * ES2015 26.2.2.1 + * + * @return NULL - if the operation fails + * pointer to the newly created revocable proxy object - otherwise + */ +ecma_object_t * +ecma_proxy_create_revocable (ecma_value_t target, /**< target argument */ + ecma_value_t handler) /**< handler argument */ +{ + /* 1. */ + ecma_object_t *proxy_p = ecma_proxy_create (target, handler); + + /* 2. */ + if (proxy_p == NULL) + { + return proxy_p; + } + + ecma_value_t proxy_value = ecma_make_object_value (proxy_p); + + /* 3. */ + ecma_object_t *func_obj_p; + func_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE), + sizeof (ecma_revocable_proxy_object_t), + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p; + rev_proxy_p->header.u.external_handler_cb = ecma_proxy_revoke_cb; + /* 4. */ + rev_proxy_p->proxy = proxy_value; + + ecma_property_value_t *prop_value_p; + ecma_value_t revoker = ecma_make_object_value (func_obj_p); + + /* 5. */ + ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + + /* 6. */ + prop_value_p = ecma_create_named_data_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_PROXY), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + prop_value_p->value = proxy_value; + + /* 7. */ + prop_value_p = ecma_create_named_data_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_REVOKE), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + prop_value_p->value = revoker; + + ecma_deref_object (proxy_p); + ecma_deref_object (func_obj_p); + + /* 8. */ + return obj_p; +} /* ecma_proxy_create_revocable */ + +/** + * Internal find property operation for Proxy object + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NOT_FOUND - if the property is not found + * value of the property - otherwise + */ +ecma_value_t +ecma_proxy_object_find (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_value_t has_result = ecma_proxy_object_has (obj_p, prop_name_p); + + if (ECMA_IS_VALUE_ERROR (has_result)) + { + return has_result; + } + + if (ecma_is_value_false (has_result)) + { + return ECMA_VALUE_NOT_FOUND; + } + + return ecma_proxy_object_get (obj_p, prop_name_p, ecma_make_object_value (obj_p)); +} /* ecma_proxy_object_find */ + +/** + * Convert the result of the ecma_proxy_object_get_prototype_of to compressed pointer + * + * Note: if `proto` is non-null, the reference from the object is released + * + * @return compressed pointer to the `proto` value + */ +jmem_cpointer_t +ecma_proxy_object_prototype_to_cp (ecma_value_t proto) /**< ECMA_VALUE_NULL or object */ +{ + JERRY_ASSERT (ecma_is_value_null (proto) || ecma_is_value_object (proto)); + + if (ecma_is_value_null (proto)) + { + return JMEM_CP_NULL; + } + + jmem_cpointer_t proto_cp; + ecma_object_t *proto_obj_p = ecma_get_object_from_value (proto); + ECMA_SET_POINTER (proto_cp, proto_obj_p); + ecma_deref_object (proto_obj_p); + + return proto_cp; +} /* ecma_proxy_object_prototype_to_cp */ + +/** + * Helper method for validate the proxy object + * + * @return proxy trap - if the validation is successful + * ECMA_VALUE_ERROR - otherwise + */ +static ecma_value_t +ecma_validate_proxy_object (ecma_value_t handler, /**< proxy handler */ + lit_magic_string_id_t magic_id) /**< routine magic id */ +{ + if (ecma_is_value_null (handler)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Handler can not be null")); + } + + JERRY_ASSERT (ecma_is_value_object (handler)); + + return ecma_op_get_method_by_magic_id (handler, magic_id); +} /* ecma_validate_proxy_object */ + +/* Interal operations */ + +/** + * The Proxy object [[GetPrototypeOf]] internal routine + * + * See also: + * ECMAScript v6, 9.5.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NULL or valid object (prototype) otherwise + */ +ecma_value_t +ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_builtin_object_object_get_prototype_of (target_obj_p); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + + /* 8. */ + ecma_value_t handler_proto = ecma_op_function_call (func_obj_p, handler, &target, 1); + + ecma_deref_object (func_obj_p); + + /* 9. */ + if (ECMA_IS_VALUE_ERROR (handler_proto)) + { + return handler_proto; + } + + /* 10. */ + if (!ecma_is_value_object (handler_proto) && !ecma_is_value_null (handler_proto)) + { + ecma_free_value (handler_proto); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned neither object nor null.")); + } + + /* 11. */ + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + /* 12. */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + ecma_free_value (handler_proto); + + return extensible_target; + } + + /* 13. */ + if (ecma_is_value_true (extensible_target)) + { + return handler_proto; + } + + /* 14. */ + ecma_value_t target_proto = ecma_builtin_object_object_get_prototype_of (target_obj_p); + + /* 15. */ + if (ECMA_IS_VALUE_ERROR (target_proto)) + { + return target_proto; + } + + ecma_value_t ret_value = handler_proto; + + /* 16. */ + if (handler_proto != target_proto) + { + ecma_free_value (handler_proto); + + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Proxy target is non-extensible, but the trap did not " + "return its actual prototype.")); + } + + ecma_free_value (target_proto); + + /* 17. */ + return ret_value; +} /* ecma_proxy_object_get_prototype_of */ + +/** + * The Proxy object [[SetPrototypeOf]] internal routine + * + * See also: + * ECMAScript v6, 9.5.2 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the new prototype can be set for the given object + */ +ecma_value_t +ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, /**< proxy object */ + ecma_value_t proto) /**< new prototype object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_SET_PROTOTYPE_OF_UL); + + /* 7.*/ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + if (ECMA_OBJECT_IS_PROXY (target_obj_p)) + { + return ecma_proxy_object_set_prototype_of (target_obj_p, proto); + } + + return ecma_op_ordinary_object_set_prototype_of (target_obj_p, proto); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t args[] = { target, proto }; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2); + + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 11. */ + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + /* 12. */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + return extensible_target; + } + + /* 13. */ + if (ecma_is_value_true (extensible_target)) + { + return ecma_make_boolean_value (boolean_trap_result); + } + + /* 14. */ + ecma_value_t target_proto = ecma_builtin_object_object_get_prototype_of (target_obj_p); + + /* 15. */ + if (ECMA_IS_VALUE_ERROR (target_proto)) + { + return target_proto; + } + + ecma_value_t ret_value = ecma_make_boolean_value (boolean_trap_result); + + /* 16. */ + if (boolean_trap_result && (target_proto != proto)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Target object is non-extensible and trap " + "returned different prototype.")); + } + + ecma_free_value (target_proto); + + /* 17. */ + return ret_value; +} /* ecma_proxy_object_set_prototype_of */ + +/** + * The Proxy object [[isExtensible]] internal routine + * + * See also: + * ECMAScript v6, 9.5.3 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object is extensible + */ +ecma_value_t +ecma_proxy_object_is_extensible (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_IS_EXTENSIBLE); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_builtin_object_object_is_extensible (target_obj_p); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + + /* 8. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, &target, 1); + + ecma_deref_object (func_obj_p); + + /* 9. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + bool target_result; + + /* 10. */ + if (ECMA_OBJECT_IS_PROXY (target_obj_p)) + { + ecma_value_t proxy_is_ext = ecma_proxy_object_is_extensible (target_obj_p); + + if (ECMA_IS_VALUE_ERROR (proxy_is_ext)) + { + return proxy_is_ext; + } + + target_result = ecma_is_value_true (proxy_is_ext); + } + else + { + target_result = ecma_op_ordinary_object_is_extensible (target_obj_p); + } + + /* 12. */ + if (boolean_trap_result != target_result) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap result does not reflect extensibility of proxy target")); + } + + return ecma_make_boolean_value (boolean_trap_result); +} /* ecma_proxy_object_is_extensible */ + +/** + * The Proxy object [[PreventExtensions]] internal routine + * + * See also: + * ECMAScript v6, 9.5.4 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object can be set as inextensible + */ +ecma_value_t +ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + ecma_value_t ret_value = ecma_builtin_object_object_prevent_extensions (target_obj_p); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + ecma_deref_object (target_obj_p); + + return ECMA_VALUE_TRUE; + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + + /* 8. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, &target, 1); + + ecma_deref_object (func_obj_p); + + /* 9. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 10. */ + if (boolean_trap_result) + { + ecma_value_t target_is_ext = ecma_builtin_object_object_is_extensible (target_obj_p); + + if (ECMA_IS_VALUE_ERROR (target_is_ext)) + { + return target_is_ext; + } + + if (ecma_is_value_true (target_is_ext)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap result does not reflect inextensibility of proxy target")); + } + } + + /* 11. */ + return ecma_make_boolean_value (boolean_trap_result); +} /* ecma_proxy_object_prevent_extensions */ + +/** + * The Proxy object [[GetOwnProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.5 + * + * Note: - Returned value is always a simple value so freeing it is unnecessary. + * - If the operation does not fail, freeing the filled property descriptor is the caller's responsibility + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether object has property with the given name + */ +ecma_value_t +ecma_proxy_object_get_own_property_descriptor (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_property_descriptor_t *prop_desc_p) /**< [out] property + * descriptor */ +{ + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL); + + ecma_value_t target = proxy_obj_p->target; + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, prop_desc_p); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t args[] = { target, prop_value }; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2); + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + /* 11. */ + if (!ecma_is_value_object (trap_result) && !ecma_is_value_undefined (trap_result)) + { + ecma_free_value (trap_result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap is not object nor undefined.")); + } + + /* 12. */ + ecma_property_descriptor_t target_desc; + ecma_value_t target_status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + /* 13. */ + if (ECMA_IS_VALUE_ERROR (target_status)) + { + ecma_free_value (trap_result); + return target_status; + } + + /* 14. */ + if (ecma_is_value_undefined (trap_result)) + { + /* .a */ + if (ecma_is_value_false (target_status)) + { + return ECMA_VALUE_FALSE; + } + /* .b */ + if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)) + { + ecma_free_property_descriptor (&target_desc); + return ecma_raise_type_error (ECMA_ERR_MSG ("Given property is a non-configurable" + " data property on the proxy target")); + } + + /* .c */ + ecma_free_property_descriptor (&target_desc); + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + /* .d */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + return extensible_target; + } + + /* .e */ + JERRY_ASSERT (ecma_is_value_boolean (extensible_target)); + + /* .f */ + if (ecma_is_value_false (extensible_target)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Target not extensible.")); + } + + /* .g */ + return ECMA_VALUE_FALSE; + } + + /* 15. */ + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + /* 16. */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + if (ecma_is_value_true (target_status)) + { + ecma_free_property_descriptor (&target_desc); + } + ecma_free_value (trap_result); + return extensible_target; + } + + /* 17, 19 */ + ecma_value_t result_val = ecma_op_to_property_descriptor (trap_result, prop_desc_p); + + ecma_op_to_complete_property_descriptor (prop_desc_p); + ecma_free_value (trap_result); + + /* 18. */ + if (ECMA_IS_VALUE_ERROR (result_val)) + { + if (ecma_is_value_true (target_status)) + { + ecma_free_property_descriptor (&target_desc); + } + return result_val; + } + + /* 20. */ + bool is_extensible = ecma_is_value_true (extensible_target); + + bool is_valid = ecma_op_is_compatible_property_descriptor (prop_desc_p, + (ecma_is_value_true (target_status) ? &target_desc : NULL), + is_extensible); + + bool target_has_desc = ecma_is_value_true (target_status); + bool target_is_configurable = false; + + if (target_has_desc) + { + target_is_configurable = ((target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) != 0); + ecma_free_property_descriptor (&target_desc); + } + + /* 21. */ + if (!is_valid) + { + ecma_free_property_descriptor (prop_desc_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("The two descriptors are not compatible.")); + } + + /* 22. */ + else if (!(prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE)) + { + if (!target_has_desc || target_is_configurable) + { + ecma_free_property_descriptor (prop_desc_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Not compatible.")); + } + } + return ECMA_VALUE_TRUE; +} /* ecma_proxy_object_get_own_property_descriptor */ + +/** + * The Proxy object [[DefineOwnProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.6 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property can be defined for the given object + */ +ecma_value_t +ecma_proxy_object_define_own_property (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + const ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_DEFINE_PROPERTY_UL); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_define_own_property (target_obj_p, prop_name_p, prop_desc_p); + } + + /* 9. */ + ecma_object_t *desc_obj = ecma_op_from_property_descriptor (prop_desc_p); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t desc_obj_value = ecma_make_object_value (desc_obj); + ecma_value_t args[] = {target, prop_value, desc_obj_value}; + + /* 10. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 3); + + ecma_deref_object (func_obj_p); + ecma_deref_object (desc_obj); + + /* 11. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 12. */ + if (!boolean_trap_result) + { + return ECMA_VALUE_FALSE; + } + + /* 13. */ + ecma_property_descriptor_t target_desc; + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + /* 14. */ + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + bool target_prop_found = ecma_is_value_true (status); + + /* 15. */ + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + bool is_target_ext = ecma_is_value_true (extensible_target); + + /* 16. */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + if (target_prop_found) + { + ecma_free_property_descriptor (&target_desc); + } + + return extensible_target; + } + + /* 17. */ + bool setting_config_false = ((prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE_DEFINED) + && !(prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE)); + + /* 19. */ + if (!target_prop_found) + { + if (!is_target_ext) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for adding property " + "to the non-extensible target")); + } + + if (setting_config_false) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for defining non-configurable property " + "which is non-existent in the target")); + } + } + /* 20. */ + else + { + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + if (!ecma_op_is_compatible_property_descriptor (prop_desc_p, &target_desc, is_target_ext)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for adding property that is " + "incompatible with the existing property in the target")); + } + else if (setting_config_false && (target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for defining non-configurable property " + "which is configurable in the target")); + } + + ecma_free_property_descriptor (&target_desc); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + } + + return ECMA_VALUE_TRUE; +} /* ecma_proxy_object_define_own_property */ + +/** + * The Proxy object [[HasProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.7 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property is found + */ +ecma_value_t +ecma_proxy_object_has (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + ECMA_CHECK_STACK_USAGE (); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_HAS); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_has_property (target_obj_p, prop_name_p); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t args[] = {target, prop_value}; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2); + + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 11. */ + if (!boolean_trap_result) + { + ecma_property_descriptor_t target_desc; + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + if (ecma_is_value_true (status)) + { + bool prop_is_configurable = target_desc.flags & ECMA_PROP_IS_CONFIGURABLE; + + ecma_free_property_descriptor (&target_desc); + + if (!prop_is_configurable) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned falsish for property which exists " + "in the proxy target as non-configurable")); + } + + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + return extensible_target; + } + + if (ecma_is_value_false (extensible_target)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned falsish for property but " + "the proxy target is not extensible")); + } + } + } + + /* 12. */ + return ecma_make_boolean_value (boolean_trap_result); +} /* ecma_proxy_object_has */ + +/** + * The Proxy object [[Get]] internal routine + * + * See also: + * ECMAScript v6, 9.5.8 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * value of the given nameddata property or the result of the getter function call - otherwise + */ +ecma_value_t +ecma_proxy_object_get (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_value_t receiver) /**< receiver to invoke getter function */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + ECMA_CHECK_STACK_USAGE (); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_get_with_receiver (target_obj_p, prop_name_p, receiver); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t args[] = { target, prop_value, receiver }; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 3); + + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + /* 11. */ + ecma_property_descriptor_t target_desc; + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + /* 12. */ + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + /* 13. */ + if (ecma_is_value_true (status)) + { + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + if ((target_desc.flags & ECMA_PROP_IS_VALUE_DEFINED) + && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) + && !(target_desc.flags & ECMA_PROP_IS_WRITABLE) + && !ecma_op_same_value (trap_result, target_desc.value)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("given property is a read-only and non-configurable" + " data property on the proxy target")); + } + else if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) + && (target_desc.flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)) + && target_desc.get_p == NULL + && !ecma_is_value_undefined (trap_result)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("given property is a non-configurable property and" + " does not have a getter function")); + } + + ecma_free_property_descriptor (&target_desc); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_free_value (trap_result); + + return ret_value; + } + } + + /* 14. */ + return trap_result; +} /* ecma_proxy_object_get */ + +/** + * The Proxy object [[Set]] internal routine + * + * See also: + * ECMAScript v6, 9.5.9 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be set to the given object + */ +ecma_value_t +ecma_proxy_object_set (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_value_t value, /**< value to set */ + ecma_value_t receiver) /**< receiver to invoke setter function */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + ECMA_CHECK_STACK_USAGE (); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_SET); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_put_with_receiver (target_obj_p, prop_name_p, value, receiver, false); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_name_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t args[] = { target, prop_name_value, value, receiver }; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 4); + + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 11. */ + if (!boolean_trap_result) + { + return ECMA_VALUE_FALSE; + } + + /* 12. */ + ecma_property_descriptor_t target_desc; + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + /* 13. */ + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + /* 14. */ + if (ecma_is_value_true (status)) + { + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + if ((target_desc.flags & ECMA_PROP_IS_VALUE_DEFINED) + && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) + && !(target_desc.flags & ECMA_PROP_IS_WRITABLE) + && !ecma_op_same_value (value, target_desc.value)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("The property exists in the proxy target as a" + " non-configurable and non-writable data property" + " with a different value.")); + } + else if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) + && (target_desc.flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED)) + && target_desc.set_p == NULL) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("The property exists in the proxy target as a" + " non-configurable accessor property whitout a setter.")); + } + + ecma_free_property_descriptor (&target_desc); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + } + + /* 15. */ + return ECMA_VALUE_TRUE; +} /* ecma_proxy_object_set */ + +/** + * The Proxy object [[Delete]] internal routine + * + * See also: + * ECMAScript v6, 9.5.10 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be deleted + */ +ecma_value_t +ecma_proxy_object_delete_property (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 2. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 3-6.*/ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_DELETE_PROPERTY_UL); + + /* 7. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 8. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_delete (target_obj_p, prop_name_p, false); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t prop_name_value = ecma_make_prop_name_value (prop_name_p); + ecma_value_t args[] = { target, prop_name_value }; + + /* 9. */ + ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2); + + ecma_deref_object (func_obj_p); + + /* 10. */ + if (ECMA_IS_VALUE_ERROR (trap_result)) + { + return trap_result; + } + + bool boolean_trap_result = ecma_op_to_boolean (trap_result); + + ecma_free_value (trap_result); + + /* 11. */ + if (!boolean_trap_result) + { + return ECMA_VALUE_FALSE; + } + + /* 12. */ + ecma_property_descriptor_t target_desc; + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc); + + /* 13. */ + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + /* 14. */ + if (ecma_is_value_false (status)) + { + return ECMA_VALUE_TRUE; + } + + ecma_value_t ret_value = ECMA_VALUE_TRUE; + + /* 15. */ + if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for property which is " + "non-configurable in the proxy target.")); + } + + ecma_free_property_descriptor (&target_desc); + + /* 16. */ + return ret_value; +} /* ecma_proxy_object_delete_property */ + +/** + * The Proxy object [[Enumerate]] internal routine + * + * See also: + * ECMAScript v6, 9.5.11 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ecma-object - otherwise + */ +ecma_value_t +ecma_proxy_object_enumerate (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Enumerate]]")); +} /* ecma_proxy_object_enumerate */ + +/** + * Helper method for the Proxy object [[OwnPropertyKeys]] operation + * + * See also: + * ECMAScript v6, 9.5.12 steps 21. 23. + * + * @return ECMA_VALUE_ERROR - if a target key is not in the unchecked_result_keys collection + * ECMA_VALUE_EMPTY - otherwise + */ +static ecma_value_t +ecma_proxy_object_own_property_keys_helper (ecma_collection_t *target_collection, /**< target keys */ + ecma_collection_t *unchecked_result_keys, /**< unchecked keys */ + uint32_t *counter) /**< unchecked property counter */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + for (uint32_t i = 0; i < target_collection->item_count; i++) + { + ecma_string_t *current_prop_name = ecma_get_prop_name_from_value (target_collection->buffer_p[i]); + + ret_value = ECMA_VALUE_ERROR; + + for (uint32_t j = 0; j < unchecked_result_keys->item_count; j++) + { + if (ecma_is_value_empty (unchecked_result_keys->buffer_p[j])) + { + continue; + } + + ecma_string_t *unchecked_prop_name = ecma_get_prop_name_from_value (unchecked_result_keys->buffer_p[j]); + + if (ecma_compare_ecma_strings (current_prop_name, unchecked_prop_name)) + { + ecma_deref_ecma_string (unchecked_prop_name); + ret_value = ECMA_VALUE_EMPTY; + unchecked_result_keys->buffer_p[j] = ECMA_VALUE_EMPTY; + (*counter)++; + } + } + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + break; + } + } + + return ret_value; +} /* ecma_proxy_object_own_property_keys_helper */ + +/** + * Helper method for checking the invariants in the Proxy object [[OwnPropertyKeys]] operation + * + * See also: + * ECMAScript v6, 9.5.12 steps 20-25. + * + * @return true - if none of the invariants got violated + * false - otherwise + */ +static bool +ecma_proxy_check_invariants_for_own_prop_keys (ecma_collection_t *trap_result, + ecma_collection_t *target_non_configurable_keys, + ecma_collection_t *target_configurable_keys, + ecma_value_t extensible_target) +{ + /* 20. */ + ecma_collection_t *unchecked_result_keys = ecma_new_collection (); + + ecma_collection_append (unchecked_result_keys, trap_result->buffer_p, trap_result->item_count); + + for (uint32_t i = 0; i < unchecked_result_keys->item_count; i++) + { + ecma_string_t *unchecked_prop_name = ecma_get_prop_name_from_value (unchecked_result_keys->buffer_p[i]); + ecma_ref_ecma_string (unchecked_prop_name); + } + + bool check_ok = false; + uint32_t unchecked_prop_name_counter = 0; + + /* 21. */ + if (ECMA_IS_VALUE_ERROR (ecma_proxy_object_own_property_keys_helper (target_non_configurable_keys, + unchecked_result_keys, + &unchecked_prop_name_counter))) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Trap result did not include all non-configurable keys.")); + } + /* 22. */ + else if (ecma_is_value_true (extensible_target)) + { + check_ok = true; + } + /* 23. */ + else if (ECMA_IS_VALUE_ERROR (ecma_proxy_object_own_property_keys_helper (target_configurable_keys, + unchecked_result_keys, + &unchecked_prop_name_counter))) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Trap result did not include all configurable keys.")); + } + /* 24. */ + else if (unchecked_result_keys->item_count != unchecked_prop_name_counter) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned extra keys but proxy target is non-extensible")); + } + /* 25. */ + else + { + check_ok = true; + } + + ecma_collection_free (unchecked_result_keys); + + return check_ok; +} /* ecma_proxy_check_invariants_for_own_prop_keys */ + +/** + * The Proxy object [[OwnPropertyKeys]] internal routine + * + * See also: + * ECMAScript v6, 9.5.12 + * + * Note: If the returned collection is not NULL, it must be freed with + * ecma_collection_free if it is no longer needed + * + * @return NULL - if the operation fails + * pointer to a newly allocated list of property names - otherwise + */ +ecma_collection_t * +ecma_proxy_object_own_property_keys (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_OWN_KEYS_UL); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return NULL; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + return ecma_op_object_get_property_names (target_obj_p, ECMA_LIST_SYMBOLS); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + + /* 8. */ + ecma_value_t trap_result_array = ecma_op_function_call (func_obj_p, handler, &target, 1); + + ecma_deref_object (func_obj_p); + + if (ECMA_IS_VALUE_ERROR (trap_result_array)) + { + return NULL; + } + + /* 9. */ + ecma_collection_t *trap_result = ecma_op_create_list_from_array_like (trap_result_array, true); + + ecma_free_value (trap_result_array); + + /* 10. */ + if (trap_result == NULL) + { + return trap_result; + } + + /* 11. */ + ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); + + /* 12. */ + if (ECMA_IS_VALUE_ERROR (extensible_target)) + { + ecma_collection_free (trap_result); + return NULL; + } + + /* 13. */ + ecma_collection_t *target_keys = ecma_op_object_get_property_names (target_obj_p, ECMA_LIST_SYMBOLS); + + /* 14. */ + if (target_keys == NULL) + { + ecma_collection_free (trap_result); + return target_keys; + } + + /* 16. */ + ecma_collection_t *target_configurable_keys = ecma_new_collection (); + + /* 17. */ + ecma_collection_t *target_non_configurable_keys = ecma_new_collection (); + + ecma_collection_t *ret_value = NULL; + + /* 18. */ + for (uint32_t i = 0; i < target_keys->item_count; i++) + { + ecma_property_descriptor_t target_desc; + + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (target_keys->buffer_p[i]); + + ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, + prop_name_p, + &target_desc); + + if (ECMA_IS_VALUE_ERROR (status)) + { + ecma_collection_free (trap_result); + goto free_target_collections; + } + + ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p); + + if (ecma_is_value_true (status) + && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)) + { + ecma_collection_push_back (target_non_configurable_keys, prop_value); + } + else + { + ecma_collection_push_back (target_configurable_keys, prop_value); + } + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&target_desc); + } + } + + /* 19. */ + if (ecma_is_value_true (extensible_target) && target_non_configurable_keys->item_count == 0) + { + ret_value = trap_result; + } + /* 20-25. */ + else if (ecma_proxy_check_invariants_for_own_prop_keys (trap_result, + target_non_configurable_keys, + target_configurable_keys, + extensible_target)) + { + ret_value = trap_result; + } + else + { + JERRY_ASSERT (ret_value == NULL); + ecma_collection_free (trap_result); + } + +free_target_collections: + ecma_collection_destroy (target_keys); + ecma_collection_free (target_configurable_keys); + ecma_collection_free (target_non_configurable_keys); + + return ret_value; +} /* ecma_proxy_object_own_property_keys */ + +/** + * The Proxy object [[Call]] internal routine + * + * See also: + * ECMAScript v6, 9.5.13 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the function call - otherwise + */ +ecma_value_t +ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */ + ecma_value_t this_argument, /**< this argument to invoke the function */ + const ecma_value_t *args_p, /**< argument list */ + ecma_length_t argc) /**< number of arguments */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5.*/ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_APPLY); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + return ecma_op_function_call (target_obj_p, this_argument, args_p, argc); + } + + /* 8. */ + ecma_value_t args_array = ecma_op_create_array_object (args_p, argc, false); + ecma_value_t value_array[] = {target, this_argument, args_array}; + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + /* 9. */ + ecma_value_t ret_value = ecma_op_function_call (func_obj_p, handler, value_array, 3); + ecma_deref_object (func_obj_p); + ecma_deref_object (ecma_get_object_from_value (args_array)); + + return ret_value; +} /* ecma_proxy_object_call */ + +/** + * The Proxy object [[Construct]] internal routine + * + * See also: + * ECMAScript v6, 9.5.14 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the construct call - otherwise + */ +ecma_value_t +ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */ + ecma_object_t *new_target_p, /**< new target */ + const ecma_value_t *args_p, /**< argument list */ + ecma_length_t argc) /**< number of arguments */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_proxy_object_t * proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 1. */ + ecma_value_t handler = proxy_obj_p->handler; + + /* 2-5. */ + ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_CONSTRUCT); + + /* 6. */ + if (ECMA_IS_VALUE_ERROR (trap)) + { + return trap; + } + + ecma_value_t target = proxy_obj_p->target; + ecma_object_t *target_obj_p = ecma_get_object_from_value (target); + + /* 7. */ + if (ecma_is_value_undefined (trap)) + { + JERRY_ASSERT (ecma_object_is_constructor (target_obj_p)); + + return ecma_op_function_construct (target_obj_p, new_target_p, args_p, argc); + } + + /* 8. */ + ecma_value_t arg_array = ecma_op_create_array_object (args_p, argc, false); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (trap); + ecma_value_t new_target_value = ecma_make_object_value (new_target_p); + ecma_value_t function_call_args[] = {target, arg_array, new_target_value}; + + /* 9. */ + ecma_value_t new_obj = ecma_op_function_call (func_obj_p, handler, function_call_args, 3); + + ecma_free_value (arg_array); + ecma_deref_object (func_obj_p); + + /* 10 .*/ + if (ECMA_IS_VALUE_ERROR (new_obj)) + { + return new_obj; + } + + /* 11. */ + if (!ecma_is_value_object (new_obj)) + { + ecma_free_value (new_obj); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned non-object")); + } + + /* 12. */ + return new_obj; +} /* ecma_proxy_object_construct */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +/** + * @} + * @} + */ diff --git a/jerry-core/ecma/operations/ecma-proxy-object.h b/jerry-core/ecma/operations/ecma-proxy-object.h new file mode 100644 index 00000000..db8ae06c --- /dev/null +++ b/jerry-core/ecma/operations/ecma-proxy-object.h @@ -0,0 +1,120 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_PROXY_OBJECT_H +#define ECMA_PROXY_OBJECT_H + +#include "ecma-globals.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmaproxyobject ECMA Proxy object related routines + * @{ + */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +ecma_object_t * +ecma_proxy_create (ecma_value_t target, + ecma_value_t handler); + +ecma_object_t * +ecma_proxy_create_revocable (ecma_value_t target, + ecma_value_t handler); + +ecma_value_t +ecma_proxy_revoke_cb (const ecma_value_t function_obj, + const ecma_value_t this_val, + const ecma_value_t args_p[], + const ecma_length_t args_count); + +jmem_cpointer_t +ecma_proxy_object_prototype_to_cp (ecma_value_t proto); + +ecma_value_t +ecma_proxy_object_find (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +/* Interal operations */ + +ecma_value_t +ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, + ecma_value_t proto); + +ecma_value_t +ecma_proxy_object_is_extensible (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_get_own_property_descriptor (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + ecma_property_descriptor_t *prop_desc_p); + +ecma_value_t +ecma_proxy_object_define_own_property (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + const ecma_property_descriptor_t *prop_desc_p); + +ecma_value_t +ecma_proxy_object_has (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +ecma_value_t +ecma_proxy_object_get (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + ecma_value_t receiver); + +ecma_value_t +ecma_proxy_object_set (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + ecma_value_t name, + ecma_value_t receiver); + +ecma_value_t +ecma_proxy_object_delete_property (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +ecma_value_t +ecma_proxy_object_enumerate (ecma_object_t *obj_p); + +ecma_collection_t * +ecma_proxy_object_own_property_keys (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_call (ecma_object_t *obj_p, + ecma_value_t this_argument, + const ecma_value_t *args_p, + ecma_length_t argc); + +ecma_value_t +ecma_proxy_object_construct (ecma_object_t *obj_p, + ecma_object_t *new_target_p, + const ecma_value_t *args_p, + ecma_length_t argc); + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +/** + * @} + * @} + */ + +#endif /* !ECMA_PROXY_OBJECT_H */ diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index 30ecf3aa..518d2167 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -21,6 +21,7 @@ #include "ecma-lcache.h" #include "ecma-lex-env.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-reference.h" #include "jrt.h" @@ -34,9 +35,9 @@ /** * Resolve syntactic reference. * - * @return if reference was resolved successfully, - * pointer to lexical environment - reference's base, - * else - NULL. + * @return ECMA_OBJECT_POINTER_ERROR - if the operation fails + * pointer to lexical environment - if the reference's base is resolved sucessfully, + * NULL - otherwise. */ ecma_object_t * ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical environment */ @@ -46,15 +47,24 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical while (true) { -#if ENABLED (JERRY_ES2015_CLASS) - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) +#if ENABLED (JERRY_ES2015) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND) { JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ - if (ecma_op_has_binding (lex_env_p, name_p)) + ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_binding)) + { + return ECMA_OBJECT_POINTER_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (has_binding)) { return lex_env_p; } @@ -68,30 +78,187 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical } } /* ecma_op_resolve_reference_base */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) /** - * Resolve super reference. + * Perform GetThisEnvironment and GetSuperBase operations * - * @return value of the reference + * See also: ECMAScript v6, 8.1.1.3.5 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_UNDEFINED - if the home object is null + * value of the [[HomeObject]].[[Prototype]] internal slot - otherwise */ -ecma_object_t * -ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */ +ecma_value_t +ecma_op_resolve_super_base (ecma_object_t *lex_env_p) /**< starting lexical environment */ { + JERRY_ASSERT (lex_env_p != NULL); + while (true) { - JERRY_ASSERT (lex_env_p != NULL); - - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND) { - return ecma_get_lex_env_binding_object (lex_env_p); + ecma_object_t *home_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u1.home_object_cp); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (home_p)) + { + return ecma_proxy_object_get_prototype_of (home_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (home_p); + + if (proto_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_NULL; + } + + ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (proto_p); + + return ecma_make_object_value (proto_p); } - JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL) + { + break; + } lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } -} /* ecma_op_resolve_super_reference_value */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_resolve_super_base */ + +/** + * Helper method for HasBindig operation + * + * See also: + * ECMA-262 v6, 8.1.1.2.1 steps 7-9; + * + * @return ECMA_VALUE_TRUE - if the property is unscopable + * ECMA_VALUE_FALSE - if a the property is not unscopable + * ECMA_VALUE_ERROR - otherwise + */ +static ecma_value_t +ecma_op_is_prop_unscopable (ecma_object_t *binding_obj_p, /**< binding object */ + ecma_string_t *prop_name_p) /**< property's name */ +{ + ecma_value_t unscopables = ecma_op_object_get_by_symbol_id (binding_obj_p, LIT_GLOBAL_SYMBOL_UNSCOPABLES); + + if (ECMA_IS_VALUE_ERROR (unscopables)) + { + return unscopables; + } + + if (ecma_is_value_object (unscopables)) + { + ecma_object_t *unscopables_obj_p = ecma_get_object_from_value (unscopables); + ecma_value_t get_unscopables_value = ecma_op_object_get (unscopables_obj_p, prop_name_p); + ecma_deref_object (unscopables_obj_p); + + if (ECMA_IS_VALUE_ERROR (get_unscopables_value)) + { + return get_unscopables_value; + } + + bool is_blocked = ecma_op_to_boolean (get_unscopables_value); + + ecma_free_value (get_unscopables_value); + + return ecma_make_boolean_value (is_blocked); + } + + ecma_free_value (unscopables); + + return ECMA_VALUE_FALSE; +} /* ecma_op_is_prop_unscopable */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Helper method for HasBindig operation + * + * See also: + * ECMA-262 v6, 8.1.1.2.1 steps 7-9; + * + * @return ECMA_VALUE_TRUE - if the property is unscopable + * ECMA_VALUE_FALSE - if a the property is not unscopable + * ECMA_VALUE_ERROR - otherwise + */ + +/** + * Resolve value corresponding to the given object environment reference. + * + * Note: the steps are already include the HasBindig operation steps + * + * See also: + * ECMA-262 v6, 8.1.1.2.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NOT_FOUND - if the binding not exists or blocked via @@unscopables + * result of the binding - otherwise + */ +ecma_value_t +ecma_op_object_bound_environment_resolve_reference_value (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_string_t *name_p) /**< variable name */ +{ + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + ecma_value_t found_binding; + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + found_binding = ecma_proxy_object_has (binding_obj_p, name_p); + + if (!ecma_is_value_true (found_binding)) + { + return ECMA_IS_VALUE_ERROR (found_binding) ? found_binding : ECMA_VALUE_NOT_FOUND; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + found_binding = ecma_op_object_find (binding_obj_p, name_p); + + if (ECMA_IS_VALUE_ERROR (found_binding) || !ecma_is_value_found (found_binding)) + { + return found_binding; + } + +#if ENABLED (JERRY_ES2015) + if (JERRY_LIKELY (lex_env_p == ecma_get_global_scope ())) +#endif /* ENABLED (JERRY_ES2015) */ + { + return found_binding; + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +#if ENABLED (JERRY_ES2015) + ecma_value_t blocked = ecma_op_is_prop_unscopable (binding_obj_p, name_p); + + if (ecma_is_value_false (blocked)) + { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + return ecma_proxy_object_get (binding_obj_p, name_p, ecma_make_object_value (binding_obj_p)); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return found_binding; + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (!ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + ecma_free_value (found_binding); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ECMA_IS_VALUE_ERROR (blocked) ? blocked : ECMA_VALUE_NOT_FOUND; +#endif /* ENABLED (JERRY_ES2015) */ +} /* ecma_op_object_bound_environment_resolve_reference_value */ /** * Resolve value corresponding to reference. @@ -114,55 +281,74 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical if (property_p != NULL) { - return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" + " initialized before reading their value.")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + return ecma_fast_copy_value (property_value_p->value); } } else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) { - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); +#if ENABLED (JERRY_ES2015) + bool lcache_lookup_allowed = (lex_env_p == ecma_get_global_environment ()); +#else /* !ENABLED (JERRY_ES2015)*/ + bool lcache_lookup_allowed = true; +#endif /* ENABLED (JERRY_ES2015) */ + if (lcache_lookup_allowed) + { #if ENABLED (JERRY_LCACHE) - ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); - if (property_p != NULL) - { - ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - - if (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) + if (property_p != NULL) { - return ecma_fast_copy_value (prop_value_p->value); + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) + { + return ecma_fast_copy_value (prop_value_p->value); + } + + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); + + ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p); + + if (get_set_pair_p->getter_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_UNDEFINED; + } + + ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp); + + ecma_value_t base_value = ecma_make_object_value (binding_obj_p); + return ecma_op_function_call (getter_p, base_value, NULL, 0); } - - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); - - ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p); - - if (get_set_pair_p->getter_cp == JMEM_CP_NULL) - { - return ECMA_VALUE_UNDEFINED; - } - - ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp); - - ecma_value_t base_value = ecma_make_object_value (binding_obj_p); - return ecma_op_function_call (getter_p, base_value, NULL, 0); - } #endif /* ENABLED (JERRY_LCACHE) */ + } - ecma_value_t prop_value = ecma_op_object_find (binding_obj_p, name_p); + ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); - if (ecma_is_value_found (prop_value)) + if (ecma_is_value_found (result)) { - return prop_value; + /* Note: the result may contains ECMA_VALUE_ERROR */ + return result; } } else { -#if ENABLED (JERRY_ES2015_CLASS) - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_UNREACHABLE (); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ } if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL) diff --git a/jerry-core/ecma/operations/ecma-reference.h b/jerry-core/ecma/operations/ecma-reference.h index 37409edb..95837976 100644 --- a/jerry-core/ecma/operations/ecma-reference.h +++ b/jerry-core/ecma/operations/ecma-reference.h @@ -28,9 +28,10 @@ ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p); ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p); -#if ENABLED (JERRY_ES2015_CLASS) -ecma_object_t *ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +ecma_value_t ecma_op_object_bound_environment_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p); +#if ENABLED (JERRY_ES2015) +ecma_value_t ecma_op_resolve_super_base (ecma_object_t *lex_env_p); +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-regexp-object.c b/jerry-core/ecma/operations/ecma-regexp-object.c index f3bcb432..82f22a46 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/jerry-core/ecma/operations/ecma-regexp-object.c @@ -15,11 +15,13 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" +#include "ecma-builtins.h" #include "ecma-builtin-helpers.h" #include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-objects.h" +#include "ecma-function-object.h" #include "ecma-regexp-object.h" #include "ecma-try-catch-macro.h" #include "jcontext.h" @@ -44,11 +46,6 @@ */ #define RE_GLOBAL_CAPTURE 0 -/** - * Check if a RegExp opcode is a capture group or not - */ -#define RE_IS_CAPTURE_GROUP(x) (((x) < RE_OP_NON_CAPTURE_GROUP_START) ? 1 : 0) - /** * Parse RegExp flags (global, ignoreCase, multiline) * @@ -64,228 +61,347 @@ ecma_regexp_parse_flags (ecma_string_t *flags_str_p, /**< Input string with flag uint16_t *flags_p) /**< [out] parsed flag bits */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; + uint16_t result_flags = RE_FLAG_EMPTY; ECMA_STRING_TO_UTF8_STRING (flags_str_p, flags_start_p, flags_start_size); const lit_utf8_byte_t *flags_str_curr_p = flags_start_p; const lit_utf8_byte_t *flags_str_end_p = flags_start_p + flags_start_size; - while (flags_str_curr_p < flags_str_end_p - && ecma_is_value_empty (ret_value)) + while (flags_str_curr_p < flags_str_end_p) { + ecma_regexp_flags_t flag; switch (*flags_str_curr_p++) { case 'g': { - if (*flags_p & RE_FLAG_GLOBAL) - { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp flags.")); - } - *flags_p |= RE_FLAG_GLOBAL; + flag = RE_FLAG_GLOBAL; break; } case 'i': { - if (*flags_p & RE_FLAG_IGNORE_CASE) - { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp flags.")); - } - *flags_p |= RE_FLAG_IGNORE_CASE; + flag = RE_FLAG_IGNORE_CASE; break; } case 'm': { - if (*flags_p & RE_FLAG_MULTILINE) - { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp flags.")); - } - *flags_p |= RE_FLAG_MULTILINE; + flag = RE_FLAG_MULTILINE; + break; + } + case 'y': + { + flag = RE_FLAG_STICKY; + break; + } + case 'u': + { + flag = RE_FLAG_UNICODE; break; } default: { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp flags.")); + flag = RE_FLAG_EMPTY; break; } } + + if (flag == RE_FLAG_EMPTY || (result_flags & flag) != 0) + { + ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp flags.")); + break; + } + + result_flags = (uint16_t) (result_flags | flag); } ECMA_FINALIZE_UTF8_STRING (flags_start_p, flags_start_size); + *flags_p = result_flags; return ret_value; } /* ecma_regexp_parse_flags */ +#if !ENABLED (JERRY_ES2015) /* * Create the properties of a RegExp instance. */ static void -ecma_regexp_create_props (ecma_object_t *re_object_p) /**< RegExp object */ +ecma_regexp_create_props (ecma_object_t *re_object_p, /**< RegExp object */ + ecma_string_t *source_p, /**< source string */ + uint16_t flags) /**< flags */ { -#if !ENABLED (JERRY_ES2015) - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL), - ECMA_PROPERTY_FIXED, - NULL); - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE), - ECMA_PROPERTY_FIXED, - NULL); -#endif /* !ENABLED (JERRY_ES2015) */ - ecma_create_named_data_property (re_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), - ECMA_PROPERTY_FLAG_WRITABLE, - NULL); + ecma_property_value_t *prop_value_p; + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE), + ECMA_PROPERTY_FIXED, + NULL); + + ecma_ref_ecma_string (source_p); + prop_value_p->value = ecma_make_string_value (source_p); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_GLOBAL); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE); + + prop_value_p = ecma_create_named_data_property (re_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE), + ECMA_PROPERTY_FIXED, + NULL); + + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_MULTILINE); } /* ecma_regexp_create_props */ /* - * Helper function to assign a value to a property + * Update the properties of a RegExp instance. */ static void -ecma_regexp_helper_assign_prop (ecma_object_t *re_object_p, /**< RegExp object */ - lit_magic_string_id_t prop_id, /**< property name ide */ - ecma_value_t value) /**< value */ +ecma_regexp_update_props (ecma_object_t *re_object_p, /**< RegExp object */ + ecma_string_t *source_p, /**< source string */ + uint16_t flags) /**< flags */ { - ecma_property_ref_t property_ref; - ecma_op_object_get_own_property (re_object_p, - ecma_get_magic_string (prop_id), - &property_ref, - ECMA_PROPERTY_GET_VALUE); - ecma_named_data_property_assign_value (re_object_p, - property_ref.value_p, - value); -} /* ecma_regexp_helper_assign_prop */ + ecma_property_t *prop_p; -/** - * Initializes the properties of a RegExp instance. - */ -void -ecma_regexp_initialize_props (ecma_object_t *re_object_p, /**< RegExp object */ - ecma_string_t *source_p, /**< source string */ - uint16_t flags) /**< flags */ -{ -#if !ENABLED (JERRY_ES2015) - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_SOURCE, - ecma_make_string_value (source_p)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE)); + JERRY_ASSERT (prop_p != NULL); + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + ecma_free_value (prop_value_p->value); + ecma_ref_ecma_string (source_p); + prop_value_p->value = ecma_make_string_value (source_p); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_GLOBAL, - ecma_make_boolean_value (flags & RE_FLAG_GLOBAL)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_GLOBAL); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_IGNORECASE_UL, - ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE)); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE); - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_MULTILINE, - ecma_make_boolean_value (flags & RE_FLAG_MULTILINE)); -#else /* ENABLED (JERRY_ES2015) */ - JERRY_UNUSED (source_p); - JERRY_UNUSED (flags); + prop_p = ecma_find_named_property (re_object_p, ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE)); + JERRY_ASSERT (prop_p != NULL); + prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + prop_value_p->value = ecma_make_boolean_value (flags & RE_FLAG_MULTILINE); +} /* ecma_regexp_update_props */ #endif /* !ENABLED (JERRY_ES2015) */ - ecma_regexp_helper_assign_prop (re_object_p, - LIT_MAGIC_STRING_LASTINDEX_UL, - ecma_make_uint32_value (0)); -} /* ecma_regexp_initialize_props */ - /** - * RegExp object creation operation. + * RegExpAlloc method * * See also: ECMA-262 v5, 15.10.4.1 + * ECMA-262 v6, 21.2.3.2.1 * - * @return constructed RegExp object - * Returned value must be freed with ecma_free_value + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return ecma_object_t */ -ecma_value_t -ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p) /**< RegExp bytecode */ +ecma_object_t * +ecma_op_regexp_alloc (ecma_object_t *ctr_obj_p) /**< constructor object pointer */ { - JERRY_ASSERT (bytecode_p != NULL); - - ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); - - ecma_object_t *object_p = ecma_create_object (re_prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); - - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - /* Set the internal [[Class]] property */ - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; - - /* Set bytecode internal property. */ - ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bytecode_p); - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p); - - /* Create and initialize RegExp object properties */ - ecma_regexp_create_props (object_p); - ecma_regexp_initialize_props (object_p, - ecma_get_string_from_value (bytecode_p->source), - bytecode_p->header.status_flags); - - return ecma_make_object_value (object_p); -} /* ecma_op_create_regexp_object_from_bytecode */ - -/** - * RegExp object creation operation. - * - * See also: ECMA-262 v5, 15.10.4.1 - * - * @return constructed RegExp object - if pattern and flags were parsed successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value - */ -ecma_value_t -ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */ - uint16_t flags) /**< flags */ -{ - JERRY_ASSERT (pattern_p != NULL); - - ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); - - ecma_object_t *object_p = ecma_create_object (re_prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED; - - ecma_regexp_create_props (object_p); - ecma_regexp_initialize_props (object_p, pattern_p, flags); - - /* Compile bytecode. */ - const re_compiled_code_t *bc_p = NULL; - ecma_value_t ret_value = re_compile_bytecode (&bc_p, pattern_p, flags); - if (ECMA_IS_VALUE_ERROR (ret_value)) +#if ENABLED (JERRY_ES2015) + if (ctr_obj_p == NULL) { - ecma_deref_object (object_p); - return ret_value; + ctr_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP); } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); + ecma_object_t *proto_obj_p = ecma_op_get_prototype_from_constructor (ctr_obj_p, + ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); - /* Set [[Class]] and bytecode internal properties. */ - ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; - ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, bc_p); + if (JERRY_UNLIKELY (proto_obj_p == NULL)) + { + return proto_obj_p; + } - return ecma_make_object_value (object_p); -} /* ecma_op_create_regexp_object */ +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (ctr_obj_p); + ecma_object_t *proto_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *new_object_p = ecma_create_object (proto_obj_p, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + +#if ENABLED (JERRY_ES2015) + ecma_deref_object (proto_obj_p); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_extended_object_t *regexp_obj_p = (ecma_extended_object_t *) new_object_p; + + /* Class id will be initialized after the bytecode is compiled. */ + regexp_obj_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED; + + ecma_value_t status = ecma_builtin_helper_def_prop (new_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROP_IS_THROW); + + JERRY_ASSERT (ecma_is_value_true (status)); + + return new_object_p; +} /* ecma_op_regexp_alloc */ + +/** + * Helper method for initializing an aready existing RegExp object. + */ +static void +ecma_op_regexp_initialize (ecma_object_t *regexp_obj_p, /**< RegExp object */ + const re_compiled_code_t *bc_p, /**< bytecode */ + ecma_string_t *pattern_str_p, /**< pattern */ + uint16_t flags) /**< flags */ +{ + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) regexp_obj_p; + +#if !ENABLED (JERRY_ES2015) + if (ext_obj_p->u.class_prop.class_id == LIT_MAGIC_STRING_UNDEFINED) + { + /* This instance has not been initialized before. */ + ecma_regexp_create_props (regexp_obj_p, pattern_str_p, flags); + } + else + { + ecma_regexp_update_props (regexp_obj_p, pattern_str_p, flags); + } +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) + JERRY_UNUSED (pattern_str_p); + JERRY_UNUSED (flags); +#endif /* ENABLED (JERRY_ES2015) */ + + ext_obj_p->u.class_prop.class_id = LIT_MAGIC_STRING_REGEXP_UL; + ECMA_SET_INTERNAL_VALUE_POINTER (ext_obj_p->u.class_prop.u.value, bc_p); +} /* ecma_op_regexp_initialize */ + +/** + * Method for creating a RegExp object from pattern. + * + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. + * + * @return ecma_value_t + */ +ecma_value_t +ecma_op_create_regexp_from_pattern (ecma_object_t *regexp_obj_p, /**< RegExp object */ + ecma_value_t pattern_value, /**< pattern */ + ecma_value_t flags_value) /**< flags */ +{ + ecma_string_t *pattern_str_p = ecma_regexp_read_pattern_str_helper (pattern_value); + uint16_t flags = 0; + + if (JERRY_UNLIKELY (pattern_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + if (!ecma_is_value_undefined (flags_value)) + { + ecma_string_t *flags_str_p = ecma_op_to_string (flags_value); + + if (JERRY_UNLIKELY (flags_str_p == NULL)) + { + ecma_deref_ecma_string (pattern_str_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t parse_flags_value = ecma_regexp_parse_flags (flags_str_p, &flags); + ecma_deref_ecma_string (flags_str_p); + + if (ECMA_IS_VALUE_ERROR (parse_flags_value)) + { + ecma_deref_ecma_string (pattern_str_p); + return parse_flags_value; + } + + JERRY_ASSERT (ecma_is_value_empty (parse_flags_value)); + } + + re_compiled_code_t *bc_p = re_compile_bytecode (pattern_str_p, flags); + + if (JERRY_UNLIKELY (bc_p == NULL)) + { + ecma_deref_ecma_string (pattern_str_p); + return ECMA_VALUE_ERROR; + } + + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); + ecma_deref_ecma_string (pattern_str_p); + + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_from_pattern */ + +/** + * Method for creating a RegExp object from bytecode. + * + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. + * + * @return ecma_value_t + */ +ecma_value_t +ecma_op_create_regexp_from_bytecode (ecma_object_t *regexp_obj_p, /**< RegExp object */ + re_compiled_code_t *bc_p) /**< bytecode */ +{ + ecma_bytecode_ref ((ecma_compiled_code_t *) bc_p); + ecma_string_t *pattern_str_p = ecma_get_string_from_value (bc_p->source); + uint16_t flags = bc_p->header.status_flags; + + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); + + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_from_bytecode */ + +/** + * Method for creating a RegExp object from pattern with already parsed flags. + * + * Note: + * Allocation have to happen before invoking this function using ecma_op_regexp_alloc. + * + * @return ecma_value_t + */ +ecma_value_t +ecma_op_create_regexp_with_flags (ecma_object_t *regexp_obj_p, /**< RegExp object */ + ecma_value_t pattern_value, /**< pattern */ + uint16_t flags) /**< flags */ +{ + ecma_string_t *pattern_str_p = ecma_regexp_read_pattern_str_helper (pattern_value); + + if (JERRY_UNLIKELY (pattern_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + re_compiled_code_t *bc_p = re_compile_bytecode (pattern_str_p, flags); + ecma_deref_ecma_string (pattern_str_p); + + if (JERRY_UNLIKELY (bc_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_op_regexp_initialize (regexp_obj_p, bc_p, pattern_str_p, flags); + + return ecma_make_object_value (regexp_obj_p); +} /* ecma_op_create_regexp_with_flags */ /** * Canonicalize a character * * @return ecma_char_t canonicalized character */ -ecma_char_t -ecma_regexp_canonicalize_char (ecma_char_t ch) /**< character */ +lit_code_point_t +ecma_regexp_canonicalize_char (lit_code_point_t ch, /**< character */ + bool unicode) /**< unicode */ { if (JERRY_LIKELY (ch <= LIT_UTF8_1_BYTE_CODE_POINT_MAX)) { @@ -297,24 +413,30 @@ ecma_regexp_canonicalize_char (ecma_char_t ch) /**< character */ return ch; } - ecma_char_t u[LIT_MAXIMUM_OTHER_CASE_LENGTH]; - const ecma_length_t size = lit_char_to_upper_case (ch, u, LIT_MAXIMUM_OTHER_CASE_LENGTH); +#if ENABLED (JERRY_ES2015) + /* TODO: Implement case folding for code points in the upper planes. */ + if (JERRY_UNLIKELY (ch > LIT_UTF16_CODE_UNIT_MAX)) + { + return ch; + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_char_t u[LIT_MAXIMUM_OTHER_CASE_LENGTH]; + const ecma_length_t size = lit_char_to_upper_case ((ecma_char_t) ch, u, LIT_MAXIMUM_OTHER_CASE_LENGTH); - /* 3. */ if (size != 1) { return ch; } - /* 4. */ + const ecma_char_t cu = u[0]; - /* 5. */ - if (cu >= 128) + if (cu <= LIT_UTF8_1_BYTE_CODE_POINT_MAX && !unicode) { /* 6. */ - return cu; + return ch; } - return ch; + return cu; } /* ecma_regexp_canonicalize_char */ /** @@ -324,31 +446,159 @@ ecma_regexp_canonicalize_char (ecma_char_t ch) /**< character */ * * @return ecma_char_t canonicalized character */ -inline ecma_char_t JERRY_ATTR_ALWAYS_INLINE -ecma_regexp_canonicalize (ecma_char_t ch, /**< character */ - bool is_ignorecase) /**< IgnoreCase flag */ +static inline lit_code_point_t JERRY_ATTR_ALWAYS_INLINE +ecma_regexp_canonicalize (lit_code_point_t ch, /**< character */ + uint16_t flags) /**< flags */ { - if (is_ignorecase) + if (flags & RE_FLAG_IGNORE_CASE) { - return ecma_regexp_canonicalize_char (ch); + return ecma_regexp_canonicalize_char (ch, flags & RE_FLAG_UNICODE); } return ch; } /* ecma_regexp_canonicalize */ /** - * Recursive function for RegExp matching. + * Check if a code point is matched by a class escape. + * + * @return true, if code point matches escape + * false, otherwise + */ +static bool +ecma_regexp_check_class_escape (lit_code_point_t cp, /**< char */ + ecma_class_escape_t escape) /**< escape */ +{ + switch (escape) + { + case RE_ESCAPE_DIGIT: + { + return (cp >= LIT_CHAR_0 && cp <= LIT_CHAR_9); + } + case RE_ESCAPE_NOT_DIGIT: + { + return (cp < LIT_CHAR_0 || cp > LIT_CHAR_9); + } + case RE_ESCAPE_WORD_CHAR: + { + return lit_char_is_word_char (cp); + } + case RE_ESCAPE_NOT_WORD_CHAR: + { + return !lit_char_is_word_char (cp); + } + case RE_ESCAPE_WHITESPACE: + { + return lit_char_is_white_space ((ecma_char_t) cp); + } + case RE_ESCAPE_NOT_WHITESPACE: + { + return !lit_char_is_white_space ((ecma_char_t) cp); + } + default: + { + JERRY_UNREACHABLE (); + } + } +} /* ecma_regexp_check_class_escape */ + +/** + * Helper function to get current code point or code unit depending on execution mode, + * and advance the string pointer. + * + * @return lit_code_point_t current code point + */ +static lit_code_point_t +ecma_regexp_advance (ecma_regexp_ctx_t *re_ctx_p, /**< regexp context */ + const lit_utf8_byte_t **str_p) /**< reference to string pointer */ +{ + JERRY_ASSERT (str_p != NULL); + lit_code_point_t cp = lit_cesu8_read_next (str_p); + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (re_ctx_p->flags & RE_FLAG_UNICODE) + && lit_is_code_point_utf16_high_surrogate ((ecma_char_t) cp) + && *str_p < re_ctx_p->input_end_p) + { + const ecma_char_t next_ch = lit_cesu8_peek_next (*str_p); + if (lit_is_code_point_utf16_low_surrogate (next_ch)) + { + cp = lit_convert_surrogate_pair_to_code_point ((ecma_char_t) cp, next_ch); + *str_p += LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + return ecma_regexp_canonicalize (cp, re_ctx_p->flags); +} /* ecma_regexp_advance */ + +#if ENABLED (JERRY_ES2015) +/** + * Helper function to get current full unicode code point and advance the string pointer. + * + * @return lit_code_point_t current code point + */ +lit_code_point_t +ecma_regexp_unicode_advance (const lit_utf8_byte_t **str_p, /**< reference to string pointer */ + const lit_utf8_byte_t *end_p) /**< string end pointer */ +{ + JERRY_ASSERT (str_p != NULL); + const lit_utf8_byte_t *current_p = *str_p; + + lit_code_point_t ch = lit_cesu8_read_next (¤t_p); + if (lit_is_code_point_utf16_high_surrogate ((ecma_char_t) ch) + && current_p < end_p) + { + const ecma_char_t next_ch = lit_cesu8_peek_next (current_p); + if (lit_is_code_point_utf16_low_surrogate (next_ch)) + { + ch = lit_convert_surrogate_pair_to_code_point ((ecma_char_t) ch, next_ch); + current_p += LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; + } + } + + *str_p = current_p; + return ch; +} /* ecma_regexp_unicode_advance */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Helper function to revert the string pointer to the previous code point. + * + * @return pointer to previous code point + */ +static JERRY_ATTR_NOINLINE const lit_utf8_byte_t * +ecma_regexp_step_back (ecma_regexp_ctx_t *re_ctx_p, /**< regexp context */ + const lit_utf8_byte_t *str_p) /**< reference to string pointer */ +{ + JERRY_ASSERT (str_p != NULL); +#if ENABLED (JERRY_ES2015) + lit_code_point_t ch = lit_cesu8_read_prev (&str_p); + if (JERRY_UNLIKELY (re_ctx_p->flags & RE_FLAG_UNICODE) + && lit_is_code_point_utf16_low_surrogate (ch) + && lit_is_code_point_utf16_high_surrogate (lit_cesu8_peek_prev (str_p))) + { + str_p -= LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (re_ctx_p); + lit_utf8_decr (&str_p); +#endif /* !ENABLED (JERRY_ES2015) */ + return str_p; +} /* ecma_regexp_step_back */ + +/** + * Recursive function for executing RegExp bytecode. * * See also: * ECMA-262 v5, 15.10.2.1 * - * @return true - if matched - * false - otherwise + * @return pointer to the end of the currently matched substring + * NULL, if pattern did not match */ static const lit_utf8_byte_t * -ecma_regexp_match (ecma_regexp_ctx_t *re_ctx_p, /**< RegExp matcher context */ - const uint8_t *bc_p, /**< pointer to the current RegExp bytecode */ - const lit_utf8_byte_t *str_curr_p) /**< input string pointer */ +ecma_regexp_run (ecma_regexp_ctx_t *re_ctx_p, /**< RegExp matcher context */ + const uint8_t *bc_p, /**< pointer to the current RegExp bytecode */ + const lit_utf8_byte_t *str_curr_p) /**< input string pointer */ { #if (JERRY_STACK_LIMIT != 0) if (JERRY_UNLIKELY (ecma_get_current_stack_usage () > CONFIG_MEM_STACK_LIMIT)) @@ -357,695 +607,993 @@ ecma_regexp_match (ecma_regexp_ctx_t *re_ctx_p, /**< RegExp matcher context */ } #endif /* JERRY_STACK_LIMIT != 0 */ + const lit_utf8_byte_t *str_start_p = str_curr_p; + const uint8_t *next_alternative_p = NULL; + while (true) { - re_opcode_t op = re_get_opcode (&bc_p); + const re_opcode_t op = re_get_opcode (&bc_p); switch (op) { - case RE_OP_MATCH: + case RE_OP_EOF: + { + re_ctx_p->captures_p[RE_GLOBAL_CAPTURE].end_p = str_curr_p; + /* FALLTHRU */ + } + case RE_OP_ASSERT_END: + case RE_OP_ITERATOR_END: { - JERRY_TRACE_MSG ("Execute RE_OP_MATCH: match\n"); return str_curr_p; } + case RE_OP_ALTERNATIVE_START: + { + const uint32_t offset = re_get_value (&bc_p); + next_alternative_p = bc_p + offset; + continue; + } + case RE_OP_ALTERNATIVE_NEXT: + { + while (true) + { + const uint32_t offset = re_get_value (&bc_p); + bc_p += offset; + + if (*bc_p != RE_OP_ALTERNATIVE_NEXT) + { + break; + } + + bc_p++; + } + + continue; + } + case RE_OP_NO_ALTERNATIVE: + { + return NULL; + } + case RE_OP_CAPTURING_GROUP_START: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_capture_t *const group_p = re_ctx_p->captures_p + group_idx; + group_p->subcapture_count = re_get_value (&bc_p); + + const lit_utf8_byte_t *const saved_begin_p = group_p->begin_p; + const lit_utf8_byte_t *const saved_end_p = group_p->end_p; + const uint32_t saved_iterator = group_p->iterator; + + const uint32_t qmin = re_get_value (&bc_p); + group_p->end_p = NULL; + + /* If zero iterations are allowed, then execute the end opcode which will handle further iterations, + * otherwise run the 1st iteration immediately by executing group bytecode. */ + if (qmin == 0) + { + group_p->iterator = 0; + group_p->begin_p = NULL; + const uint32_t end_offset = re_get_value (&bc_p); + group_p->bc_p = bc_p; + + bc_p += end_offset; + } + else + { + group_p->iterator = 1; + group_p->begin_p = str_curr_p; + group_p->bc_p = bc_p; + } + + const lit_utf8_byte_t *matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + group_p->iterator = saved_iterator; + + if (matched_p == NULL) + { + group_p->begin_p = saved_begin_p; + group_p->end_p = saved_end_p; + goto fail; + } + + return matched_p; + } + case RE_OP_NON_CAPTURING_GROUP_START: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_non_capture_t *const group_p = re_ctx_p->non_captures_p + group_idx; + + group_p->subcapture_start = re_get_value (&bc_p); + group_p->subcapture_count = re_get_value (&bc_p); + + const uint32_t saved_iterator = group_p->iterator; + const uint32_t qmin = re_get_value (&bc_p); + + /* If zero iterations are allowed, then execute the end opcode which will handle further iterations, + * otherwise run the 1st iteration immediately by executing group bytecode. */ + if (qmin == 0) + { + group_p->iterator = 0; + group_p->begin_p = NULL; + const uint32_t end_offset = re_get_value (&bc_p); + group_p->bc_p = bc_p; + + bc_p += end_offset; + } + else + { + group_p->iterator = 1; + group_p->begin_p = str_curr_p; + group_p->bc_p = bc_p; + } + + const lit_utf8_byte_t *matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + group_p->iterator = saved_iterator; + + if (matched_p == NULL) + { + goto fail; + } + + return matched_p; + } + case RE_OP_GREEDY_CAPTURING_GROUP_END: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_capture_t *const group_p = re_ctx_p->captures_p + group_idx; + const uint32_t qmin = re_get_value (&bc_p); + + if (group_p->iterator < qmin) + { + /* No need to save begin_p since we don't have to backtrack beyond the minimum iteration count, but we have + * to clear nested capturing groups. */ + group_p->begin_p = str_curr_p; + for (uint32_t i = 1; i < group_p->subcapture_count; ++i) + { + group_p[i].begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + group_p->iterator--; + goto fail; + } + + /* Empty matches are not allowed after reaching the minimum number of iterations. */ + if (JERRY_UNLIKELY (group_p->begin_p >= str_curr_p) && (group_p->iterator > qmin)) + { + goto fail; + } + + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + if (JERRY_UNLIKELY (group_p->iterator >= qmax)) + { + /* Reached maximum number of iterations, try to match tail bytecode. */ + group_p->end_p = str_curr_p; + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + goto fail; + } + + { + /* Save and clear all nested capturing groups, and try to iterate. */ + JERRY_VLA (const lit_utf8_byte_t *, saved_captures_p, group_p->subcapture_count); + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + saved_captures_p[i] = group_p[i].begin_p; + group_p[i].begin_p = NULL; + } + + group_p->iterator++; + group_p->begin_p = str_curr_p; + + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + /* Failed to iterate again, backtrack to current match, and try to run tail bytecode. */ + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + group_p[i].begin_p = saved_captures_p[i]; + } + + group_p->iterator--; + group_p->end_p = str_curr_p; + } + + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + goto fail; + } + case RE_OP_GREEDY_NON_CAPTURING_GROUP_END: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_non_capture_t *const group_p = re_ctx_p->non_captures_p + group_idx; + const uint32_t qmin = re_get_value (&bc_p); + + if (group_p->iterator < qmin) + { + /* No need to save begin_p but we have to clear nested capturing groups. */ + group_p->begin_p = str_curr_p; + + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start; + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + capture_p[i].begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + group_p->iterator--; + goto fail; + } + + /* Empty matches are not allowed after reaching the minimum number of iterations. */ + if (JERRY_UNLIKELY (group_p->begin_p >= str_curr_p) && (group_p->iterator > qmin)) + { + goto fail; + } + + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + if (JERRY_UNLIKELY (group_p->iterator >= qmax)) + { + /* Reached maximum number of iterations, try to match tail bytecode. */ + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + goto fail; + } + + { + /* Save and clear all nested capturing groups, and try to iterate. */ + JERRY_VLA (const lit_utf8_byte_t *, saved_captures_p, group_p->subcapture_count); + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start + i; + saved_captures_p[i] = capture_p->begin_p; + capture_p->begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const saved_begin_p = group_p->begin_p; + group_p->begin_p = str_curr_p; + + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + /* Failed to iterate again, backtrack to current match, and try to run tail bytecode. */ + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start + i; + capture_p->begin_p = saved_captures_p[i]; + } + + group_p->iterator--; + group_p->begin_p = saved_begin_p; + } + + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + goto fail; + } + case RE_OP_LAZY_CAPTURING_GROUP_END: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_capture_t *const group_p = re_ctx_p->captures_p + group_idx; + const uint32_t qmin = re_get_value (&bc_p); + + if (group_p->iterator < qmin) + { + /* No need to save begin_p but we have to clear nested capturing groups. */ + group_p->begin_p = str_curr_p; + for (uint32_t i = 1; i < group_p->subcapture_count; ++i) + { + group_p[i].begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + group_p->iterator--; + goto fail; + } + + /* Empty matches are not allowed after reaching the minimum number of iterations. */ + if (JERRY_UNLIKELY (group_p->begin_p >= str_curr_p) && (group_p->iterator > qmin)) + { + goto fail; + } + + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + group_p->end_p = str_curr_p; + + /* Try to match tail bytecode. */ + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + if (JERRY_UNLIKELY (group_p->iterator >= qmax)) + { + /* Reached maximum number of iterations and tail bytecode did not match. */ + goto fail; + } + + { + /* Save and clear all nested capturing groups, and try to iterate. */ + JERRY_VLA (const lit_utf8_byte_t *, saved_captures_p, group_p->subcapture_count); + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + saved_captures_p[i] = group_p[i].begin_p; + group_p[i].begin_p = NULL; + } + + group_p->iterator++; + group_p->begin_p = str_curr_p; + + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + /* Backtrack to current match. */ + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + group_p[i].begin_p = saved_captures_p[i]; + } + + group_p->iterator--; + } + + goto fail; + } + case RE_OP_LAZY_NON_CAPTURING_GROUP_END: + { + const uint32_t group_idx = re_get_value (&bc_p); + ecma_regexp_non_capture_t *const group_p = re_ctx_p->non_captures_p + group_idx; + const uint32_t qmin = re_get_value (&bc_p); + + if (group_p->iterator < qmin) + { + /* Clear nested captures. */ + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start; + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + capture_p[i].begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + group_p->iterator--; + goto fail; + } + + /* Empty matches are not allowed after reaching the minimum number of iterations. */ + if (JERRY_UNLIKELY (group_p->begin_p >= str_curr_p) && (group_p->iterator > qmin)) + { + goto fail; + } + + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + + /* Try to match tail bytecode. */ + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + if (JERRY_UNLIKELY (group_p->iterator >= qmax)) + { + /* Reached maximum number of iterations and tail bytecode did not match. */ + goto fail; + } + + { + /* Save and clear all nested capturing groups, and try to iterate. */ + JERRY_VLA (const lit_utf8_byte_t *, saved_captures_p, group_p->subcapture_count); + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start + i; + saved_captures_p[i] = capture_p->begin_p; + capture_p->begin_p = NULL; + } + + group_p->iterator++; + const lit_utf8_byte_t *const saved_begin_p = group_p->begin_p; + group_p->begin_p = str_curr_p; + + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, group_p->bc_p, str_curr_p); + + if (matched_p != NULL) + { + return matched_p; + } + + /* Backtrack to current match. */ + for (uint32_t i = 0; i < group_p->subcapture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + group_p->subcapture_start + i; + capture_p->begin_p = saved_captures_p[i]; + } + + group_p->iterator--; + group_p->begin_p = saved_begin_p; + } + + goto fail; + } + case RE_OP_GREEDY_ITERATOR: + { + const uint32_t qmin = re_get_value (&bc_p); + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + const uint32_t end_offset = re_get_value (&bc_p); + + uint32_t iterator = 0; + while (iterator < qmin) + { + str_curr_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (str_curr_p == NULL) + { + goto fail; + } + + if (ECMA_RE_STACK_LIMIT_REACHED (str_curr_p)) + { + return str_curr_p; + } + + iterator++; + } + + while (iterator < qmax) + { + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (matched_p == NULL) + { + break; + } + + if (ECMA_RE_STACK_LIMIT_REACHED (str_curr_p)) + { + return str_curr_p; + } + + str_curr_p = matched_p; + iterator++; + } + + const uint8_t *const tail_bc_p = bc_p + end_offset; + while (true) + { + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, tail_bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + if (JERRY_UNLIKELY (iterator <= qmin)) + { + goto fail; + } + + iterator--; + JERRY_ASSERT (str_curr_p > re_ctx_p->input_start_p); + str_curr_p = ecma_regexp_step_back (re_ctx_p, str_curr_p); + } + + JERRY_UNREACHABLE (); + } + case RE_OP_LAZY_ITERATOR: + { + const uint32_t qmin = re_get_value (&bc_p); + const uint32_t qmax = re_get_value (&bc_p) - RE_QMAX_OFFSET; + const uint32_t end_offset = re_get_value (&bc_p); + + uint32_t iterator = 0; + while (iterator < qmin) + { + str_curr_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (str_curr_p == NULL) + { + goto fail; + } + + if (ECMA_RE_STACK_LIMIT_REACHED (str_curr_p)) + { + return str_curr_p; + } + + iterator++; + } + + const uint8_t *const tail_bc_p = bc_p + end_offset; + while (true) + { + const lit_utf8_byte_t *const tail_match_p = ecma_regexp_run (re_ctx_p, tail_bc_p, str_curr_p); + + if (tail_match_p != NULL) + { + return tail_match_p; + } + + if (JERRY_UNLIKELY (iterator >= qmax)) + { + goto fail; + } + + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (matched_p == NULL) + { + goto fail; + } + + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + return matched_p; + } + + iterator++; + str_curr_p = matched_p; + } + + JERRY_UNREACHABLE (); + } + case RE_OP_BACKREFERENCE: + { + const uint32_t backref_idx = re_get_value (&bc_p); + JERRY_ASSERT (backref_idx >= 1 && backref_idx < re_ctx_p->captures_count); + const ecma_regexp_capture_t *capture_p = re_ctx_p->captures_p + backref_idx; + + if (!ECMA_RE_IS_CAPTURE_DEFINED (capture_p) || capture_p->end_p <= capture_p->begin_p) + { + /* Undefined or zero length captures always match. */ + continue; + } + + const lit_utf8_size_t capture_size = (lit_utf8_size_t) (capture_p->end_p - capture_p->begin_p); + + if (str_curr_p + capture_size > re_ctx_p->input_end_p + || memcmp (str_curr_p, capture_p->begin_p, capture_size)) + { + goto fail; + } + + str_curr_p += capture_size; + continue; + } + case RE_OP_ASSERT_LINE_START: + { + if (str_curr_p <= re_ctx_p->input_start_p) + { + continue; + } + + if (!(re_ctx_p->flags & RE_FLAG_MULTILINE) || !lit_char_is_line_terminator (lit_cesu8_peek_prev (str_curr_p))) + { + goto fail; + } + + continue; + } + case RE_OP_ASSERT_LINE_END: + { + if (str_curr_p >= re_ctx_p->input_end_p) + { + continue; + } + + if (!(re_ctx_p->flags & RE_FLAG_MULTILINE) || !lit_char_is_line_terminator (lit_cesu8_peek_next (str_curr_p))) + { + goto fail; + } + + continue; + } + case RE_OP_ASSERT_WORD_BOUNDARY: + { + const bool is_wordchar_left = ((str_curr_p > re_ctx_p->input_start_p) + && lit_char_is_word_char (str_curr_p[-1])); + + const bool is_wordchar_right = ((str_curr_p < re_ctx_p->input_end_p) + && lit_char_is_word_char (str_curr_p[0])); + if (is_wordchar_right == is_wordchar_left) + { + goto fail; + } + + continue; + } + case RE_OP_ASSERT_NOT_WORD_BOUNDARY: + { + const bool is_wordchar_left = ((str_curr_p > re_ctx_p->input_start_p) + && lit_char_is_word_char (str_curr_p[-1])); + + const bool is_wordchar_right = ((str_curr_p < re_ctx_p->input_end_p) + && lit_char_is_word_char (str_curr_p[0])); + if (is_wordchar_right != is_wordchar_left) + { + goto fail; + } + + continue; + } + case RE_OP_ASSERT_LOOKAHEAD_POS: + { + const uint8_t qmin = re_get_byte (&bc_p); + const uint32_t capture_start = re_get_value (&bc_p); + const uint32_t capture_count = re_get_value (&bc_p); + const uint32_t end_offset = re_get_value (&bc_p); + + /* If qmin is zero, the assertion implicitly matches. */ + if (qmin == 0) + { + bc_p += end_offset; + continue; + } + + /* Capture end pointers might get clobbered and need to be restored after a tail match fail. */ + JERRY_VLA (const lit_utf8_byte_t *, saved_captures_p, capture_count); + for (uint32_t i = 0; i < capture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + capture_start + i; + saved_captures_p[i] = capture_p->end_p; + } + + /* The first iteration will decide whether the assertion matches depending on whether + * the iteration matched or not. */ + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + return matched_p; + } + + if (matched_p == NULL) + { + goto fail; + } + + const lit_utf8_byte_t *tail_match_p = ecma_regexp_run (re_ctx_p, bc_p + end_offset, str_curr_p); + + if (tail_match_p == NULL) + { + for (uint32_t i = 0; i < capture_count; ++i) + { + ecma_regexp_capture_t *const capture_p = re_ctx_p->captures_p + capture_start + i; + capture_p->begin_p = NULL; + capture_p->end_p = saved_captures_p[i]; + } + + goto fail; + } + + return tail_match_p; + } + case RE_OP_ASSERT_LOOKAHEAD_NEG: + { + const uint8_t qmin = re_get_byte (&bc_p); + uint32_t capture_idx = re_get_value (&bc_p); + const uint32_t capture_count = re_get_value (&bc_p); + const uint32_t end_offset = re_get_value (&bc_p); + + /* If qmin is zero, the assertion implicitly matches. */ + if (qmin > 0) + { + /* The first iteration will decide whether the assertion matches depending on whether + * the iteration matched or not. */ + const lit_utf8_byte_t *const matched_p = ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); + + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + return matched_p; + } + + if (matched_p != NULL) + { + /* Nested capturing groups inside a negative lookahead can never capture, so we clear their results. */ + const uint32_t capture_end = capture_idx + capture_count; + while (capture_idx < capture_end) + { + re_ctx_p->captures_p[capture_idx++].begin_p = NULL; + } + + goto fail; + } + } + + bc_p += end_offset; + continue; + } + case RE_OP_CLASS_ESCAPE: + { + if (str_curr_p >= re_ctx_p->input_end_p) + { + goto fail; + } + + const lit_code_point_t cp = ecma_regexp_advance (re_ctx_p, &str_curr_p); + + const ecma_class_escape_t escape = (ecma_class_escape_t) re_get_byte (&bc_p); + if (!ecma_regexp_check_class_escape (cp, escape)) + { + goto fail; + } + + continue; + } + case RE_OP_CHAR_CLASS: + { + if (str_curr_p >= re_ctx_p->input_end_p) + { + goto fail; + } + + uint8_t flags = re_get_byte (&bc_p); + uint32_t char_count = (flags & RE_CLASS_HAS_CHARS) ? re_get_value (&bc_p) : 0; + uint32_t range_count = (flags & RE_CLASS_HAS_RANGES) ? re_get_value (&bc_p) : 0; + + const lit_code_point_t cp = ecma_regexp_advance (re_ctx_p, &str_curr_p); + + uint8_t escape_count = flags & RE_CLASS_ESCAPE_COUNT_MASK; + while (escape_count > 0) + { + escape_count--; + const ecma_class_escape_t escape = re_get_byte (&bc_p); + if (ecma_regexp_check_class_escape (cp, escape)) + { + goto class_found; + } + } + + while (char_count > 0) + { + char_count--; + const lit_code_point_t curr = re_get_char (&bc_p, re_ctx_p->flags & RE_FLAG_UNICODE); + if (cp == curr) + { + goto class_found; + } + } + + while (range_count > 0) + { + range_count--; + const lit_code_point_t begin = re_get_char (&bc_p, re_ctx_p->flags & RE_FLAG_UNICODE); + + if (cp < begin) + { + bc_p += re_ctx_p->char_size; + continue; + } + + const lit_code_point_t end = re_get_char (&bc_p, re_ctx_p->flags & RE_FLAG_UNICODE); + if (cp <= end) + { + goto class_found; + } + } + + /* Not found */ + if (flags & RE_CLASS_INVERT) + { + continue; + } + + goto fail; + +class_found: + if (flags & RE_CLASS_INVERT) + { + goto fail; + } + + const uint32_t chars_size = char_count * re_ctx_p->char_size; + const uint32_t ranges_size = range_count * re_ctx_p->char_size * 2; + bc_p = bc_p + escape_count + chars_size + ranges_size; + continue; + } +#if ENABLED (JERRY_ES2015) + case RE_OP_UNICODE_PERIOD: + { + if (str_curr_p >= re_ctx_p->input_end_p) + { + goto fail; + } + + const lit_code_point_t cp = ecma_regexp_unicode_advance (&str_curr_p, re_ctx_p->input_end_p); + + if (JERRY_UNLIKELY (cp <= LIT_UTF16_CODE_UNIT_MAX && lit_char_is_line_terminator ((ecma_char_t) cp))) + { + goto fail; + } + + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + case RE_OP_PERIOD: + { + if (str_curr_p >= re_ctx_p->input_end_p) + { + goto fail; + } + + const ecma_char_t ch = lit_cesu8_read_next (&str_curr_p); + + if (lit_char_is_line_terminator (ch)) + { + goto fail; + } + + continue; + } case RE_OP_CHAR: { if (str_curr_p >= re_ctx_p->input_end_p) { - return NULL; /* fail */ + goto fail; } - const bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; - ecma_char_t ch1 = (ecma_char_t) re_get_char (&bc_p); /* Already canonicalized. */ - ecma_char_t ch2 = ecma_regexp_canonicalize (lit_utf8_read_next (&str_curr_p), is_ignorecase); - JERRY_TRACE_MSG ("Character matching %d to %d: ", ch1, ch2); + const lit_code_point_t ch1 = re_get_char (&bc_p, re_ctx_p->flags & RE_FLAG_UNICODE); + const lit_code_point_t ch2 = ecma_regexp_advance (re_ctx_p, &str_curr_p); if (ch1 != ch2) { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ + goto fail; } - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - case RE_OP_PERIOD: - { - if (str_curr_p >= re_ctx_p->input_end_p) - { - return NULL; /* fail */ - } - - const ecma_char_t ch = lit_utf8_read_next (&str_curr_p); - JERRY_TRACE_MSG ("Period matching '.' to %u: ", (unsigned int) ch); - - if (lit_char_is_line_terminator (ch)) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - case RE_OP_ASSERT_START: - { - JERRY_TRACE_MSG ("Execute RE_OP_ASSERT_START: "); - - if (str_curr_p <= re_ctx_p->input_start_p) - { - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - - if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - if (lit_char_is_line_terminator (lit_utf8_peek_prev (str_curr_p))) - { - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - case RE_OP_ASSERT_END: - { - JERRY_TRACE_MSG ("Execute RE_OP_ASSERT_END: "); - - if (str_curr_p >= re_ctx_p->input_end_p) - { - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - - if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - if (lit_char_is_line_terminator (lit_utf8_peek_next (str_curr_p))) - { - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - case RE_OP_ASSERT_WORD_BOUNDARY: - case RE_OP_ASSERT_NOT_WORD_BOUNDARY: - { - const bool is_wordchar_left = ((str_curr_p > re_ctx_p->input_start_p) - && lit_char_is_word_char (lit_utf8_peek_prev (str_curr_p))); - - const bool is_wordchar_right = ((str_curr_p < re_ctx_p->input_end_p) - && lit_char_is_word_char (lit_utf8_peek_next (str_curr_p))); - - if (op == RE_OP_ASSERT_WORD_BOUNDARY) - { - JERRY_TRACE_MSG ("Execute RE_OP_ASSERT_WORD_BOUNDARY: "); - if (is_wordchar_left == is_wordchar_right) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - } - else - { - JERRY_ASSERT (op == RE_OP_ASSERT_NOT_WORD_BOUNDARY); - JERRY_TRACE_MSG ("Execute RE_OP_ASSERT_NOT_WORD_BOUNDARY: "); - - if (is_wordchar_left != is_wordchar_right) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - } - - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - case RE_OP_LOOKAHEAD_POS: - case RE_OP_LOOKAHEAD_NEG: - { - const lit_utf8_byte_t *matched_p = NULL; - const size_t captures_size = re_ctx_p->captures_count * sizeof (ecma_regexp_capture_t); - ecma_regexp_capture_t *saved_captures_p = (ecma_regexp_capture_t *) jmem_heap_alloc_block (captures_size); - memcpy (saved_captures_p, re_ctx_p->captures_p, captures_size); - - do - { - const uint32_t offset = re_get_value (&bc_p); - - if (matched_p == NULL) - { - matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) - { - jmem_heap_free_block (saved_captures_p, captures_size); - return matched_p; - } - } - bc_p += offset; - } - while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); - - JERRY_TRACE_MSG ("Execute RE_OP_LOOKAHEAD_POS/NEG: "); - if ((op == RE_OP_LOOKAHEAD_POS && matched_p != NULL) - || (op == RE_OP_LOOKAHEAD_NEG && matched_p == NULL)) - { - JERRY_TRACE_MSG ("match\n"); - matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - } - else - { - JERRY_TRACE_MSG ("fail\n"); - matched_p = NULL; /* fail */ - } - - if (matched_p == NULL) - { - /* restore saved */ - memcpy (re_ctx_p->captures_p, saved_captures_p, captures_size); - } - - jmem_heap_free_block (saved_captures_p, captures_size); - return matched_p; - } - case RE_OP_CHAR_CLASS: - case RE_OP_INV_CHAR_CLASS: - { - JERRY_TRACE_MSG ("Execute RE_OP_CHAR_CLASS/RE_OP_INV_CHAR_CLASS, "); - if (str_curr_p >= re_ctx_p->input_end_p) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - const bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; - const ecma_char_t curr_ch = ecma_regexp_canonicalize (lit_utf8_read_next (&str_curr_p), is_ignorecase); - - uint32_t range_count = re_get_value (&bc_p); - bool is_match = false; - - while (range_count-- > 0) - { - const ecma_char_t ch1 = re_get_char (&bc_p); - if (curr_ch < ch1) - { - bc_p += sizeof (ecma_char_t); - continue; - } - - const ecma_char_t ch2 = re_get_char (&bc_p); - is_match = (curr_ch <= ch2); - if (is_match) - { - /* Skip the remaining ranges in the bytecode. */ - bc_p += range_count * 2 * sizeof (ecma_char_t); - break; - } - } - - JERRY_ASSERT (op == RE_OP_CHAR_CLASS || op == RE_OP_INV_CHAR_CLASS); - - if ((op == RE_OP_CHAR_CLASS) != is_match) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - case RE_OP_BACKREFERENCE: - { - const uint32_t backref_idx = re_get_value (&bc_p); - JERRY_TRACE_MSG ("Execute RE_OP_BACKREFERENCE (idx: %u): ", (unsigned int) backref_idx); - JERRY_ASSERT (backref_idx >= 1 && backref_idx < re_ctx_p->captures_count); - const ecma_regexp_capture_t capture = re_ctx_p->captures_p[backref_idx]; - - if (capture.begin_p == NULL || capture.end_p == NULL) - { - JERRY_TRACE_MSG ("match\n"); - break; /* capture is 'undefined', always matches! */ - } - - const lit_utf8_size_t capture_size = (lit_utf8_size_t) (capture.end_p - capture.begin_p); - - if (str_curr_p + capture_size > re_ctx_p->input_end_p) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - if (memcmp (str_curr_p, capture.begin_p, capture_size)) - { - JERRY_TRACE_MSG ("fail\n"); - return NULL; /* fail */ - } - - str_curr_p += capture_size; - JERRY_TRACE_MSG ("match\n"); - break; /* tail merge */ - } - case RE_OP_SAVE_AT_START: - { - JERRY_TRACE_MSG ("Execute RE_OP_SAVE_AT_START\n"); - re_ctx_p->captures_p[RE_GLOBAL_CAPTURE].begin_p = str_curr_p; - - do - { - const uint32_t offset = re_get_value (&bc_p); - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - bc_p += offset; - } - while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); - bc_p -= sizeof (uint8_t); - - return NULL; /* fail */ - } - case RE_OP_SAVE_AND_MATCH: - { - JERRY_TRACE_MSG ("End of pattern is reached: match\n"); - re_ctx_p->captures_p[RE_GLOBAL_CAPTURE].end_p = str_curr_p; - return str_curr_p; /* match */ - } - case RE_OP_ALTERNATIVE: - { - /* - * Alternatives should be jumped over, when an alternative opcode appears. - */ - uint32_t offset = re_get_value (&bc_p); - JERRY_TRACE_MSG ("Execute RE_OP_ALTERNATIVE"); - bc_p += offset; - - while (*bc_p == RE_OP_ALTERNATIVE) - { - JERRY_TRACE_MSG (", jump: %u", (unsigned int) offset); - bc_p++; - offset = re_get_value (&bc_p); - bc_p += offset; - } - - JERRY_TRACE_MSG ("\n"); - break; /* tail merge */ - } - case RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START: - case RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START: - { - /* - * On non-greedy iterations we have to execute the bytecode - * after the group first, if zero iteration is allowed. - */ - const lit_utf8_byte_t *old_begin_p = NULL; - const uint8_t *const bc_start_p = bc_p; /* save the bytecode start position of the group start */ - const uint32_t start_idx = re_get_value (&bc_p); - const uint32_t offset = re_get_value (&bc_p); - - uint32_t *iterator_p; - if (RE_IS_CAPTURE_GROUP (op)) - { - JERRY_ASSERT (start_idx < re_ctx_p->captures_count); - re_ctx_p->captures_p[start_idx].begin_p = str_curr_p; - iterator_p = &(re_ctx_p->iterations_p[start_idx - 1]); - } - else - { - JERRY_ASSERT (start_idx < re_ctx_p->non_captures_count); - iterator_p = &(re_ctx_p->iterations_p[start_idx + re_ctx_p->captures_count - 1]); - } - *iterator_p = 0; - - /* Jump all over to the end of the END opcode. */ - bc_p += offset; - - /* Try to match after the close paren if zero is allowed */ - const lit_utf8_byte_t *matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return str_curr_p; /* match */ - } - - if (RE_IS_CAPTURE_GROUP (op)) - { - re_ctx_p->captures_p[start_idx].begin_p = old_begin_p; - } - - bc_p = bc_start_p; - /* FALLTHRU */ - } - case RE_OP_CAPTURE_GROUP_START: - case RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START: - case RE_OP_NON_CAPTURE_GROUP_START: - case RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START: - { - const uint8_t *bc_end_p = NULL; - const uint32_t start_idx = re_get_value (&bc_p); - - if (op != RE_OP_CAPTURE_GROUP_START - && op != RE_OP_NON_CAPTURE_GROUP_START) - { - const uint32_t offset = re_get_value (&bc_p); - bc_end_p = bc_p + offset; - } - - const lit_utf8_byte_t **group_begin_p; - uint32_t *iterator_p; - if (RE_IS_CAPTURE_GROUP (op)) - { - JERRY_ASSERT (start_idx < re_ctx_p->captures_count); - group_begin_p = &(re_ctx_p->captures_p[start_idx].begin_p); - iterator_p = &(re_ctx_p->iterations_p[start_idx - 1]); - } - else - { - JERRY_ASSERT (start_idx < re_ctx_p->non_captures_count); - group_begin_p = &(re_ctx_p->non_captures_p[start_idx].str_p); - iterator_p = &(re_ctx_p->iterations_p[start_idx + re_ctx_p->captures_count - 1]); - } - - const lit_utf8_byte_t *const old_begin_p = *group_begin_p; - const uint32_t old_iter_count = *iterator_p; - *group_begin_p = str_curr_p; - *iterator_p = 0; - - do - { - const uint32_t offset = re_get_value (&bc_p); - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - bc_p += offset; - } - while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); - - bc_p -= sizeof (uint8_t); - *iterator_p = old_iter_count; - - /* Try to match after the close paren if zero is allowed. */ - if (op == RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START - || op == RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START) - { - JERRY_ASSERT (bc_end_p); - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_end_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - } - - *group_begin_p = old_begin_p; - return NULL; /* fail */ - } - case RE_OP_CAPTURE_NON_GREEDY_GROUP_END: - case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END: - { - /* - * On non-greedy iterations we have to execute the bytecode - * after the group first. Try to iterate only if it fails. - */ - const uint8_t *const bc_start_p = bc_p; /* save the bytecode start position of the group end */ - const uint32_t end_idx = re_get_value (&bc_p); - const uint32_t min = re_get_value (&bc_p); - const uint32_t max = re_get_value (&bc_p); - re_get_value (&bc_p); /* start offset */ - - const lit_utf8_byte_t **group_end_p; - uint32_t *iterator_p; - if (RE_IS_CAPTURE_GROUP (op)) - { - JERRY_ASSERT (end_idx < re_ctx_p->captures_count); - group_end_p = &(re_ctx_p->captures_p[end_idx].end_p); - iterator_p = &(re_ctx_p->iterations_p[end_idx - 1]); - } - else - { - JERRY_ASSERT (end_idx < re_ctx_p->non_captures_count); - group_end_p = &(re_ctx_p->non_captures_p[end_idx].str_p); - iterator_p = &(re_ctx_p->iterations_p[end_idx + re_ctx_p->captures_count - 1]); - } - - (*iterator_p)++; - - if (*iterator_p >= min && *iterator_p <= max) - { - const lit_utf8_byte_t *const old_end_p = *group_end_p; - *group_end_p = str_curr_p; - - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - *group_end_p = old_end_p; - } - (*iterator_p)--; - bc_p = bc_start_p; - - /* Non-greedy fails, try to iterate. */ - /* FALLTHRU */ - } - case RE_OP_CAPTURE_GREEDY_GROUP_END: - case RE_OP_NON_CAPTURE_GREEDY_GROUP_END: - { - const uint32_t end_idx = re_get_value (&bc_p); - const uint32_t min = re_get_value (&bc_p); - const uint32_t max = re_get_value (&bc_p); - uint32_t offset = re_get_value (&bc_p); - - const lit_utf8_byte_t **group_begin_p; - const lit_utf8_byte_t **group_end_p; - uint32_t *iterator_p; - - if (RE_IS_CAPTURE_GROUP (op)) - { - JERRY_ASSERT (end_idx < re_ctx_p->captures_count); - group_begin_p = &(re_ctx_p->captures_p[end_idx].begin_p); - group_end_p = &(re_ctx_p->captures_p[end_idx].end_p); - iterator_p = &(re_ctx_p->iterations_p[end_idx - 1]); - } - else - { - JERRY_ASSERT (end_idx <= re_ctx_p->non_captures_count); - group_begin_p = &(re_ctx_p->non_captures_p[end_idx].str_p); - group_end_p = &(re_ctx_p->non_captures_p[end_idx].str_p); - iterator_p = &(re_ctx_p->iterations_p[end_idx + re_ctx_p->captures_count - 1]); - } - - /* Check the empty iteration if the minimum number of iterations is reached. */ - if (*iterator_p >= min && str_curr_p == *group_begin_p) - { - return NULL; /* fail */ - } - - (*iterator_p)++; - - const uint8_t *const bc_start_p = bc_p; /* Save the bytecode end position of the END opcodes. */ - const lit_utf8_byte_t *const old_end_p = *group_end_p; - *group_end_p = str_curr_p; - - if (*iterator_p < max) - { - bc_p -= offset; - offset = re_get_value (&bc_p); - - const lit_utf8_byte_t *const old_begin_p = *group_begin_p; - *group_begin_p = str_curr_p; - - const lit_utf8_byte_t *matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - /* Try to match alternatives if any. */ - bc_p += offset; - while (*bc_p == RE_OP_ALTERNATIVE) - { - bc_p++; /* RE_OP_ALTERNATIVE */ - offset = re_get_value (&bc_p); - - *group_begin_p = str_curr_p; - - matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - bc_p += offset; - } - - *group_begin_p = old_begin_p; - } - - if (*iterator_p >= min && *iterator_p <= max) - { - /* Try to match the rest of the bytecode. */ - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_start_p, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - } - - /* restore if fails */ - *group_end_p = old_end_p; - (*iterator_p)--; - return NULL; /* fail */ - } - case RE_OP_NON_GREEDY_ITERATOR: - { - const uint32_t min = re_get_value (&bc_p); - const uint32_t max = re_get_value (&bc_p); - - const uint32_t offset = re_get_value (&bc_p); - JERRY_TRACE_MSG ("Non-greedy iterator, min=%lu, max=%lu, offset=%ld\n", - (unsigned long) min, (unsigned long) max, (long) offset); - - uint32_t iter_count = 0; - while (iter_count <= max) - { - if (iter_count >= min) - { - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p + offset, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - } - - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) - { - return matched_p; - } - - if (matched_p == NULL) - { - break; - } - - str_curr_p = matched_p; - iter_count++; - } - - return NULL; /* fail */ + continue; } default: { - JERRY_ASSERT (op == RE_OP_GREEDY_ITERATOR); + JERRY_ASSERT (op == RE_OP_BYTE); - const uint32_t min = re_get_value (&bc_p); - const uint32_t max = re_get_value (&bc_p); - - const uint32_t offset = re_get_value (&bc_p); - JERRY_TRACE_MSG ("Greedy iterator, min=%lu, max=%lu, offset=%ld\n", - (unsigned long) min, (unsigned long) max, (long) offset); - - uint32_t iter_count = 0; - while (iter_count < max) + if (str_curr_p >= re_ctx_p->input_end_p + || *bc_p++ != *str_curr_p++) { - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p, str_curr_p); - - if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) - { - return matched_p; - } - - if (matched_p == NULL) - { - break; - } - - str_curr_p = matched_p; - iter_count++; + goto fail; } - if (iter_count >= min) - { - while (true) - { - const lit_utf8_byte_t *const matched_p = ecma_regexp_match (re_ctx_p, bc_p + offset, str_curr_p); - - if (matched_p != NULL) - { - return matched_p; /* match */ - } - - if (iter_count == min) - { - break; - } - - lit_utf8_read_prev (&str_curr_p); - iter_count--; - } - } - - return NULL; /* fail */ + continue; } } + + JERRY_UNREACHABLE (); +fail: + bc_p = next_alternative_p; + + if (bc_p == NULL || *bc_p++ != RE_OP_ALTERNATIVE_NEXT) + { + /* None of the alternatives matched. */ + return NULL; + } + + /* Get the end of the new alternative and continue execution. */ + str_curr_p = str_start_p; + const uint32_t offset = re_get_value (&bc_p); + next_alternative_p = bc_p + offset; } +} /* ecma_regexp_run */ + +/** + * Match a RegExp at a specific position in the input string. + * + * @return pointer to the end of the matched sub-string + * NULL, if pattern did not match + */ +static const lit_utf8_byte_t * +ecma_regexp_match (ecma_regexp_ctx_t *re_ctx_p, /**< RegExp matcher context */ + const uint8_t *bc_p, /**< pointer to the current RegExp bytecode */ + const lit_utf8_byte_t *str_curr_p) /**< input string pointer */ +{ + re_ctx_p->captures_p[RE_GLOBAL_CAPTURE].begin_p = str_curr_p; + + for (uint32_t i = 1; i < re_ctx_p->captures_count; ++i) + { + re_ctx_p->captures_p[i].begin_p = NULL; + } + + return ecma_regexp_run (re_ctx_p, bc_p, str_curr_p); } /* ecma_regexp_match */ +/* + * Helper function to get the result of a capture + * + * @return string value, if capture is defined + * undefined, otherwise + */ +ecma_value_t +ecma_regexp_get_capture_value (const ecma_regexp_capture_t *const capture_p) /**< capture */ +{ + if (ECMA_RE_IS_CAPTURE_DEFINED (capture_p)) + { + JERRY_ASSERT (capture_p->end_p >= capture_p->begin_p); + const lit_utf8_size_t capture_size = (lit_utf8_size_t) (capture_p->end_p - capture_p->begin_p); + ecma_string_t *const capture_str_p = ecma_new_ecma_string_from_utf8 (capture_p->begin_p, capture_size); + return ecma_make_string_value (capture_str_p); + } + + return ECMA_VALUE_UNDEFINED; +} /* ecma_regexp_get_capture_value */ + +/** + * Helper function to create a result array from the captures in a regexp context + * + * @return ecma value containing the created array object + */ static ecma_value_t -ecma_regexp_create_result_object (ecma_regexp_ctx_t *re_ctx_p, - ecma_string_t *input_string_p, - uint32_t index) +ecma_regexp_create_result_object (ecma_regexp_ctx_t *re_ctx_p, /**< regexp context */ + ecma_string_t *input_string_p, /**< input ecma string */ + uint32_t index) /**< match index */ { ecma_value_t result_array = ecma_op_create_array_object (0, 0, false); ecma_object_t *result_p = ecma_get_object_from_value (result_array); for (uint32_t i = 0; i < re_ctx_p->captures_count; i++) { - const ecma_regexp_capture_t capture = re_ctx_p->captures_p[i]; - - if (capture.begin_p != NULL && capture.end_p >= capture.begin_p) - { - const lit_utf8_size_t capture_size = (lit_utf8_size_t) (capture.end_p - capture.begin_p); - ecma_string_t *const capture_str_p = ecma_new_ecma_string_from_utf8 (capture.begin_p, capture_size); - const ecma_value_t capture_value = ecma_make_string_value (capture_str_p); - ecma_builtin_helper_def_prop_by_index (result_p, - i, - capture_value, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - ecma_deref_ecma_string (capture_str_p); - } - else - { - ecma_builtin_helper_def_prop_by_index (result_p, - i, - ECMA_VALUE_UNDEFINED, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); - } + ecma_value_t capture_value = ecma_regexp_get_capture_value (re_ctx_p->captures_p + i); + ecma_builtin_helper_def_prop_by_index (result_p, + i, + capture_value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + ecma_free_value (capture_value); } ecma_builtin_helper_def_prop (result_p, @@ -1061,6 +1609,52 @@ ecma_regexp_create_result_object (ecma_regexp_ctx_t *re_ctx_p, return result_array; } /* ecma_regexp_create_result_object */ +/** + * Helper function to initialize a regexp match context + */ +static void +ecma_regexp_initialize_context (ecma_regexp_ctx_t *ctx_p, /**< regexp context */ + const re_compiled_code_t *bc_p, /**< regexp bytecode */ + const lit_utf8_byte_t *input_start_p, /**< pointer to input string */ + const lit_utf8_byte_t *input_end_p) /**< pointer to end of input string */ +{ + JERRY_ASSERT (ctx_p != NULL); + JERRY_ASSERT (bc_p != NULL); + JERRY_ASSERT (input_start_p != NULL); + JERRY_ASSERT (input_end_p >= input_start_p); + + ctx_p->flags = bc_p->header.status_flags; + ctx_p->char_size = (ctx_p->flags & RE_FLAG_UNICODE) ? sizeof (lit_code_point_t) : sizeof (ecma_char_t); + + ctx_p->input_start_p = input_start_p; + ctx_p->input_end_p = input_end_p; + + ctx_p->captures_count = bc_p->captures_count; + ctx_p->non_captures_count = bc_p->non_captures_count; + + ctx_p->captures_p = jmem_heap_alloc_block (ctx_p->captures_count * sizeof (ecma_regexp_capture_t)); + + if (ctx_p->non_captures_count > 0) + { + ctx_p->non_captures_p = jmem_heap_alloc_block (ctx_p->non_captures_count * sizeof (ecma_regexp_non_capture_t)); + } +} /* ecma_regexp_initialize_context */ + +/** + * Helper function to clean up a regexp context + */ +static void +ecma_regexp_cleanup_context (ecma_regexp_ctx_t *ctx_p) /**< regexp context */ +{ + JERRY_ASSERT (ctx_p != NULL); + jmem_heap_free_block (ctx_p->captures_p, ctx_p->captures_count * sizeof (ecma_regexp_capture_t)); + + if (ctx_p->non_captures_count > 0) + { + jmem_heap_free_block (ctx_p->non_captures_p, ctx_p->non_captures_count * sizeof (ecma_regexp_non_capture_t)); + } +} /* ecma_regexp_cleanup_context */ + /** * RegExp helper function to start the recursive matching algorithm * and create the result Array object @@ -1075,53 +1669,17 @@ ecma_regexp_create_result_object (ecma_regexp_ctx_t *re_ctx_p, * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ - ecma_value_t input_string, /**< input string */ - bool ignore_global) /**< ignore global flag */ +ecma_regexp_exec_helper (ecma_object_t *regexp_object_p, /**< RegExp object */ + ecma_string_t *input_string_p) /**< input string */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; - JERRY_ASSERT (ecma_is_value_object (regexp_value)); - JERRY_ASSERT (ecma_is_value_string (input_string)); - - ecma_object_t *regexp_object_p = ecma_get_object_from_value (regexp_value); - - JERRY_ASSERT (ecma_object_class_is (regexp_object_p, LIT_MAGIC_STRING_REGEXP_UL)); + JERRY_ASSERT (ecma_object_is_regexp_object (ecma_make_object_value (regexp_object_p))); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) regexp_object_p; re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, ext_object_p->u.class_prop.u.value); - ecma_regexp_ctx_t re_ctx; - ecma_string_t *input_string_p = ecma_get_string_from_value (input_string); - - if (bc_p == NULL) - { -#if ENABLED (JERRY_ES2015) - return ecma_raise_type_error (ECMA_ERR_MSG ("Incompatible type")); -#else /* !ENABLED (JERRY_ES2015) */ - /* Missing bytecode means the RegExp object is the RegExp.prototype, - * which will always result in an empty string match. */ - re_ctx.captures_count = 1; - - re_ctx.captures_p = jmem_heap_alloc_block (sizeof (ecma_regexp_capture_t)); - re_ctx.captures_p->begin_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING__EMPTY); - re_ctx.captures_p->end_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING__EMPTY); - - ret_value = ecma_regexp_create_result_object (&re_ctx, input_string_p, 0); - - jmem_heap_free_block (re_ctx.captures_p, sizeof (ecma_regexp_capture_t)); - return ret_value; -#endif /* ENABLED (JERRY_ES2015) */ - } - - re_ctx.flags = bc_p->header.status_flags; - - if (ignore_global) - { - re_ctx.flags &= (uint16_t) ~RE_FLAG_GLOBAL; - } - lit_utf8_size_t input_size; lit_utf8_size_t input_length; uint8_t input_flags = ECMA_STRING_FLAG_IS_ASCII; @@ -1133,13 +1691,14 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ const lit_utf8_byte_t *input_curr_p = input_buffer_p; uint32_t index = 0; - if (re_ctx.flags & RE_FLAG_GLOBAL) + if (bc_p->header.status_flags & (RE_FLAG_GLOBAL | RE_FLAG_STICKY)) { ecma_string_t *lastindex_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_value_t lastindex_value = ecma_op_object_get_own_data_prop (regexp_object_p, lastindex_str_p); ecma_number_t lastindex_num; - ret_value = ecma_get_number (lastindex_value, &lastindex_num); + ret_value = ecma_op_to_integer (lastindex_value, &lastindex_num); + ecma_free_value (lastindex_value); if (ECMA_IS_VALUE_ERROR (ret_value)) @@ -1191,26 +1750,12 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ } } - re_ctx.input_start_p = input_buffer_p; - const lit_utf8_byte_t *input_end_p = re_ctx.input_start_p + input_size; - re_ctx.input_end_p = input_end_p; - - JERRY_TRACE_MSG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n", - re_ctx.flags & RE_FLAG_GLOBAL, - re_ctx.flags & RE_FLAG_IGNORE_CASE, - re_ctx.flags & RE_FLAG_MULTILINE); - - re_ctx.captures_count = bc_p->captures_count; - re_ctx.captures_p = jmem_heap_alloc_block (re_ctx.captures_count * sizeof (ecma_regexp_capture_t)); - memset (re_ctx.captures_p, 0, re_ctx.captures_count * sizeof (ecma_regexp_capture_t)); - - re_ctx.non_captures_count = bc_p->non_captures_count; - re_ctx.non_captures_p = jmem_heap_alloc_block (re_ctx.non_captures_count * sizeof (ecma_regexp_non_capture_t)); - memset (re_ctx.non_captures_p, 0, re_ctx.non_captures_count * sizeof (ecma_regexp_non_capture_t)); - - const uint32_t iters_length = re_ctx.captures_count + re_ctx.non_captures_count - 1; - re_ctx.iterations_p = jmem_heap_alloc_block (iters_length * sizeof (uint32_t)); - memset (re_ctx.iterations_p, 0, iters_length * sizeof (uint32_t)); + const lit_utf8_byte_t *input_end_p = input_buffer_p + input_size; + ecma_regexp_ctx_t re_ctx; + ecma_regexp_initialize_context (&re_ctx, + bc_p, + input_buffer_p, + input_end_p); /* 2. Try to match */ uint8_t *bc_start_p = (uint8_t *) (bc_p + 1); @@ -1226,8 +1771,26 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ break; } - index++; - if (index > input_length) +#if ENABLED (JERRY_ES2015) + if (re_ctx.flags & RE_FLAG_STICKY) + { + ecma_value_t put_result = ecma_op_object_put (regexp_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + true); + if (ECMA_IS_VALUE_ERROR (put_result)) + { + ret_value = put_result; + goto cleanup_context; + } + + JERRY_ASSERT (ecma_is_value_boolean (put_result)); + ret_value = ECMA_VALUE_NULL; + goto cleanup_context; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (input_curr_p >= input_end_p) { if (re_ctx.flags & RE_FLAG_GLOBAL) { @@ -1250,6 +1813,24 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ } JERRY_ASSERT (input_curr_p < input_end_p); + +#if ENABLED (JERRY_ES2015) + if (re_ctx.flags & RE_FLAG_UNICODE) + { + index++; + const lit_code_point_t cp = ecma_regexp_unicode_advance (&input_curr_p, + input_end_p); + + if (cp > LIT_UTF16_CODE_UNIT_MAX) + { + index++; + } + + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + + index++; lit_utf8_incr (&input_curr_p); } @@ -1261,7 +1842,7 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ goto cleanup_context; } - if (re_ctx.flags & RE_FLAG_GLOBAL) + if (re_ctx.flags & (RE_FLAG_GLOBAL | RE_FLAG_STICKY)) { JERRY_ASSERT (index <= input_length); @@ -1295,15 +1876,7 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ ret_value = ecma_regexp_create_result_object (&re_ctx, input_string_p, index); cleanup_context: - jmem_heap_free_block (re_ctx.captures_p, re_ctx.captures_count * sizeof (ecma_regexp_capture_t)); - if (re_ctx.non_captures_p != NULL) - { - jmem_heap_free_block (re_ctx.non_captures_p, re_ctx.non_captures_count * sizeof (ecma_regexp_non_capture_t)); - } - if (re_ctx.iterations_p != NULL) - { - jmem_heap_free_block (re_ctx.iterations_p, iters_length * sizeof (uint32_t)); - } + ecma_regexp_cleanup_context (&re_ctx); cleanup_string: if (input_flags & ECMA_STRING_FLAG_MUST_BE_FREED) @@ -1324,34 +1897,1558 @@ cleanup_string: * @return empty value if success, error value otherwise * Returned value must be freed with ecma_free_value. */ -ecma_value_t -ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg, /**< the RegExp pattern */ - ecma_string_t **pattern_string_p) /**< [out] ptr to the pattern string ptr */ +ecma_string_t * +ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg) /**< the RegExp pattern */ { if (!ecma_is_value_undefined (pattern_arg)) { - ecma_value_t regexp_str_value = ecma_op_to_string (pattern_arg); - if (ECMA_IS_VALUE_ERROR (regexp_str_value)) + ecma_string_t *pattern_string_p = ecma_op_to_string (pattern_arg); + if (JERRY_UNLIKELY (pattern_string_p == NULL) || !ecma_string_is_empty (pattern_string_p)) { - return regexp_str_value; + return pattern_string_p; } - - *pattern_string_p = ecma_get_string_from_value (regexp_str_value); - if (!ecma_string_is_empty (*pattern_string_p)) - { - ecma_ref_ecma_string (*pattern_string_p); - } - - ecma_free_value (regexp_str_value); // must be freed *after* ecma_ref_ecma_string } - if (!*pattern_string_p || ecma_string_is_empty (*pattern_string_p)) - { - *pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); - } - return ECMA_VALUE_EMPTY; + return ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP); } /* ecma_regexp_read_pattern_str_helper */ +/** + * Helper function for RegExp based string searches + * + * See also: + * ECMA-262 v6, 21.2.5.9 + * + * @return index of the match + */ +ecma_value_t +ecma_regexp_search_helper (ecma_value_t regexp_arg, /**< regexp argument */ + ecma_value_t string_arg) /**< string argument */ +{ + /* 2. */ + if (!ecma_is_value_object (regexp_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + ecma_value_t result = ECMA_VALUE_ERROR; + + /* 3-4. */ + ecma_string_t *const string_p = ecma_op_to_string (string_arg); + if (string_p == NULL) + { + return result; + } + + ecma_object_t *const regexp_object_p = ecma_get_object_from_value (regexp_arg); + + /* 5-6. */ + ecma_string_t *const last_index_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); + const ecma_value_t prev_last_index = ecma_op_object_get (regexp_object_p, last_index_str_p); + if (ECMA_IS_VALUE_ERROR (prev_last_index)) + { + goto cleanup_string; + } + + /* 7-8. */ + const ecma_value_t status = ecma_op_object_put (regexp_object_p, last_index_str_p, ecma_make_uint32_value (0), true); + if (ECMA_IS_VALUE_ERROR (status)) + { + ecma_free_value (prev_last_index); + goto cleanup_string; + } + + JERRY_ASSERT (ecma_is_value_boolean (status)); + + /* 9-10. */ + const ecma_value_t match = ecma_op_regexp_exec (regexp_arg, string_p); + if (ECMA_IS_VALUE_ERROR (match)) + { + ecma_free_value (prev_last_index); + goto cleanup_string; + } + + /* 11-12. */ + result = ecma_op_object_put (regexp_object_p, last_index_str_p, prev_last_index, true); + ecma_free_value (prev_last_index); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_free_value (match); + goto cleanup_string; + } + + /* 13-14. */ + if (ecma_is_value_null (match)) + { + result = ecma_make_int32_value (-1); + } + else + { + ecma_object_t *const match_p = ecma_get_object_from_value (match); + result = ecma_op_object_get_by_magic_id (match_p, LIT_MAGIC_STRING_INDEX); + ecma_deref_object (match_p); + } + +cleanup_string: + ecma_deref_ecma_string (string_p); + return result; +} /* ecma_regexp_search_helper */ + +/** + * Helper function for RegExp based string split operation + * + * See also: + * ECMA-262 v6, 21.2.5.11 + * + * @return array of split and captured strings + */ +ecma_value_t +ecma_regexp_split_helper (ecma_value_t this_arg, /**< this value */ + ecma_value_t string_arg, /**< string value */ + ecma_value_t limit_arg) /**< limit value */ +{ +#if ENABLED (JERRY_ES2015) + /* 2. */ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + ecma_value_t result = ECMA_VALUE_ERROR; + + /* 3-4. */ + ecma_string_t *const string_p = ecma_op_to_string (string_arg); + if (string_p == NULL) + { + return result; + } + + /* 5-6. */ + ecma_object_t *const regexp_obj_p = ecma_get_object_from_value (this_arg); + ecma_value_t constructor = ecma_op_species_constructor (regexp_obj_p, ECMA_BUILTIN_ID_REGEXP); + if (ECMA_IS_VALUE_ERROR (constructor)) + { + goto cleanup_string; + } + + ecma_object_t *const constructor_obj_p = ecma_get_object_from_value (constructor); + + /* 7-8. */ + ecma_value_t flags = ecma_op_object_get_by_magic_id (regexp_obj_p, LIT_MAGIC_STRING_FLAGS); + if (ECMA_IS_VALUE_ERROR (flags)) + { + ecma_deref_object (constructor_obj_p); + goto cleanup_string; + } + + ecma_string_t *flags_str_p = ecma_op_to_string (flags); + ecma_free_value (flags); + + if (JERRY_UNLIKELY (flags_str_p == NULL)) + { + ecma_deref_object (constructor_obj_p); + goto cleanup_string; + } + + lit_utf8_size_t flags_size; + uint8_t flags_str_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *flags_buffer_p = ecma_string_get_chars (flags_str_p, + &flags_size, + NULL, + NULL, + &flags_str_flags); + + bool unicode = false; + bool sticky = false; + + /* 9-11. */ + const lit_utf8_byte_t *const flags_end_p = flags_buffer_p + flags_size; + for (const lit_utf8_byte_t *current_p = flags_buffer_p; current_p < flags_end_p; ++current_p) + { + switch (*current_p) + { + case LIT_CHAR_LOWERCASE_U: + { + unicode = true; + break; + } + case LIT_CHAR_LOWERCASE_Y: + { + sticky = true; + break; + } + } + } + + if (flags_str_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) flags_buffer_p, flags_size); + } + + /* 12. */ + if (!sticky) + { + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (flags_str_p); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_LOWERCASE_Y); + + ecma_deref_ecma_string (flags_str_p); + flags_str_p = ecma_stringbuilder_finalize (&builder); + } + + /* 13-14. */ + ecma_value_t arguments[] = { this_arg, ecma_make_string_value (flags_str_p) }; + ecma_value_t splitter = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, arguments, 2); + + ecma_deref_ecma_string (flags_str_p); + ecma_deref_object (constructor_obj_p); + + if (ECMA_IS_VALUE_ERROR (splitter)) + { + goto cleanup_string; + } + + ecma_object_t *const splitter_obj_p = ecma_get_object_from_value (splitter); + + /* 17. */ + uint32_t limit = UINT32_MAX; + if (!ecma_is_value_undefined (limit_arg)) + { + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (limit_arg, &limit))) + { + goto cleanup_splitter; + } + } + + /* 15. */ + ecma_value_t array = ecma_op_create_array_object (NULL, 0, false); + + /* 21. */ + if (limit == 0) + { + result = array; + goto cleanup_splitter; + } + + const lit_utf8_size_t string_length = ecma_string_get_length (string_p); + + ecma_object_t *const array_p = ecma_get_object_from_value (array); + ecma_length_t array_length = 0; + + /* 22. */ + if (string_length == 0) + { + const ecma_value_t match = ecma_op_regexp_exec (splitter, string_p); + + if (ECMA_IS_VALUE_ERROR (match)) + { + goto cleanup_array; + } + + if (ecma_is_value_null (match)) + { + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length, + ecma_make_string_value (string_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + } + + ecma_free_value (match); + result = array; + goto cleanup_splitter; + } + + /* 23. */ + uint32_t current_index = 0; + uint32_t previous_index = 0; + + ecma_string_t *const lastindex_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); + + /* 24. */ + while (current_index < string_length) + { + /* 24.a-b. */ + result = ecma_op_object_put (splitter_obj_p, + lastindex_str_p, + ecma_make_uint32_value (current_index), + true); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_array; + } + + JERRY_ASSERT (ecma_is_value_true (result)); + + /* 24.c-d. */ + result = ecma_op_regexp_exec (splitter, string_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_array; + } + + /* 24.e. */ + if (ecma_is_value_null (result)) + { + current_index = ecma_op_advance_string_index (string_p, current_index, unicode); + continue; + } + + ecma_object_t *const match_array_p = ecma_get_object_from_value (result); + + /* 24.f.i. */ + result = ecma_op_object_get (splitter_obj_p, lastindex_str_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (match_array_p); + goto cleanup_array; + } + + uint32_t end_index; + const ecma_value_t length_value = ecma_op_to_length (result, &end_index); + ecma_free_value (result); + + if (ECMA_IS_VALUE_ERROR (length_value)) + { + result = ECMA_VALUE_ERROR; + ecma_deref_object (match_array_p); + goto cleanup_array; + } + + /* 24.f.iii. */ + if (previous_index == end_index) + { + ecma_deref_object (match_array_p); + current_index = ecma_op_advance_string_index (string_p, current_index, unicode); + continue; + } + + /* 24.f.iv.1-4. */ + ecma_string_t *const split_str_p = ecma_string_substr (string_p, previous_index, current_index); + + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + ecma_make_string_value (split_str_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + ecma_deref_ecma_string (split_str_p); + + /* 24.f.iv.5. */ + if (array_length == limit) + { + ecma_deref_object (match_array_p); + result = array; + goto cleanup_splitter; + } + + /* 24.f.iv.6. */ + previous_index = end_index; + + /* 24.f.iv.7-8. */ + uint32_t match_length; + result = ecma_op_object_get_length (match_array_p, &match_length); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (match_array_p); + goto cleanup_array; + } + + /* 24.f.iv.9. */ + match_length = (match_length > 0) ? match_length - 1 : match_length; + + uint32_t match_index = 1; + while (match_index <= match_length) + { + /* 24.f.iv.11.a-b. */ + result = ecma_op_object_get_by_uint32_index (match_array_p, match_index++); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (match_array_p); + goto cleanup_array; + } + + const ecma_value_t capture = result; + + /* 24.f.iv.11.c. */ + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + capture, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + + ecma_free_value (capture); + + if (array_length == limit) + { + ecma_deref_object (match_array_p); + result = array; + goto cleanup_splitter; + } + } + + /* 24.f.iv.12. */ + current_index = end_index; + + ecma_deref_object (match_array_p); + } + + ecma_string_t *const end_str_p = ecma_string_substr (string_p, previous_index, string_length); + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + ecma_make_string_value (end_str_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + ecma_deref_ecma_string (end_str_p); + + result = array; + goto cleanup_splitter; + +cleanup_array: + ecma_deref_object (array_p); +cleanup_splitter: + ecma_deref_object (splitter_obj_p); +cleanup_string: + ecma_deref_ecma_string (string_p); + + return result; +#else /* ENABLED (JERRY_ES2015) */ + ecma_value_t result = ECMA_VALUE_ERROR; + + /* 2. */ + ecma_string_t *string_p = ecma_op_to_string (string_arg); + if (JERRY_UNLIKELY (string_p == NULL)) + { + return result; + } + + /* 5. */ + uint32_t limit = UINT32_MAX; + if (!ecma_is_value_undefined (limit_arg)) + { + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (limit_arg, &limit))) + { + goto cleanup_string; + } + } + + /* 15. */ + ecma_value_t array = ecma_op_create_array_object (NULL, 0, false); + + /* 21. */ + if (limit == 0) + { + result = array; + goto cleanup_string; + } + + ecma_object_t *const array_p = ecma_get_object_from_value (array); + ecma_length_t array_length = 0; + + ecma_object_t *const regexp_p = ecma_get_object_from_value (this_arg); + ecma_extended_object_t *const ext_object_p = (ecma_extended_object_t *) regexp_p; + re_compiled_code_t *const bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, + ext_object_p->u.class_prop.u.value); + + lit_utf8_size_t string_size; + lit_utf8_size_t string_length; + uint8_t string_flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *string_buffer_p = ecma_string_get_chars (string_p, + &string_size, + &string_length, + NULL, + &string_flags); + + const lit_utf8_byte_t *current_str_p = string_buffer_p; + const lit_utf8_byte_t *previous_str_p = string_buffer_p; + const lit_utf8_byte_t *const string_end_p = string_buffer_p + string_size; + + ecma_regexp_ctx_t re_ctx; + ecma_regexp_initialize_context (&re_ctx, + bc_p, + string_buffer_p, + string_buffer_p + string_size); + + uint8_t *const bc_start_p = (uint8_t *) (bc_p + 1); + + if (string_length == 0) + { + const lit_utf8_byte_t *const matched_p = ecma_regexp_match (&re_ctx, bc_start_p, current_str_p); + + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + result = ecma_raise_range_error (ECMA_ERR_MSG ("Stack limit exceeded.")); + goto cleanup_array; + } + + if (matched_p == NULL) + { + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length, + ecma_make_string_value (string_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + } + + result = array; + goto cleanup_context; + } + + /* 13. */ + while (current_str_p < string_end_p) + { + /* 13.a. */ + const lit_utf8_byte_t *const matched_p = ecma_regexp_match (&re_ctx, bc_start_p, current_str_p); + + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + result = ecma_raise_range_error (ECMA_ERR_MSG ("Stack limit exceeded.")); + goto cleanup_array; + } + + if (matched_p == NULL || matched_p == previous_str_p) + { + lit_utf8_incr (¤t_str_p); + continue; + } + + /* 13.c.iii.1. */ + ecma_string_t *const str_p = ecma_new_ecma_string_from_utf8 (previous_str_p, + (lit_utf8_size_t) (current_str_p - previous_str_p)); + + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + ecma_make_string_value (str_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + ecma_deref_ecma_string (str_p); + + if (array_length == limit) + { + result = array; + goto cleanup_context; + } + + /* 13.c.iii.5. */ + previous_str_p = matched_p; + + uint32_t index = 1; + while (index < re_ctx.captures_count) + { + const ecma_value_t capture = ecma_regexp_get_capture_value (re_ctx.captures_p + index); + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + capture, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + ecma_free_value (capture); + + if (array_length == limit) + { + result = array; + goto cleanup_context; + } + + index++; + } + + /* 13.c.iii.8. */ + current_str_p = matched_p; + } + + ecma_string_t *const str_p = ecma_new_ecma_string_from_utf8 (previous_str_p, + (lit_utf8_size_t) (string_end_p - previous_str_p)); + + result = ecma_builtin_helper_def_prop_by_index (array_p, + array_length++, + ecma_make_string_value (str_p), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (result)); + ecma_deref_ecma_string (str_p); + + result = array; + goto cleanup_context; + +cleanup_array: + ecma_deref_object (array_p); +cleanup_context: + ecma_regexp_cleanup_context (&re_ctx); + if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) string_buffer_p, string_size); + } +cleanup_string: + ecma_deref_ecma_string (string_p); + + return result; +#endif /* ENABLED (JERRY_ES2015) */ +} /* ecma_regexp_split_helper */ + +/** + * Fast path for RegExp based replace operation + * + * This method assumes the following: + * - The RegExp object is a built-in RegExp + * - The 'exec' method of the RegExp object is the built-in 'exec' method + * - The 'lastIndex' property is writable + * + * The standard would normally require us to first execute the regexp and collect the results, + * and after that iterate over the collected results and replace them. + * The assumptions above guarantee that during the matching phase there will be no exceptions thrown, + * which means we can do the match/replace in a single loop, without collecting the results. + * + * @return string value if successful + * thrown value otherwise + */ +static ecma_value_t +ecma_regexp_replace_helper_fast (ecma_replace_context_t *ctx_p, /**string_p = ecma_string_get_chars (string_p, + &(ctx_p->string_size), + &string_length, + NULL, + &string_flags); + + const lit_utf8_byte_t *const string_end_p = ctx_p->string_p + ctx_p->string_size; + const uint8_t *const bc_start_p = (const uint8_t *) (bc_p + 1); + const lit_utf8_byte_t *matched_p = NULL; + const lit_utf8_byte_t *current_p = ctx_p->string_p; + const lit_utf8_byte_t *last_append_p = current_p; + JERRY_ASSERT (ctx_p->index <= string_length); + +#if ENABLED (JERRY_ES2015) + /* Global matches always start at index 0, but Sticky matches may have a non-zero lastIndex. */ + if (ctx_p->index > 0) + { + if (string_flags & ECMA_STRING_FLAG_IS_ASCII) + { + current_p += ctx_p->index; + } + else + { + ecma_length_t index = ctx_p->index; + while (index--) + { + lit_utf8_incr (¤t_p); + } + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_regexp_ctx_t re_ctx; + ecma_regexp_initialize_context (&re_ctx, + bc_p, + ctx_p->string_p, + string_end_p); + + ctx_p->builder = ecma_stringbuilder_create (); + ctx_p->capture_count = re_ctx.captures_count; + ctx_p->u.captures_p = re_ctx.captures_p; + + while (true) + { + matched_p = ecma_regexp_match (&re_ctx, bc_start_p, current_p); + + if (matched_p != NULL) + { + if (ECMA_RE_STACK_LIMIT_REACHED (matched_p)) + { + result = ecma_raise_range_error (ECMA_ERR_MSG ("Stack limit exceeded.")); + goto cleanup_builder; + } + + const lit_utf8_size_t remaining_size = (lit_utf8_size_t) (current_p - last_append_p); + ecma_stringbuilder_append_raw (&(ctx_p->builder), last_append_p, remaining_size); + + if (ctx_p->replace_str_p != NULL) + { + ctx_p->matched_p = current_p; + const ecma_regexp_capture_t *const global_capture_p = re_ctx.captures_p; + ctx_p->matched_size = (lit_utf8_size_t) (global_capture_p->end_p - global_capture_p->begin_p); + ctx_p->match_byte_pos = (lit_utf8_size_t) (current_p - re_ctx.input_start_p); + + ecma_builtin_replace_substitute (ctx_p); + } + else + { + ecma_collection_t *arguments_p = ecma_new_collection (); + + for (uint32_t i = 0; i < re_ctx.captures_count; i++) + { + ecma_value_t capture = ecma_regexp_get_capture_value (re_ctx.captures_p + i); + ecma_collection_push_back (arguments_p, capture); + } + + ecma_collection_push_back (arguments_p, ecma_make_uint32_value (ctx_p->index)); + ecma_ref_ecma_string (string_p); + ecma_collection_push_back (arguments_p, ecma_make_string_value (string_p)); + ecma_object_t *function_p = ecma_get_object_from_value (replace_arg); + + result = ecma_op_function_call (function_p, + ECMA_VALUE_UNDEFINED, + arguments_p->buffer_p, + arguments_p->item_count); + + ecma_collection_free (arguments_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_builder; + } + + /* 16.m.v */ + ecma_string_t *const replace_result_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (replace_result_p == NULL) + { + result = ECMA_VALUE_ERROR; + goto cleanup_builder; + } + + ecma_stringbuilder_append (&(ctx_p->builder), replace_result_p); + ecma_deref_ecma_string (replace_result_p); + } + + const ecma_regexp_capture_t *global_capture_p = re_ctx.captures_p; + last_append_p = global_capture_p->end_p; + + if (!(re_ctx.flags & RE_FLAG_GLOBAL)) + { + break; + } + + const lit_utf8_size_t matched_size = (lit_utf8_size_t) (global_capture_p->end_p - global_capture_p->begin_p); + if (matched_size > 0) + { + ctx_p->index += lit_utf8_string_length (current_p, matched_size); + current_p = last_append_p; + continue; + } + } + + if (current_p >= string_end_p) + { + break; + } + +#if ENABLED (JERRY_ES2015) + if ((re_ctx.flags & RE_FLAG_UNICODE) != 0) + { + ctx_p->index++; + const lit_code_point_t cp = ecma_regexp_unicode_advance (¤t_p, + string_end_p); + + if (cp > LIT_UTF16_CODE_UNIT_MAX) + { + ctx_p->index++; + } + + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + + ctx_p->index++; + lit_utf8_incr (¤t_p); + } + + const lit_utf8_size_t trailing_size = (lit_utf8_size_t) (string_end_p - last_append_p); + ecma_stringbuilder_append_raw (&(ctx_p->builder), last_append_p, trailing_size); + + result = ecma_make_string_value (ecma_stringbuilder_finalize (&(ctx_p->builder))); + goto cleanup_context; + +cleanup_builder: + ecma_stringbuilder_destroy (&(ctx_p->builder)); + +cleanup_context: + ecma_regexp_cleanup_context (&re_ctx); + + if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) ctx_p->string_p, ctx_p->string_size); + } + + return result; +} /* ecma_regexp_replace_helper_fast */ + +/** + * Helper function for RegExp based replacing + * + * See also: + * String.prototype.replace + * RegExp.prototype[@@replace] + * + * @return result string of the replacement, if successful + * error value, otherwise + */ +ecma_value_t +ecma_regexp_replace_helper (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg, /**< source string */ + ecma_value_t replace_arg) /**< replace string */ +{ + /* 2. */ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg); + + ecma_replace_context_t replace_ctx; + replace_ctx.index = 0; + + /* 3. */ + ecma_string_t *string_p = ecma_op_to_string (string_arg); + if (string_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ECMA_VALUE_ERROR; + + /* 6. */ + replace_ctx.replace_str_p = NULL; + if (!ecma_op_is_callable (replace_arg)) + { + replace_ctx.replace_str_p = ecma_op_to_string (replace_arg); + + if (replace_ctx.replace_str_p == NULL) + { + goto cleanup_string; + } + } + + /* 8 */ + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_GLOBAL); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + const bool global = ecma_op_to_boolean (result); + ecma_free_value (result); + +#if ENABLED (JERRY_ES2015) + const lit_utf8_size_t string_length = ecma_string_get_length (string_p); + bool unicode = false; +#endif /* ENABLED (JERRY_ES2015) */ + + /* 10. */ + if (global) + { +#if ENABLED (JERRY_ES2015) + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_UNICODE); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + unicode = ecma_op_to_boolean (result); + ecma_free_value (result); +#endif /* ENABLED (JERRY_ES2015) */ + + result = ecma_op_object_put (this_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + true); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + JERRY_ASSERT (ecma_is_value_boolean (result)); + } + +#if !ENABLED (JERRY_ES2015) + ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) this_obj_p; + const re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, + re_obj_p->u.class_prop.u.value); + + result = ecma_regexp_replace_helper_fast (&replace_ctx, + bc_p, + string_p, + replace_arg); + + goto cleanup_replace; +#else /* ENABLED (JERRY_ES2015) */ + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_EXEC); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + /* Check for fast path. */ + if (ecma_op_is_callable (result)) + { + ecma_extended_object_t *function_p = (ecma_extended_object_t *) ecma_get_object_from_value (result); + if (ecma_object_class_is (this_obj_p, LIT_MAGIC_STRING_REGEXP_UL) + && ecma_builtin_is_regexp_exec (function_p)) + { + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_STICKY); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + const bool sticky = ecma_op_to_boolean (result); + ecma_free_value (result); + + if (sticky && !global) + { + ecma_string_t *lastindex_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); + ecma_value_t lastindex_value = ecma_op_object_get_own_data_prop (this_obj_p, lastindex_str_p); + + result = ecma_op_to_length (lastindex_value, &replace_ctx.index); + ecma_free_value (lastindex_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_replace; + } + + if (replace_ctx.index > string_length) + { + ecma_deref_object ((ecma_object_t *) function_p); + + result = ecma_op_object_put (this_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + true); + JERRY_ASSERT (ecma_is_value_true (result)); + + ecma_ref_ecma_string (string_p); + result = ecma_make_string_value (string_p); + goto cleanup_replace; + } + } + + ecma_extended_object_t *re_obj_p = (ecma_extended_object_t *) this_obj_p; + const re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, + re_obj_p->u.class_prop.u.value); + + result = ecma_regexp_replace_helper_fast (&replace_ctx, + bc_p, + string_p, + replace_arg); + + ecma_deref_object ((ecma_object_t *) function_p); + goto cleanup_replace; + } + } + + ecma_collection_t *results_p = ecma_new_collection (); + + while (true) + { + /* 13.a */ + if (ecma_op_is_callable (result)) + { + ecma_object_t *const function_p = ecma_get_object_from_value (result); + + ecma_value_t arguments[] = { ecma_make_string_value (string_p) }; + result = ecma_op_function_call (function_p, this_arg, arguments, 1); + + ecma_deref_object (function_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_results; + } + + if (!ecma_is_value_object (result) && !ecma_is_value_null (result)) + { + ecma_free_value (result); + result = ecma_raise_type_error (ECMA_ERR_MSG ("Return value of 'exec' must be an Object or Null")); + goto cleanup_results; + } + } + else + { + ecma_free_value (result); + + if (!ecma_object_class_is (this_obj_p, LIT_MAGIC_STRING_REGEXP_UL)) + { + result = ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a valid RegExp object")); + goto cleanup_results; + } + + result = ecma_regexp_exec_helper (this_obj_p, string_p); + } + + /* 13.c */ + if (ecma_is_value_null (result)) + { + break; + } + + /* 13.d.i */ + ecma_collection_push_back (results_p, result); + + if (!global) + { + break; + } + + /* 13.d.iii.1 */ + result = ecma_op_object_get_by_uint32_index (ecma_get_object_from_value (result), 0); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_results; + } + + ecma_string_t *match_str_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (match_str_p == NULL) + { + result = ECMA_VALUE_ERROR; + goto cleanup_results; + } + + const bool is_empty = ecma_string_is_empty (match_str_p); + ecma_deref_ecma_string (match_str_p); + + /* 13.d.iii.3 */ + if (is_empty) + { + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_LASTINDEX_UL); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_results; + } + + uint32_t index; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (result, &index))) + { + ecma_free_value (result); + result = ECMA_VALUE_ERROR; + goto cleanup_results; + } + + ecma_free_value (result); + + index = ecma_op_advance_string_index (string_p, index, unicode); + + /* 10.d.iii.3.c */ + result = ecma_op_object_put (this_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (index), + true); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_results; + } + + JERRY_ASSERT (ecma_is_value_boolean (result)); + } + + result = ecma_op_object_get_by_magic_id (this_obj_p, LIT_MAGIC_STRING_EXEC); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_results; + } + } + + uint8_t string_flags = ECMA_STRING_FLAG_IS_ASCII; + replace_ctx.string_p = ecma_string_get_chars (string_p, + &(replace_ctx.string_size), + NULL, + NULL, + &string_flags); + + /* 14. */ + replace_ctx.builder = ecma_stringbuilder_create (); + replace_ctx.matched_p = NULL; + replace_ctx.capture_count = 0; + + /* 15. */ + const lit_utf8_byte_t *source_position_p = replace_ctx.string_p; + const lit_utf8_byte_t *const string_end_p = replace_ctx.string_p + replace_ctx.string_size; + + /* 16. */ + for (ecma_value_t *current_p = results_p->buffer_p; + current_p < results_p->buffer_p + results_p->item_count; + current_p++) + { + /* 16.a */ + ecma_object_t *current_object_p = ecma_get_object_from_value (*current_p); + + uint32_t capture_count; + result = ecma_op_object_get_length (current_object_p, &capture_count); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_builder; + } + + /* 16.c */ + capture_count = (capture_count > 0) ? capture_count - 1 : capture_count; + + /* 16.d */ + result = ecma_op_object_get_by_uint32_index (current_object_p, 0); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_builder; + } + + ecma_string_t *matched_str_p = ecma_op_to_string (result); + ecma_free_value (result); + + /* 16.e */ + if (matched_str_p == NULL) + { + result = ECMA_VALUE_ERROR; + goto cleanup_builder; + } + + /* 16.g */ + result = ecma_op_object_get_by_magic_id (current_object_p, LIT_MAGIC_STRING_INDEX); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_ecma_string (matched_str_p); + goto cleanup_builder; + } + + const ecma_value_t index_value = result; + + ecma_number_t position_num; + result = ecma_op_to_integer (index_value, &position_num); + ecma_free_value (index_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_ecma_string (matched_str_p); + goto cleanup_builder; + } + + /* 16.i */ + lit_utf8_size_t position = JERRY_MIN ((lit_utf8_size_t) JERRY_MAX (position_num, 0.0f), string_length); + + /* 16.k */ + ecma_collection_t *arguments_p = ecma_new_collection (); + ecma_collection_push_back (arguments_p, ecma_make_string_value (matched_str_p)); + + /* 16.j, l */ + uint32_t n = 1; + while (n <= capture_count) + { + result = ecma_op_object_get_by_uint32_index (current_object_p, n); + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_collection_free (arguments_p); + goto cleanup_builder; + } + + /* 16.l.iii */ + if (!ecma_is_value_undefined (result)) + { + ecma_string_t *capture_str_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (capture_str_p == NULL) + { + ecma_collection_free (arguments_p); + result = ECMA_VALUE_ERROR; + goto cleanup_builder; + } + + result = ecma_make_string_value (capture_str_p); + } + + /* 16.l.iv */ + ecma_collection_push_back (arguments_p, result); + n++; + } + + const bool should_replace = (position >= replace_ctx.index); + /* 16.p */ + if (should_replace) + { + const lit_utf8_byte_t *match_position_p; + const lit_utf8_size_t matched_str_size = ecma_string_get_size (matched_str_p); + const lit_utf8_size_t matched_str_length = ecma_string_get_length (matched_str_p); + + if (string_flags & ECMA_STRING_FLAG_IS_ASCII) + { + match_position_p = replace_ctx.string_p + position; + } + else + { + match_position_p = source_position_p; + lit_utf8_size_t distance = position - replace_ctx.index; + while (distance--) + { + lit_utf8_incr (&match_position_p); + } + } + + ecma_stringbuilder_append_raw (&replace_ctx.builder, + source_position_p, + (lit_utf8_size_t) (match_position_p - source_position_p)); + replace_ctx.match_byte_pos = (lit_utf8_size_t) (match_position_p - replace_ctx.string_p); + + if ((string_flags & ECMA_STRING_FLAG_IS_ASCII) && matched_str_size == matched_str_length) + { + source_position_p = JERRY_MIN (match_position_p + matched_str_size, string_end_p); + } + else + { + lit_utf8_size_t code_unit_count = matched_str_length; + + while (code_unit_count-- > 0 && JERRY_LIKELY (match_position_p < string_end_p)) + { + lit_utf8_incr (&match_position_p); + } + + source_position_p = match_position_p; + } + + replace_ctx.index = JERRY_MIN (position + matched_str_length, string_length); + } + + /* 16.m */ + if (replace_ctx.replace_str_p == NULL) + { + /* 16.m.i-ii. + * arguments_p already contains <> */ + + /* 16.m.iii */ + ecma_collection_push_back (arguments_p, ecma_make_uint32_value (position)); + ecma_ref_ecma_string (string_p); + ecma_collection_push_back (arguments_p, ecma_make_string_value (string_p)); + + result = ecma_op_function_call (ecma_get_object_from_value (replace_arg), + ECMA_VALUE_UNDEFINED, + arguments_p->buffer_p, + arguments_p->item_count); + + ecma_collection_free (arguments_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_builder; + } + + /* 16.m.v */ + ecma_string_t *const replace_result_p = ecma_op_to_string (result); + ecma_free_value (result); + + if (replace_result_p == NULL) + { + result = ECMA_VALUE_ERROR; + goto cleanup_builder; + } + + /* 16.m/p */ + if (should_replace) + { + ecma_stringbuilder_append (&replace_ctx.builder, replace_result_p); + } + + ecma_deref_ecma_string (replace_result_p); + } + else + { + /* 16.n/p */ + if (should_replace) + { + replace_ctx.u.collection_p = arguments_p; + ecma_builtin_replace_substitute (&replace_ctx); + } + + ecma_collection_free (arguments_p); + } + } + + /* 18. */ + JERRY_ASSERT (replace_ctx.index <= string_length); + ecma_stringbuilder_append_raw (&(replace_ctx.builder), + source_position_p, + (lit_utf8_size_t) (string_end_p - source_position_p)); + + result = ecma_make_string_value (ecma_stringbuilder_finalize (&replace_ctx.builder)); + goto cleanup_chars; + +cleanup_builder: + ecma_stringbuilder_destroy (&replace_ctx.builder); + +cleanup_chars: + if (string_flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) replace_ctx.string_p, replace_ctx.string_size); + } + +cleanup_results: + ecma_collection_free (results_p); +#endif /* !ENABLED (JERRY_ES2015) */ + +cleanup_replace: + if (replace_ctx.replace_str_p != NULL) + { + ecma_deref_ecma_string (replace_ctx.replace_str_p); + } + +cleanup_string: + ecma_deref_ecma_string (string_p); + + return result; +} /* ecma_regexp_replace_helper */ + +/** + * Helper function for RegExp based matching + * + * See also: + * String.prototype.match + * RegExp.prototype[@@match] + * + * @return ecma_value_t + */ +ecma_value_t +ecma_regexp_match_helper (ecma_value_t this_arg, /**< this argument */ + ecma_value_t string_arg) /**< source string */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + ecma_string_t *str_p = ecma_op_to_string (string_arg); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + + ecma_value_t global_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_GLOBAL); + + if (ECMA_IS_VALUE_ERROR (global_value)) + { + ecma_deref_ecma_string (str_p); + return global_value; + } + + bool global = ecma_op_to_boolean (global_value); + + ecma_free_value (global_value); + + if (!global) + { + ecma_value_t result = ecma_op_regexp_exec (this_arg, str_p); + ecma_deref_ecma_string (str_p); + return result; + } + +#if ENABLED (JERRY_ES2015) + ecma_value_t full_unicode_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_UNICODE); + + if (ECMA_IS_VALUE_ERROR (full_unicode_value)) + { + ecma_deref_ecma_string (str_p); + return full_unicode_value; + } + + bool full_unicode = ecma_op_to_boolean (full_unicode_value); + + ecma_free_value (full_unicode_value); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t set_status = ecma_op_object_put (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (0), + true); + + if (ECMA_IS_VALUE_ERROR (set_status)) + { + ecma_deref_ecma_string (str_p); + return set_status; + } + + ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_value_t result_array = ecma_op_create_array_object (0, 0, false); + ecma_object_t *result_array_p = ecma_get_object_from_value (result_array); + uint32_t n = 0; + + while (true) + { + ecma_value_t result_value = ecma_op_regexp_exec (this_arg, str_p); + + if (ECMA_IS_VALUE_ERROR (result_value)) + { + goto result_cleanup; + } + + if (ecma_is_value_null (result_value)) + { + if (n == 0) + { + ret_value = ECMA_VALUE_NULL; + goto result_cleanup; + } + + ecma_deref_ecma_string (str_p); + return result_array; + } + + ecma_object_t *result_value_p = ecma_get_object_from_value (result_value); + ecma_value_t match_str_value = ecma_op_object_get_by_uint32_index (result_value_p, 0); + + ecma_deref_object (result_value_p); + + if (ECMA_IS_VALUE_ERROR (match_str_value)) + { + goto result_cleanup; + } + + ecma_string_t *match_str_p = ecma_op_to_string (match_str_value); + + if (JERRY_UNLIKELY (match_str_p == NULL)) + { + ecma_free_value (match_str_value); + goto result_cleanup; + } + + ecma_value_t new_prop = ecma_builtin_helper_def_prop_by_index (result_array_p, + n, + match_str_value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_prop)); + + ecma_value_t match_result = ECMA_VALUE_ERROR; + if (ecma_string_is_empty (match_str_p)) + { + ecma_value_t this_index = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LASTINDEX_UL); + + if (ECMA_IS_VALUE_ERROR (this_index)) + { + goto match_cleanup; + } + +#if ENABLED (JERRY_ES2015) + uint32_t index; + ecma_value_t length_value = ecma_op_to_length (this_index, &index); + + ecma_free_value (this_index); + + if (ECMA_IS_VALUE_ERROR (length_value)) + { + goto match_cleanup; + } + + uint32_t next_index = ecma_op_advance_string_index (str_p, index, full_unicode); + + ecma_value_t next_set_status = ecma_op_object_put (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_uint32_value (next_index), + true); +#else /* !ENABLED (JERRY_ES2015) */ + ecma_number_t next_index = ecma_get_number_from_value (this_index); + + ecma_value_t next_set_status = ecma_op_object_put (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_number_value (next_index + 1), + true); + + ecma_free_value (this_index); +#endif /* ENABLED (JERRY_ES2015) */ + + if (ECMA_IS_VALUE_ERROR (next_set_status)) + { + goto match_cleanup; + } + } + + match_result = ECMA_VALUE_EMPTY; + +match_cleanup: + ecma_deref_ecma_string (match_str_p); + ecma_free_value (match_str_value); + + if (ECMA_IS_VALUE_ERROR (match_result)) + { + goto result_cleanup; + } + + n++; + } + +result_cleanup: + ecma_deref_ecma_string (str_p); + ecma_deref_object (result_array_p); + return ret_value; +} /* ecma_regexp_match_helper */ + +/** + * RegExpExec operation + * + * See also: + * ECMA-262 v6.0, 21.2.5.2.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_regexp_exec (ecma_value_t this_arg, /**< this argument */ + ecma_string_t *str_p) /**< input string */ +{ + ecma_object_t *arg_obj_p = ecma_get_object_from_value (this_arg); + +#if ENABLED (JERRY_ES2015) + ecma_value_t exec = ecma_op_object_get_by_magic_id (arg_obj_p, LIT_MAGIC_STRING_EXEC); + + if (ECMA_IS_VALUE_ERROR (exec)) + { + return exec; + } + + if (ecma_op_is_callable (exec)) + { + ecma_object_t *function_p = ecma_get_object_from_value (exec); + ecma_value_t arguments[] = { ecma_make_string_value (str_p) }; + + ecma_value_t result = ecma_op_function_call (function_p, this_arg, arguments, 1); + + ecma_deref_object (function_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + if (!ecma_is_value_object (result) && !ecma_is_value_null (result)) + { + ecma_free_value (result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Return value of 'exec' must be an Object or Null")); + } + + return result; + } + else + { + ecma_free_value (exec); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (!ecma_object_is_regexp_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a valid RegExp object")); + } + + return ecma_regexp_exec_helper (arg_obj_p, str_p); +} /* ecma_op_regexp_exec */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-regexp-object.h b/jerry-core/ecma/operations/ecma-regexp-object.h index 1b1c6e54..fdc9971c 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.h +++ b/jerry-core/ecma/operations/ecma-regexp-object.h @@ -38,25 +38,78 @@ typedef enum RE_FLAG_EMPTY = 0u, /* Empty RegExp flags */ RE_FLAG_GLOBAL = (1u << 1), /**< ECMA-262 v5, 15.10.7.2 */ RE_FLAG_IGNORE_CASE = (1u << 2), /**< ECMA-262 v5, 15.10.7.3 */ - RE_FLAG_MULTILINE = (1u << 3) /**< ECMA-262 v5, 15.10.7.4 */ + RE_FLAG_MULTILINE = (1u << 3), /**< ECMA-262 v5, 15.10.7.4 */ + RE_FLAG_STICKY = (1u << 4), /**< ECMA-262 v6, 21.2.5.12 */ + RE_FLAG_UNICODE = (1u << 5) /**< ECMA-262 v6, 21.2.5.15 */ } ecma_regexp_flags_t; /** - * Structure for storing capturing group results + * Class escapes + */ +typedef enum +{ + RE_ESCAPE__START, /**< escapes start */ + RE_ESCAPE_DIGIT = RE_ESCAPE__START, /**< digit */ + RE_ESCAPE_NOT_DIGIT, /**< not digit */ + RE_ESCAPE_WORD_CHAR, /**< word char */ + RE_ESCAPE_NOT_WORD_CHAR, /**< not word char */ + RE_ESCAPE_WHITESPACE, /**< whitespace */ + RE_ESCAPE_NOT_WHITESPACE, /**< not whitespace */ + RE_ESCAPE__COUNT, /**< escape count */ +} ecma_class_escape_t; + +/** + * Character class flags escape count mask size. + */ +#define RE_CLASS_ESCAPE_COUNT_MASK_SIZE (3u) + +/** + * Character class flags escape count mask. + */ +#define RE_CLASS_ESCAPE_COUNT_MASK ((1 << RE_CLASS_ESCAPE_COUNT_MASK_SIZE) - 1u) + +/** + * Character class flags that are present in the upper bits of the class flags byte, while the 3 least significant bits + * hold a value that contains the number of class escapes present in the character class. + */ +typedef enum +{ + RE_CLASS_HAS_CHARS = (1 << 5), /**< contains individual characters */ + RE_CLASS_HAS_RANGES = (1 << 6), /**< contains character ranges */ + RE_CLASS_INVERT = (1 << 7), /**< inverted */ +} ecma_char_class_flags_t; + +/** + * Structure for matching capturing groups and storing their result + */ +typedef struct +{ + const lit_utf8_byte_t *begin_p; /**< capture start pointer */ + const lit_utf8_byte_t *end_p; /**< capture end pointer */ + const uint8_t *bc_p; /**< group bytecode pointer */ + uint32_t iterator; /**< iteration counter */ + uint32_t subcapture_count; /**< number of nested capturing groups */ +} ecma_regexp_capture_t; + +/** + * Structure for matching non-capturing groups */ typedef struct { const lit_utf8_byte_t *begin_p; /**< substring start pointer */ - const lit_utf8_byte_t *end_p; /**< substring end pointer */ -} ecma_regexp_capture_t; + const uint8_t *bc_p; /**< group bytecode pointer */ + uint32_t iterator; /**< iteration counter */ + uint32_t subcapture_start; /**< first nested capturing group index */ + uint32_t subcapture_count; /**< number of nested capturing groups */ +} ecma_regexp_non_capture_t; /** - * Structure for storing non-capturing group results + * Check if an ecma_regexp_capture_t contains a defined capture */ -typedef struct -{ - const lit_utf8_byte_t *str_p; /**< string pointer */ -} ecma_regexp_non_capture_t; +#define ECMA_RE_IS_CAPTURE_DEFINED(c) ((c)->begin_p != NULL) + +ecma_value_t +ecma_regexp_get_capture_value (const ecma_regexp_capture_t *const capture_p); #if (JERRY_STACK_LIMIT != 0) /** @@ -72,30 +125,56 @@ typedef struct #define ECMA_RE_STACK_LIMIT_REACHED(p) (false) #endif /* JERRY_STACK_LIMIT != 0 */ +/** + * Offset applied to qmax when encoded into the bytecode. + * + * It's common for qmax to be Infinity, which is represented a UINT32_MAX. By applying the offset we are able to store + * it in a single byte az zero. + */ +#define RE_QMAX_OFFSET 1 + /** * RegExp executor context */ typedef struct { - const lit_utf8_byte_t *input_end_p; /**< end of input string */ const lit_utf8_byte_t *input_start_p; /**< start of input string */ + const lit_utf8_byte_t *input_end_p; /**< end of input string */ uint32_t captures_count; /**< number of capture groups */ - ecma_regexp_capture_t *captures_p; /**< capturing groups */ uint32_t non_captures_count; /**< number of non-capture groups */ + ecma_regexp_capture_t *captures_p; /**< capturing groups */ ecma_regexp_non_capture_t *non_captures_p; /**< non-capturing groups */ - uint32_t *iterations_p; /**< number of iterations */ uint16_t flags; /**< RegExp flags */ + uint8_t char_size; /**< size of encoded characters */ } ecma_regexp_ctx_t; -ecma_value_t ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p); -ecma_value_t ecma_op_create_regexp_object (ecma_string_t *pattern_p, uint16_t flags); -ecma_value_t ecma_regexp_exec_helper (ecma_value_t regexp_value, ecma_value_t input_string, bool ignore_global); -ecma_value_t ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg, ecma_string_t **pattern_string_p); -ecma_char_t ecma_regexp_canonicalize (ecma_char_t ch, bool is_ignorecase); -ecma_char_t ecma_regexp_canonicalize_char (ecma_char_t ch); -ecma_value_t ecma_regexp_parse_flags (ecma_string_t *flags_str_p, uint16_t *flags_p); -void ecma_regexp_initialize_props (ecma_object_t *re_obj_p, ecma_string_t *source_p, uint16_t flags); +#if ENABLED (JERRY_ES2015) +lit_code_point_t ecma_regexp_unicode_advance (const lit_utf8_byte_t **str_p, const lit_utf8_byte_t *end_p); +#endif /* ENABLED (JERRY_ES2015) */ +ecma_object_t *ecma_op_regexp_alloc (ecma_object_t *new_target_obj_p); +ecma_value_t ecma_regexp_exec_helper (ecma_object_t *regexp_object_p, + ecma_string_t *input_string_p); +ecma_string_t *ecma_regexp_read_pattern_str_helper (ecma_value_t pattern_arg); +lit_code_point_t ecma_regexp_canonicalize_char (lit_code_point_t ch, bool unicode); +ecma_value_t ecma_regexp_parse_flags (ecma_string_t *flags_str_p, uint16_t *flags_p); +void ecma_regexp_create_and_initialize_props (ecma_object_t *re_object_p, + ecma_string_t *source_p, + uint16_t flags); +ecma_value_t ecma_regexp_replace_helper (ecma_value_t this_arg, ecma_value_t string_arg, ecma_value_t replace_arg); +ecma_value_t ecma_regexp_search_helper (ecma_value_t regexp_arg, ecma_value_t string_arg); +ecma_value_t ecma_regexp_split_helper (ecma_value_t this_arg, ecma_value_t string_arg, ecma_value_t limit_arg); +ecma_value_t ecma_regexp_match_helper (ecma_value_t this_arg, ecma_value_t string_arg); + +ecma_value_t ecma_op_regexp_exec (ecma_value_t this_arg, ecma_string_t *str_p); + +ecma_value_t ecma_op_create_regexp_from_bytecode (ecma_object_t *regexp_obj_p, re_compiled_code_t *bc_p); +ecma_value_t ecma_op_create_regexp_from_pattern (ecma_object_t *regexp_obj_p, + ecma_value_t pattern_value, + ecma_value_t flags_value); +ecma_value_t ecma_op_create_regexp_with_flags (ecma_object_t *regexp_obj_p, + ecma_value_t pattern_value, + uint16_t flags); /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-string-object.c b/jerry-core/ecma/operations/ecma-string-object.c index 2f3a11ec..4b752ff4 100644 --- a/jerry-core/ecma/operations/ecma-string-object.c +++ b/jerry-core/ecma/operations/ecma-string-object.c @@ -50,14 +50,14 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of if (arguments_list_len > 0) { - prim_value = ecma_op_to_string (arguments_list_p[0]); + ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); - if (ECMA_IS_VALUE_ERROR (prim_value)) + if (JERRY_UNLIKELY (str_p == NULL)) { - return prim_value; + return ECMA_VALUE_ERROR; } - JERRY_ASSERT (ecma_is_value_string (prim_value)); + prim_value = ecma_make_string_value (str_p); } #if ENABLED (JERRY_BUILTIN_STRING) @@ -84,13 +84,8 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of */ void ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, /**< a String object */ - bool separate_enumerable, /**< true - list enumerable properties - * into main collection, - * and non-enumerable to collection of - * 'skipped non-enumerable' properties, - * false - list all properties into main - * collection. - */ + uint32_t opts, /**< listing options using flags + * from ecma_list_properties_options_t */ ecma_collection_t *main_collection_p, /**< 'main' collection */ ecma_collection_t *non_enum_collection_p) /**< skipped * 'non-enumerable' @@ -100,7 +95,7 @@ ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, /**< a String obj ecma_collection_t *for_enumerable_p = main_collection_p; - ecma_collection_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p; ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_STRING_UL); @@ -117,7 +112,10 @@ ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, /**< a String obj ecma_collection_push_back (for_enumerable_p, ecma_make_string_value (name_p)); } - ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + if ((opts & ECMA_LIST_ARRAY_INDICES) == 0) + { + ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH)); + } } /* ecma_op_string_list_lazy_property_names */ /** diff --git a/jerry-core/ecma/operations/ecma-string-object.h b/jerry-core/ecma/operations/ecma-string-object.h index b1c4b7ad..7fdacebc 100644 --- a/jerry-core/ecma/operations/ecma-string-object.h +++ b/jerry-core/ecma/operations/ecma-string-object.h @@ -30,11 +30,10 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, ecma_length_ void ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, - bool separate_enumerable, + uint32_t opts, ecma_collection_t *main_collection_p, ecma_collection_t *non_enum_collection_p); - /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-symbol-object.c b/jerry-core/ecma/operations/ecma-symbol-object.c index 818cdf95..1dc09d81 100644 --- a/jerry-core/ecma/operations/ecma-symbol-object.c +++ b/jerry-core/ecma/operations/ecma-symbol-object.c @@ -22,8 +22,9 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-symbol-object.h" +#include "lit-char-helpers.h" -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) /** \addtogroup ecma ECMA * @{ @@ -55,15 +56,15 @@ ecma_op_create_symbol (const ecma_value_t *arguments_list_p, /**< list of argume } else { - string_desc = ecma_op_to_string (arguments_list_p[0]); + ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); /* 4. */ - if (ECMA_IS_VALUE_ERROR (string_desc)) + if (JERRY_UNLIKELY (str_p == NULL)) { - return string_desc; + return ECMA_VALUE_ERROR; } - JERRY_ASSERT (ecma_is_value_string (string_desc)); + string_desc = ecma_make_string_value (str_p); } /* 5. */ @@ -83,12 +84,7 @@ ecma_op_create_symbol_object (const ecma_value_t value) /**< symbol value */ { JERRY_ASSERT (ecma_is_value_symbol (value)); -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE); -#else /* !ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ - ecma_object_t *object_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); @@ -133,12 +129,11 @@ ecma_get_symbol_descriptive_string (ecma_value_t symbol_value) /**< symbol to st ecma_string_t *string_desc_p = ecma_get_symbol_description (symbol_p); /* 5. */ - ecma_string_t *concat_p = ecma_concat_ecma_strings (ecma_get_magic_string (LIT_MAGIC_STRING_SYMBOL_LEFT_PAREN_UL), - string_desc_p); + ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) ("Symbol("), 7); + ecma_stringbuilder_append (&builder, string_desc_p); + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_RIGHT_PAREN); - ecma_string_t *final_str_p = ecma_append_magic_string_to_string (concat_p, LIT_MAGIC_STRING_RIGHT_PAREN); - - return ecma_make_string_value (final_str_p); + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_get_symbol_descriptive_string */ /** @@ -178,7 +173,7 @@ ecma_symbol_to_string_helper (ecma_value_t this_arg, /**< this argument value */ return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is must be a Symbol.")); } /* ecma_symbol_to_string_helper */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-symbol-object.h b/jerry-core/ecma/operations/ecma-symbol-object.h index b5721da3..a86d8774 100644 --- a/jerry-core/ecma/operations/ecma-symbol-object.h +++ b/jerry-core/ecma/operations/ecma-symbol-object.h @@ -16,7 +16,7 @@ #ifndef ECMA_SYMBOL_H #define ECMA_SYMBOL_H -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) #include "ecma-globals.h" /** \addtogroup ecma ECMA @@ -44,7 +44,7 @@ ecma_symbol_to_string_helper (ecma_value_t this_arg, bool is_to_string); ecma_value_t ecma_get_symbol_descriptive_string (ecma_value_t symbol_value); -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 58997955..4a99e57c 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -15,6 +15,7 @@ #include +#include "ecma-iterator-object.h" #include "ecma-typedarray-object.h" #include "ecma-arraybuffer-object.h" #include "ecma-function-object.h" @@ -123,7 +124,6 @@ ecma_typedarray_get_double_element (lit_utf8_byte_t *src) /**< the location in t return (ecma_number_t) num; } /* ecma_typedarray_get_double_element */ - /** * Normalize the given ecma_number_t to an uint32_t value */ @@ -169,7 +169,6 @@ ecma_typedarray_set_int8_element (lit_utf8_byte_t *dst_p, /**< the location in t *dst_p = (lit_utf8_byte_t) num; } /* ecma_typedarray_set_int8_element */ - /** * Write an uint8_t value into the given arraybuffer */ @@ -223,7 +222,6 @@ ecma_typedarray_set_int16_element (lit_utf8_byte_t *dst_p, /**< the location in memcpy (dst_p, &num, sizeof (int16_t)); } /* ecma_typedarray_set_int16_element */ - /** * Write an uint8_t value into the given arraybuffer */ @@ -246,7 +244,6 @@ ecma_typedarray_set_int32_element (lit_utf8_byte_t *dst_p, /**< the location in memcpy (dst_p, &num, sizeof (int32_t)); } /* ecma_typedarray_set_int32_element */ - /** * Write an uint32_t value into the given arraybuffer */ @@ -258,7 +255,6 @@ ecma_typedarray_set_uint32_element (lit_utf8_byte_t *dst_p, /**< the location in memcpy (dst_p, &num, sizeof (uint32_t)); } /* ecma_typedarray_set_uint32_element */ - /** * Write a float value into the given arraybuffer */ @@ -283,7 +279,6 @@ ecma_typedarray_set_double_element (lit_utf8_byte_t *dst_p, /**< the location in } /* ecma_typedarray_set_double_element */ #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */ - /** * Builtin id of the first %TypedArray% builtin routine intrinsic object */ @@ -458,6 +453,17 @@ ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id) / return (ecma_builtin_id_t) (ECMA_FIRST_TYPEDARRAY_BUILTIN_PROTOTYPE_ID + typedarray_id); } /* ecma_typedarray_helper_get_prototype_id */ +/** + * Get the constructor ID of a TypedArray type. + * + * @return ecma_builtin_id_t + */ +ecma_builtin_id_t +ecma_typedarray_helper_get_constructor_id (ecma_typedarray_type_t typedarray_id) /**< the id of the typedarray **/ +{ + return (ecma_builtin_id_t) (ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID + typedarray_id); +} /* ecma_typedarray_helper_get_constructor_id */ + /** * Get the built-in TypedArray type of the given object. * @@ -466,7 +472,7 @@ ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id) / ecma_typedarray_type_t ecma_get_typedarray_id (ecma_object_t *obj_p) /**< typedarray object **/ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (obj_p))); + JERRY_ASSERT (ecma_object_is_typedarray (obj_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; @@ -496,6 +502,7 @@ ecma_typedarray_helper_builtin_to_typedarray_id (ecma_builtin_id_t builtin_id) */ ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */ + ecma_object_t *src_buffer_p, /**< source buffer */ ecma_object_t *proto_p, /**< prototype object */ uint8_t element_size_shift, /**< the size shift of the element length */ ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ @@ -512,7 +519,42 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); } - ecma_object_t *new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length); + ecma_object_t *new_arraybuffer_p = NULL; + if (src_buffer_p == NULL) + { + new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length); + } + else + { +#if ENABLED (JERRY_ES2015) + ecma_value_t ctor_proto = ecma_op_species_constructor (src_buffer_p, ECMA_BUILTIN_ID_ARRAYBUFFER); +#else + ecma_value_t ctor_proto = ECMA_VALUE_ERROR; +#endif /* ENABLED (JERRY_ES2015) */ + if (ECMA_IS_VALUE_ERROR (ctor_proto)) + { + return ctor_proto; + } + + ecma_object_t *ctor_proto_p = ecma_get_object_from_value (ctor_proto); + + ecma_object_t *prototype_p = ecma_op_get_prototype_from_constructor (ctor_proto_p, + ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); + + ecma_deref_object (ctor_proto_p); + + if (JERRY_UNLIKELY (prototype_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length); + + ECMA_SET_NON_NULL_POINTER (new_arraybuffer_p->u2.prototype_cp, prototype_p); + + ecma_deref_object (prototype_p); + } + ecma_object_t *object_p = ecma_create_object (proto_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_PSEUDO_ARRAY); @@ -544,6 +586,10 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th uint8_t element_size_shift, /**< the size shift of the element length */ ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ { + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_length_t expected_length = (ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift); bool needs_ext_typedarray_obj = (byte_offset != 0 || array_length != expected_length); @@ -586,8 +632,14 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ { ecma_length_t array_length = ecma_typedarray_get_length (typedarray_p); + ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (src_arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer.")); + } ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (array_length, + src_arraybuffer_p, proto_p, element_size_shift, typedarray_id); @@ -599,7 +651,6 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); - ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); lit_utf8_byte_t *src_buf_p = ecma_arraybuffer_get_buffer (src_arraybuffer_p); ecma_object_t *dst_arraybuffer_p = ecma_typedarray_get_arraybuffer (new_typedarray_p); @@ -620,7 +671,6 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< ecma_typedarray_getter_fn_t src_typedarray_getter_cb = ecma_get_typedarray_getter_fn (src_id); ecma_typedarray_setter_fn_t target_typedarray_setter_cb = ecma_get_typedarray_setter_fn (typedarray_id); - for (uint32_t i = 0; i < array_length; i++) { /* Convert values from source to destination format. */ @@ -636,7 +686,64 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< } /* ecma_typedarray_create_object_with_typedarray */ /** - * Create a TypedArray object by transforming from an array-like object + * Helper method for ecma_op_typedarray_from + * + * @return ECMA_VALUE_TRUE - if setting the given value to the new typedarray was successful + * ECMA_VALUE_ERROR - otherwise + */ +static ecma_value_t +ecma_op_typedarray_from_helper (ecma_value_t this_val, /**< this_arg for the above from function */ + ecma_value_t current_value, /**< given value to set */ + uint32_t index, /**< currrent index */ + ecma_object_t *func_object_p, /**< map function object */ + ecma_typedarray_info_t *info_p, /**< typedarray info */ + ecma_typedarray_setter_fn_t setter_cb) /**< setter callback function */ +{ + ecma_value_t mapped_value; + if (func_object_p != NULL) + { + /* 17.d 17.f */ + ecma_value_t current_index = ecma_make_uint32_value (index); + ecma_value_t call_args[] = { current_value, current_index }; + + ecma_value_t cb_value = ecma_op_function_call (func_object_p, this_val, call_args, 2); + + ecma_free_value (current_index); + ecma_free_value (current_value); + + if (ECMA_IS_VALUE_ERROR (cb_value)) + { + return cb_value; + } + + mapped_value = cb_value; + } + else + { + mapped_value = current_value; + } + + ecma_number_t num_var; + ecma_value_t mapped_number = ecma_get_number (mapped_value, &num_var); + ecma_free_value (mapped_value); + + if (ECMA_IS_VALUE_ERROR (mapped_number)) + { + return mapped_number; + } + + if (index >= info_p->length) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); + } + + setter_cb (info_p->buffer_p + (index << info_p->shift), num_var); + + return ECMA_VALUE_TRUE; +} /* ecma_op_typedarray_from_helper */ + +/** + * Create a TypedArray object by transforming from an array-like object or iterable object * * See also: ES2015 22.2.2.1 * @@ -651,126 +758,207 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje uint8_t element_size_shift, /**< the size shift of the element length */ ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - /* 3 */ JERRY_ASSERT (ecma_op_is_callable (map_fn_val) || ecma_is_value_undefined (map_fn_val)); + /* 4-5 */ ecma_object_t *func_object_p = NULL; if (!ecma_is_value_undefined (map_fn_val)) { func_object_p = ecma_get_object_from_value (map_fn_val); } +#if ENABLED (JERRY_ES2015) + /* 6 */ + ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items_val, LIT_GLOBAL_SYMBOL_ITERATOR); + + /* 7 */ + if (ECMA_IS_VALUE_ERROR (using_iterator)) + { + return using_iterator; + } + + /* 8 */ + if (!ecma_is_value_undefined (using_iterator)) + { + /* 8.a */ + ecma_value_t iterator = ecma_op_get_iterator (items_val, using_iterator); + ecma_free_value (using_iterator); + + /* 8.b */ + if (ECMA_IS_VALUE_ERROR (iterator)) + { + return iterator; + } + + /* 8.c */ + ecma_collection_t *values_p = ecma_new_collection (); + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + /* 8.e */ + while (true) + { + /* 8.e.i */ + ecma_value_t next = ecma_op_iterator_step (iterator); + + /* 8.e.ii */ + if (ECMA_IS_VALUE_ERROR (next)) + { + ret_value = next; + break; + } + + if (next == ECMA_VALUE_FALSE) + { + break; + } + + /* 8.e.iii */ + ecma_value_t next_value = ecma_op_iterator_value (next); + ecma_free_value (next); + + if (ECMA_IS_VALUE_ERROR (next_value)) + { + ret_value = next_value; + break; + } + + ecma_collection_push_back (values_p, next_value); + } + + ecma_free_value (iterator); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_collection_free (values_p); + return ret_value; + } + + /* 8.g */ + ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (values_p->item_count, + NULL, + proto_p, + element_size_shift, + typedarray_id); + + /* 8.h */ + if (ECMA_IS_VALUE_ERROR (new_typedarray)) + { + ecma_collection_free (values_p); + return new_typedarray; + } + + ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); + ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p); + ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id); + + ret_value = ecma_make_object_value (new_typedarray_p); + + /* 8.j */ + for (uint32_t index = 0; index < values_p->item_count; index++) + { + ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val, + values_p->buffer_p[index], + index, + func_object_p, + &info, + setter_cb); + + if (ECMA_IS_VALUE_ERROR (set_value)) + { + for (uint32_t j = index + 1; j < values_p->item_count; j++) + { + ecma_free_value (values_p->buffer_p[j]); + } + + ret_value = set_value; + break; + } + } + + ecma_collection_destroy (values_p); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_deref_object (new_typedarray_p); + } + + return ret_value; + } +#endif /* ENABLED (JERRY_ES2015) */ + /* 10 */ - ECMA_TRY_CATCH (arraylike_object_val, - ecma_op_to_object (items_val), - ret_value); + ecma_value_t arraylike_object_val = ecma_op_to_object (items_val); + + if (ECMA_IS_VALUE_ERROR (arraylike_object_val)) + { + return arraylike_object_val; + } ecma_object_t *arraylike_object_p = ecma_get_object_from_value (arraylike_object_val); /* 12 */ - ECMA_TRY_CATCH (len_value, - ecma_op_object_get_by_magic_id (arraylike_object_p, LIT_MAGIC_STRING_LENGTH), - ret_value); + uint32_t len; + ecma_value_t len_value = ecma_op_object_get_length (arraylike_object_p, &len); - ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value); - - uint32_t len = ecma_number_to_uint32 (len_number); + if (ECMA_IS_VALUE_ERROR (len_value)) + { + ecma_deref_object (arraylike_object_p); + return len_value; + } /* 14 */ ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (len, + NULL, proto_p, element_size_shift, typedarray_id); if (ECMA_IS_VALUE_ERROR (new_typedarray)) { - ret_value = new_typedarray; + ecma_deref_object (arraylike_object_p); + return new_typedarray; } - else + + ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); + ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p); + ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id); + ecma_value_t ret_value = ecma_make_object_value (new_typedarray_p); + + /* 17 */ + for (uint32_t index = 0; index < len; index++) { - ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); - ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p); - ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id); - ecma_value_t error = ECMA_VALUE_EMPTY; - ecma_number_t num_var; + ecma_value_t current_value = ecma_op_object_find_by_uint32_index (arraylike_object_p, index); - /* 17 */ - ecma_value_t current_index; - - for (uint32_t index = 0; index < len && ecma_is_value_empty (ret_value); index++) + if (ECMA_IS_VALUE_ERROR (current_value)) { - /* 17.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); + ret_value = current_value; + break; + } - /* 17.b */ - ECMA_TRY_CATCH (current_value, ecma_op_object_find (arraylike_object_p, index_str_p), ret_value); + if (ecma_is_value_found (current_value)) + { + ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val, + current_value, + index, + func_object_p, + &info, + setter_cb); - if (ecma_is_value_found (current_value)) + if (ECMA_IS_VALUE_ERROR (set_value)) { - if (func_object_p != NULL) - { - /* 17.d 17.f */ - current_index = ecma_make_uint32_value (index); - ecma_value_t call_args[] = { current_value, current_index}; - - ECMA_TRY_CATCH (mapped_value, ecma_op_function_call (func_object_p, this_val, call_args, 2), ret_value); - - error = ecma_get_number (mapped_value, &num_var); - - if (ECMA_IS_VALUE_ERROR (error)) - { - ret_value = ECMA_VALUE_ERROR; - } - - if (index >= info.length) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); - } - - ecma_length_t byte_pos = index << info.shift; - setter_cb (info.buffer_p + byte_pos, num_var); - - ECMA_FINALIZE (mapped_value); - } - else - { - error = ecma_get_number (current_value, &num_var); - - if (ECMA_IS_VALUE_ERROR (error)) - { - ret_value = ECMA_VALUE_ERROR; - } - - if (index >= info.length) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); - } - - ecma_length_t byte_pos = index << info.shift; - setter_cb (info.buffer_p + byte_pos, num_var); - } + ret_value = set_value; + break; } - - ECMA_FINALIZE (current_value); - - ecma_deref_ecma_string (index_str_p); - } - - if (ecma_is_value_empty (ret_value)) - { - ret_value = ecma_make_object_value (new_typedarray_p); - } - else - { - ecma_deref_object (new_typedarray_p); } } - ECMA_OP_TO_NUMBER_FINALIZE (len_number); - ECMA_FINALIZE (len_value); - ECMA_FINALIZE (arraylike_object_val); + ecma_deref_object (arraylike_object_p); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_deref_object (new_typedarray_p); + } return ret_value; } /* ecma_op_typedarray_from */ @@ -783,7 +971,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje inline ecma_object_t * JERRY_ATTR_ALWAYS_INLINE ecma_typedarray_get_arraybuffer (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (typedarray_p))); + JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p; @@ -798,12 +986,11 @@ ecma_typedarray_get_arraybuffer (ecma_object_t *typedarray_p) /**< the pointer t uint8_t ecma_typedarray_get_element_size_shift (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (typedarray_p))); + JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p)); return ecma_typedarray_helper_get_shift_size (ecma_get_typedarray_id (typedarray_p)); } /* ecma_typedarray_get_element_size_shift */ - /** * Get the array length of the typedarray object * @@ -812,7 +999,7 @@ ecma_typedarray_get_element_size_shift (ecma_object_t *typedarray_p) /**< the po ecma_length_t ecma_typedarray_get_length (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (typedarray_p))); + JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p; @@ -825,6 +1012,12 @@ ecma_typedarray_get_length (ecma_object_t *typedarray_p) /**< the pointer to the return buffer_length >> shift; } + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return 0; + } + ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p; return info_p->array_length; @@ -838,7 +1031,7 @@ ecma_typedarray_get_length (ecma_object_t *typedarray_p) /**< the pointer to the ecma_length_t ecma_typedarray_get_offset (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (typedarray_p))); + JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p; @@ -847,6 +1040,12 @@ ecma_typedarray_get_offset (ecma_object_t *typedarray_p) /**< the pointer to the return 0; } + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return 0; + } + ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p; return info_p->byte_offset; @@ -890,7 +1089,7 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li if (arguments_list_len == 0) { /* 22.2.1.1 */ - ret = ecma_typedarray_create_object_with_length (0, proto_p, element_size_shift, typedarray_id); + ret = ecma_typedarray_create_object_with_length (0, NULL, proto_p, element_size_shift, typedarray_id); } else if (!ecma_is_value_object (arguments_list_p[0])) { @@ -911,6 +1110,7 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li else { ret = ecma_typedarray_create_object_with_length (length, + NULL, proto_p, element_size_shift, typedarray_id); @@ -920,33 +1120,40 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li } else if (ecma_is_value_object (arguments_list_p[0])) { - if (ecma_is_typedarray (arguments_list_p[0])) + ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list_p[0]); + if (ecma_object_is_typedarray (obj_p)) { /* 22.2.1.3 */ - ecma_object_t *typedarray_p = ecma_get_object_from_value (arguments_list_p[0]); + ecma_object_t *typedarray_p = obj_p; ret = ecma_typedarray_create_object_with_typedarray (typedarray_p, proto_p, element_size_shift, typedarray_id); } - else if (ecma_is_arraybuffer (arguments_list_p[0])) + else if (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)) { /* 22.2.1.5 */ - ecma_object_t *arraybuffer_p = ecma_get_object_from_value (arguments_list_p[0]); + ecma_object_t *arraybuffer_p = obj_p; ecma_value_t arg2 = ((arguments_list_len > 1) ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED); ecma_value_t arg3 = ((arguments_list_len > 2) ? arguments_list_p[2] : ECMA_VALUE_UNDEFINED); - ECMA_OP_TO_NUMBER_TRY_CATCH (num2, arg2, ret); + ecma_number_t offset; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg2, &offset))) + { + return ECMA_VALUE_ERROR; + } - uint32_t offset = ecma_number_to_uint32 (num2); - - if (ecma_number_is_negative (ecma_number_to_int32 (num2)) || (offset % (uint32_t) (1 << element_size_shift) != 0)) + if (ecma_number_is_negative (offset)) { ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset.")); } + else if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + ret = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer.")); + } else { ecma_length_t buf_byte_length = ecma_arraybuffer_get_length (arraybuffer_p); @@ -969,11 +1176,13 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li } else { - ECMA_OP_TO_NUMBER_TRY_CATCH (num3, arg3, ret); - int32_t new_length = ecma_number_to_int32 (num3); - new_length = (new_length > 0) ? new_length : 0; + uint32_t new_length; + if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (arg3, &new_length))) + { + return ECMA_VALUE_ERROR; + } - if ((uint32_t) new_length > (UINT32_MAX >> element_size_shift)) + if (new_length > (UINT32_MAX >> element_size_shift)) { ret = ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); } @@ -981,28 +1190,24 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li { new_byte_length = (ecma_length_t) new_length << element_size_shift; - if (new_byte_length + offset > buf_byte_length) + if (((ecma_number_t) new_byte_length + offset) > buf_byte_length) { ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid length.")); } } - - ECMA_OP_TO_NUMBER_FINALIZE (num3); } if (ecma_is_value_empty (ret)) { ecma_length_t array_length = new_byte_length >> element_size_shift; ret = ecma_typedarray_create_object_with_buffer (arraybuffer_p, - offset, + (ecma_length_t) offset, array_length, proto_p, element_size_shift, typedarray_id); } } - - ECMA_OP_TO_NUMBER_FINALIZE (num2); } else { @@ -1020,6 +1225,28 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li return ret; } /* ecma_op_create_typedarray */ +/** + * Check if the object is typedarray + * + * @return true - if object is a TypedArray object + * false - otherwise + */ +bool +ecma_object_is_typedarray (ecma_object_t *obj_p) /**< the target object need to be checked */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_PSEUDO_ARRAY) + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; + + return ((ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY) + || (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO)); + } + + return false; +} /* ecma_object_is_typedarray */ + /** * Check if the value is typedarray * @@ -1034,17 +1261,7 @@ ecma_is_typedarray (ecma_value_t value) /**< the target need to be checked */ return false; } - ecma_object_t *obj_p = ecma_get_object_from_value (value); - - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_PSEUDO_ARRAY) - { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - - return ((ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY) - || (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO)); - } - - return false; + return ecma_object_is_typedarray (ecma_get_object_from_value (value)); } /* ecma_is_typedarray */ /** @@ -1056,7 +1273,7 @@ void ecma_op_typedarray_list_lazy_property_names (ecma_object_t *obj_p, /**< a TypedArray object */ ecma_collection_t *main_collection_p) /**< 'main' collection */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (obj_p))); + JERRY_ASSERT (ecma_object_is_typedarray (obj_p)); ecma_length_t array_length = ecma_typedarray_get_length (obj_p); @@ -1081,7 +1298,7 @@ ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray ob const ecma_property_descriptor_t *property_desc_p) /**< the description of the prop */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (obj_p))); + JERRY_ASSERT (ecma_object_is_typedarray (obj_p)); ecma_length_t array_length = ecma_typedarray_get_length (obj_p); @@ -1104,7 +1321,7 @@ ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray ob if (ECMA_IS_VALUE_ERROR (error)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return false; } ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); @@ -1128,52 +1345,19 @@ ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray ob * @return ecma_value_t */ ecma_value_t -ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, /**< TypedArray object - * indicates the type */ +ecma_op_create_typedarray_with_type_and_length (ecma_typedarray_type_t typedarray_id, /** TypedArray id */ ecma_length_t array_length) /**< length of the typedarray */ { - JERRY_ASSERT (ecma_is_typedarray (ecma_make_object_value (obj_p))); - -#if ENABLED (JERRY_ES2015_CLASS) - ecma_value_t constructor_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); - - if (ECMA_IS_VALUE_ERROR (constructor_value) - || !ecma_is_value_object (constructor_value) - || !ecma_is_constructor (constructor_value)) - { - ecma_free_value (constructor_value); - return ecma_raise_type_error (ECMA_ERR_MSG ("object.constructor is not a constructor.")); - } - - ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value); - ecma_value_t constructor_prototype = ecma_op_object_get_by_magic_id (constructor_object_p, - LIT_MAGIC_STRING_PROTOTYPE); - - ecma_deref_object (constructor_object_p); - - if (ECMA_IS_VALUE_ERROR (constructor_prototype)) - { - return constructor_prototype; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - ecma_typedarray_type_t typedarray_id = ecma_get_typedarray_id (obj_p); + // TODO: assert validate typedarray_id ecma_object_t *proto_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (typedarray_id)); uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (typedarray_id); ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length, + NULL, proto_p, element_size_shift, typedarray_id); -#if ENABLED (JERRY_ES2015_CLASS) - ecma_object_t *constructor_prototype_object_p = ecma_get_object_from_value (constructor_prototype); - ecma_object_t *new_obj_p = ecma_get_object_from_value (new_obj); - ECMA_SET_NON_NULL_POINTER (new_obj_p->u2.prototype_cp, constructor_prototype_object_p); - - ecma_deref_object (constructor_prototype_object_p); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - return new_obj; } /* ecma_op_create_typedarray_with_type_and_length */ diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.h b/jerry-core/ecma/operations/ecma-typedarray-object.h index 3171891a..52821fa7 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.h +++ b/jerry-core/ecma/operations/ecma-typedarray-object.h @@ -39,6 +39,7 @@ void ecma_set_typedarray_element (lit_utf8_byte_t *dst_p, bool ecma_typedarray_helper_is_typedarray (ecma_builtin_id_t builtin_id); ecma_typedarray_type_t ecma_get_typedarray_id (ecma_object_t *obj_p); ecma_builtin_id_t ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id); +ecma_builtin_id_t ecma_typedarray_helper_get_constructor_id (ecma_typedarray_type_t typedarray_id); ecma_typedarray_type_t ecma_typedarray_helper_builtin_to_typedarray_id (ecma_builtin_id_t builtin_id); ecma_value_t ecma_op_typedarray_from (ecma_value_t items_val, @@ -57,16 +58,18 @@ ecma_value_t ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, ecma_object_t *proto_p, uint8_t element_size_shift, ecma_typedarray_type_t typedarray_id); +bool ecma_object_is_typedarray (ecma_object_t *obj_p); bool ecma_is_typedarray (ecma_value_t target); void ecma_op_typedarray_list_lazy_property_names (ecma_object_t *obj_p, ecma_collection_t *main_collection_p); bool ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, uint32_t index, const ecma_property_descriptor_t *property_desc_p); -ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, +ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_typedarray_type_t typedarray_id, ecma_length_t array_length); ecma_typedarray_info_t ecma_typedarray_get_info (ecma_object_t *typedarray_p); ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, + ecma_object_t *src_arraybuffer_p, ecma_object_t *proto_p, uint8_t element_size_shift, ecma_typedarray_type_t typedarray_id); diff --git a/jerry-core/ext/debug-utils.c b/jerry-core/ext/debug-utils.c index 444e9b37..ebdad50c 100755 --- a/jerry-core/ext/debug-utils.c +++ b/jerry-core/ext/debug-utils.c @@ -43,20 +43,19 @@ void PrintObjectProperties(ecma_object_t* object) prop_pair_p->names_cp[i]); ecma_property_value_t prop_value_p = prop_pair_p->values[i]; - ecma_value_t value_value; + ecma_string_t *string_value; if (ecma_is_value_object(prop_value_p.value)) { // Expand it more? - value_value = ecma_op_to_string (prop_value_p.value); + string_value = ecma_op_to_string (prop_value_p.value); } else { - value_value = ecma_op_to_string (prop_value_p.value); + string_value = ecma_op_to_string (prop_value_p.value); } // handle value_value is error value? - ecma_string_t *str_p = ecma_get_string_from_value(value_value); - JERRY_ASSERT (str_p != NULL); + JERRY_ASSERT (string_value != NULL); ecma_string_t* separator_str = ecma_new_ecma_string_from_utf8((const lit_utf8_byte_t *)" :> ", 4); prop_name = ecma_concat_ecma_strings(prop_name, separator_str); - prop_name = ecma_concat_ecma_strings(prop_name, str_p); + prop_name = ecma_concat_ecma_strings(prop_name, string_value); ECMA_STRING_TO_UTF8_STRING(prop_name, buf, buf_size); printf("PROPERTY PAIR : "); @@ -66,7 +65,7 @@ void PrintObjectProperties(ecma_object_t* object) printf("\n"); ecma_deref_ecma_string(prop_name); - ecma_deref_ecma_string(str_p); + ecma_deref_ecma_string(string_value); ecma_deref_ecma_string(separator_str); } } diff --git a/jerry-core/ext/heapdump.c b/jerry-core/ext/heapdump.c index b07d0e30..3fccee9f 100644 --- a/jerry-core/ext/heapdump.c +++ b/jerry-core/ext/heapdump.c @@ -12,6 +12,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-property-hashmap.h" +#include "ecma-array-object.h" #include @@ -195,10 +196,8 @@ void DumpPropertyPair(ecma_property_pair_t* pair) ecma_object_t* value_obj = ecma_get_object_from_value(value); LogAddr(value_obj); } else { - ecma_value_t value_value = ecma_op_to_string(value); - ecma_string_t* value_str = ecma_get_string_from_value(value_value); + ecma_string_t* value_str = ecma_op_to_string(value); LogStrObj(value_str); - ecma_free_value(value_value); } break; } @@ -311,7 +310,7 @@ void DumpInfoObject(ecma_object_t* object, heapdump_object_flags_t flags) Type("Array"); ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object; - if (ext_object->u.array.is_fast_mode) { + if (ecma_op_object_is_fast_array(object)) { Key("subtype"); LogStr("fast"); Next(); @@ -336,10 +335,8 @@ void DumpInfoObject(ecma_object_t* object, heapdump_object_flags_t flags) ecma_object_t* value_obj = ecma_get_object_from_value(values[i]); LogAddr(value_obj); } else { - ecma_value_t value_value = ecma_op_to_string(values[i]); - ecma_string_t* value_str = ecma_get_string_from_value(value_value); + ecma_string_t* value_str = ecma_op_to_string(values[i]); LogStrObj(value_str); - ecma_free_value(value_value); } } } diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 5d9b1d8c..a5c71197 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -39,7 +39,7 @@ extern "C" /** * Minor version of JerryScript API. */ -#define JERRY_API_MINOR_VERSION 1 +#define JERRY_API_MINOR_VERSION 3 /** * Patch version of JerryScript API. @@ -99,6 +99,11 @@ typedef enum JERRY_FEATURE_LOGGING, /**< logging */ JERRY_FEATURE_SYMBOL, /**< symbol support */ JERRY_FEATURE_DATAVIEW, /**< DataView support */ + JERRY_FEATURE_PROXY, /**< Proxy support */ + JERRY_FEATURE_MAP, /**< Map support */ + JERRY_FEATURE_SET, /**< Set support */ + JERRY_FEATURE_WEAKMAP, /**< WeakMap support */ + JERRY_FEATURE_WEAKSET, /**< WeakSet support */ JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */ } jerry_feature_t; @@ -327,6 +332,11 @@ typedef enum JERRY_BIN_OP_GREATER, /**< greater relation (>) */ JERRY_BIN_OP_GREATER_EQUAL, /**< greater or equal relation (>=)*/ JERRY_BIN_OP_INSTANCEOF, /**< instanceof operation */ + JERRY_BIN_OP_ADD, /**< addition operator (+) */ + JERRY_BIN_OP_SUB, /**< subtraction operator (-) */ + JERRY_BIN_OP_MUL, /**< multiplication operator (*) */ + JERRY_BIN_OP_DIV, /**< division operator (/) */ + JERRY_BIN_OP_REM, /**< remainder operator (%) */ } jerry_binary_operation_t; /** @@ -380,6 +390,7 @@ bool jerry_value_is_number (const jerry_value_t value); bool jerry_value_is_null (const jerry_value_t value); bool jerry_value_is_object (const jerry_value_t value); bool jerry_value_is_promise (const jerry_value_t value); +bool jerry_value_is_proxy (const jerry_value_t value); bool jerry_value_is_string (const jerry_value_t value); bool jerry_value_is_symbol (const jerry_value_t value); bool jerry_value_is_undefined (const jerry_value_t value); @@ -494,6 +505,7 @@ jerry_value_t jerry_create_number_nan (void); jerry_value_t jerry_create_null (void); jerry_value_t jerry_create_object (void); jerry_value_t jerry_create_promise (void); +jerry_value_t jerry_create_proxy (const jerry_value_t target, const jerry_value_t handler); jerry_value_t jerry_create_regexp (const jerry_char_t *pattern, uint16_t flags); jerry_value_t jerry_create_regexp_sz (const jerry_char_t *pattern, jerry_size_t pattern_size, uint16_t flags); jerry_value_t jerry_create_string_from_utf8 (const jerry_char_t *str_p); @@ -508,15 +520,20 @@ jerry_value_t jerry_create_undefined (void); */ jerry_value_t jerry_has_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_has_own_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); +bool jerry_has_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); bool jerry_delete_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); bool jerry_delete_property_by_index (const jerry_value_t obj_val, uint32_t index); +bool jerry_delete_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_get_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); +jerry_value_t jerry_get_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_set_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, const jerry_value_t value_to_set); jerry_value_t jerry_set_property_by_index (const jerry_value_t obj_val, uint32_t index, const jerry_value_t value_to_set); +bool jerry_set_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, + const jerry_value_t value_to_set); void jerry_init_property_descriptor_fields (jerry_property_descriptor_t *prop_desc_p); jerry_value_t jerry_define_own_property (const jerry_value_t obj_val, @@ -556,10 +573,24 @@ bool jerry_foreach_object_property (const jerry_value_t obj_val, jerry_object_pr void *user_data_p); /** - * Promise resolve/reject functions. + * Promise functions. */ jerry_value_t jerry_resolve_or_reject_promise (jerry_value_t promise, jerry_value_t argument, bool is_resolve); +/** + * Enum values representing various Promise states. + */ +typedef enum +{ + JERRY_PROMISE_STATE_NONE = 0u, /**< Invalid/Unknown state (possibly called on a non-promise object). */ + JERRY_PROMISE_STATE_PENDING, /**< Promise is in "Pending" state. */ + JERRY_PROMISE_STATE_FULFILLED, /**< Promise is in "Fulfilled" state. */ + JERRY_PROMISE_STATE_REJECTED, /**< Promise is in "Rejected" state. */ +} jerry_promise_state_t; + +jerry_value_t jerry_get_promise_result (const jerry_value_t promise); +jerry_promise_state_t jerry_get_promise_state (const jerry_value_t promise); + /** * Symbol functions. */ @@ -587,6 +618,8 @@ jerry_context_t *jerry_create_context (uint32_t heap_size, jerry_context_alloc_t */ void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency); jerry_value_t jerry_get_backtrace (uint32_t max_depth); +jerry_value_t jerry_get_resource_name (const jerry_value_t value); +jerry_value_t jerry_get_new_target (void); /** * Array buffer components. @@ -606,6 +639,8 @@ jerry_length_t jerry_arraybuffer_read (const jerry_value_t value, jerry_length_t buf_size); jerry_length_t jerry_get_arraybuffer_byte_length (const jerry_value_t value); uint8_t *jerry_get_arraybuffer_pointer (const jerry_value_t value); +jerry_value_t jerry_is_arraybuffer_detachable (const jerry_value_t value); +jerry_value_t jerry_detach_arraybuffer (const jerry_value_t value); /** * DataView functions. @@ -644,6 +679,17 @@ typedef enum JERRY_TYPEDARRAY_FLOAT64, } jerry_typedarray_type_t; +/** + * Container types. + */ +typedef enum +{ + JERRY_CONTAINER_TYPE_INVALID = 0, /**< Invalid container */ + JERRY_CONTAINER_TYPE_MAP, /**< Map type */ + JERRY_CONTAINER_TYPE_SET, /**< Set type */ + JERRY_CONTAINER_TYPE_WEAKMAP, /**< WeakMap type */ + JERRY_CONTAINER_TYPE_WEAKSET, /**< WeakSet type */ +} jerry_container_type_t; bool jerry_value_is_typedarray (jerry_value_t value); jerry_value_t jerry_create_typedarray (jerry_typedarray_type_t type_name, jerry_length_t length); @@ -660,6 +706,10 @@ jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value, jerry_length_t *byte_length); jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size); jerry_value_t jerry_json_stringify (const jerry_value_t object_to_stringify); +jerry_value_t jerry_create_container (jerry_container_type_t container_type, + const jerry_value_t *arguments_list_p, + jerry_length_t arguments_list_len); +jerry_container_type_t jerry_get_container_type (const jerry_value_t value); #if defined(JERRY_HEAPDUMP) void JerryHeapdumpRun(const char* filepath); diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index 9a9e4463..37609fd4 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -51,6 +51,7 @@ typedef enum ERR_OUT_OF_MEMORY = 10, ERR_REF_COUNT_LIMIT = 12, ERR_DISABLED_BYTE_CODE = 13, + ERR_UNTERMINATED_GC_LOOPS = 14, ERR_FAILED_INTERNAL_ASSERTION = 120 } jerry_fatal_code_t; diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 12f21315..1dfbf121 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (24u) +#define JERRY_SNAPSHOT_VERSION (49u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/jcontext/jcontext.c b/jerry-core/jcontext/jcontext.c index f6ce5383..eacefe8c 100755 --- a/jerry-core/jcontext/jcontext.c +++ b/jerry-core/jcontext/jcontext.c @@ -19,6 +19,105 @@ * @{ */ +/** + * Check the existence of the ECMA_STATUS_EXCEPTION flag. + * + * @return true - if the flag is set + * false - otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +jcontext_has_pending_exception (void) +{ + return JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION; +} /* jcontext_has_pending_exception */ + +/** + * Check the existence of the ECMA_STATUS_ABORT flag. + * + * @return true - if the flag is set + * false - otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +jcontext_has_pending_abort (void) +{ + return JERRY_CONTEXT (status_flags) & ECMA_STATUS_ABORT; +} /* jcontext_has_pending_abort */ + +/** + * Set the abort flag for the context. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_set_abort_flag (bool is_abort) /**< true - if the abort flag should be set + * false - if the abort flag should be removed */ +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + if (is_abort) + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ABORT; + } + else + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_ABORT; + } +} /* jcontext_set_abort_flag */ + +/** + * Set the exception flag for the context. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_set_exception_flag (bool is_exception) /**< true - if the exception flag should be set + * false - if the exception flag should be removed */ +{ + if (is_exception) + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + } + else + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + } +} /* jcontext_set_exception_flag */ + +/** + * Raise exception from the given error value. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_raise_exception (ecma_value_t error) /**< error to raise */ +{ + JERRY_ASSERT (!jcontext_has_pending_exception ()); + JERRY_ASSERT (!jcontext_has_pending_abort ()); + + JERRY_CONTEXT (error_value) = error; + jcontext_set_exception_flag (true); +} /* jcontext_raise_exception */ + +/** + * Release the current exception/abort of the context. + */ +void +jcontext_release_exception (void) +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + ecma_free_value (jcontext_take_exception ()); +} /* jcontext_release_exception */ + +/** + * Take the current exception/abort of context. + * + * @return current exception as an ecma-value + */ +ecma_value_t +jcontext_take_exception (void) +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + jcontext_set_abort_flag (false); + jcontext_set_exception_flag (false); + return JERRY_CONTEXT (error_value); +} /* jcontext_take_exception */ + #if !ENABLED (JERRY_EXTERNAL_CONTEXT) /** diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 494a4310..4bf2a570 100755 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -21,6 +21,7 @@ #include "debugger.h" #include "ecma-builtins.h" +#include "ecma-helpers.h" #include "ecma-jobqueue.h" #include "jerryscript-port.h" #include "jmem.h" @@ -129,7 +130,7 @@ struct jerry_context_t /* Update JERRY_CONTEXT_FIRST_MEMBER if the first non-external member changes */ jmem_cpointer_t ecma_builtin_objects[ECMA_BUILTIN_ID__COUNT]; /**< pointer to instances of built-in objects */ #if ENABLED (JERRY_BUILTIN_REGEXP) - const re_compiled_code_t *re_cache[RE_CACHE_SIZE]; /**< regex cache */ + re_compiled_code_t *re_cache[RE_CACHE_SIZE]; /**< regex cache */ #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ jmem_cpointer_t ecma_gc_objects_cp; /**< List of currently alive objects. */ jmem_heap_free_t *jmem_heap_list_skip_p; /**< This is used to speed up deallocation. */ @@ -140,11 +141,14 @@ struct jerry_context_t const lit_utf8_byte_t * const *lit_magic_string_ex_array; /**< array of external magic strings */ const lit_utf8_size_t *lit_magic_string_ex_sizes; /**< external magic string lengths */ jmem_cpointer_t string_list_first_cp; /**< first item of the literal string list */ -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) jmem_cpointer_t symbol_list_first_cp; /**< first item of the global symbol list */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ jmem_cpointer_t number_list_first_cp; /**< first item of the literal number list */ - jmem_cpointer_t ecma_global_lex_env_cp; /**< global lexical environment */ + jmem_cpointer_t ecma_global_env_cp; /**< global lexical environment */ +#if ENABLED (JERRY_ES2015) + jmem_cpointer_t ecma_global_scope_cp; /**< global lexical scope */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) ecma_module_t *ecma_modules_p; /**< list of referenced modules */ @@ -162,6 +166,9 @@ struct jerry_context_t uint32_t lit_magic_string_ex_count; /**< external magic strings count */ uint32_t jerry_init_flags; /**< run-time configuration flags */ uint32_t status_flags; /**< run-time flags (the top 8 bits are used for passing class parsing options) */ +#if (JERRY_GC_MARK_LIMIT != 0) + uint32_t ecma_gc_mark_recursion_limit; /**< GC mark recursion limit */ +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ #if ENABLED (JERRY_PROPRETY_HASHMAP) uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4, @@ -173,8 +180,8 @@ struct jerry_context_t #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) - ecma_job_queueitem_t *job_queue_head_p; /**< points to the head item of the jobqueue */ - ecma_job_queueitem_t *job_queue_tail_p; /**< points to the tail item of the jobqueue*/ + ecma_job_queue_item_t *job_queue_head_p; /**< points to the head item of the job queue */ + ecma_job_queue_item_t *job_queue_tail_p; /**< points to the tail item of the job queue */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ #if ENABLED (JERRY_VM_EXEC_STOP) @@ -195,8 +202,8 @@ struct jerry_context_t jerry_debugger_transport_header_t *debugger_transport_header_p; /**< head of transport protocol chain */ uint8_t *debugger_send_buffer_payload_p; /**< start where the outgoing message can be written */ vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */ - uint8_t *debugger_exception_byte_code_p; /**< Location of the currently executed byte code if an - * error occours while the vm_loop is suspended */ + const uint8_t *debugger_exception_byte_code_p; /**< Location of the currently executed byte code if an + * error occours while the vm_loop is suspended */ jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */ jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */ uint32_t debugger_flags; /**< debugger flags */ @@ -220,6 +227,17 @@ struct jerry_context_t ecma_lcache_hash_entry_t lcache[ECMA_LCACHE_HASH_ROWS_COUNT][ECMA_LCACHE_HASH_ROW_LENGTH]; #endif /* ENABLED (JERRY_LCACHE) */ +#if ENABLED (JERRY_ES2015) + /** + * Allowed values and it's meaning: + * * NULL (0x0): the current "new.target" is undefined, that is the execution is inside a normal method. + * * Any other valid function object pointer: the current "new.target" is valid and it is constructor call. + */ + ecma_object_t *current_new_target; + ecma_object_t *current_function_obj_p; /** currently invoked function object + (Note: currently used only in generator functions) */ +#endif /* ENABLED (JERRY_ES2015) */ + #ifdef JERRY_FOR_IAR_CONFIG #if ENABLED (JERRY_EXTERNAL_CONTEXT) fatal_handler_t jerry_fatal_handler; /* js task fatal handler */ @@ -227,7 +245,6 @@ struct jerry_context_t #endif // not defined JERRY_FOR_IAR_CONFIG }; - #if ENABLED (JERRY_EXTERNAL_CONTEXT) /* @@ -235,6 +252,7 @@ struct jerry_context_t */ extern jerry_context_t *jerry_dynamic_global_context_p; +#define JERRY_CONTEXT_STRUCT (*jerry_dynamic_global_context_p) #define JERRY_CONTEXT(field) (jerry_dynamic_global_context_p->field) #if !ENABLED (JERRY_SYSTEM_ALLOCATOR) @@ -264,6 +282,11 @@ struct jmem_heap_t */ extern jerry_context_t jerry_global_context; +/** + * Config-independent name for context. + */ +#define JERRY_CONTEXT_STRUCT (jerry_global_context) + /** * Provides a reference to a field in the current context. */ @@ -301,6 +324,27 @@ extern jmem_heap_t jerry_global_heap; #endif /* ENABLED (JERRY_EXTERNAL_CONTEXT) */ +void +jcontext_set_exception_flag (bool is_exception); + +void +jcontext_set_abort_flag (bool is_abort); + +bool +jcontext_has_pending_exception (void); + +bool +jcontext_has_pending_abort (void); + +void +jcontext_raise_exception (ecma_value_t error); + +void +jcontext_release_exception (void); + +ecma_value_t +jcontext_take_exception (void); + /** * @} */ diff --git a/jerry-core/jmem/jmem-allocator.c b/jerry-core/jmem/jmem-allocator.c index e5914803..7357e49d 100644 --- a/jerry-core/jmem/jmem-allocator.c +++ b/jerry-core/jmem/jmem-allocator.c @@ -231,4 +231,3 @@ jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompres return (void *) uint_ptr; } /* jmem_decompress_pointer */ - diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c index d059594a..7a5cb5ea 100644 --- a/jerry-core/jmem/jmem-heap.c +++ b/jerry-core/jmem/jmem-heap.c @@ -75,7 +75,7 @@ static inline jmem_heap_free_t * JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_PURE jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */ { - return (jmem_heap_free_t *)((uint8_t *) curr_p + curr_p->size); + return (jmem_heap_free_t *) ((uint8_t *) curr_p + curr_p->size); } /* jmem_heap_get_region_end */ #endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ @@ -301,6 +301,7 @@ jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */ void *data_space_p = jmem_heap_alloc (size); + /* cppcheck-suppress memleak */ while (JERRY_UNLIKELY (data_space_p == NULL) && JERRY_LIKELY (pressure < max_pressure)) { pressure++; @@ -422,7 +423,6 @@ jmem_heap_insert_block (jmem_heap_free_t *block_p, /**< block to insert */ JMEM_VALGRIND_DEFINED_SPACE (block_p, sizeof (jmem_heap_free_t)); JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t)); - const uint32_t block_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (block_p); /* Update prev. */ @@ -529,7 +529,7 @@ jmem_heap_realloc_block (void *ptr, /**< memory region to reallocate */ JMEM_VALGRIND_RESIZE_SPACE (block_p, old_size, new_size); JMEM_HEAP_STAT_FREE (old_size); JMEM_HEAP_STAT_ALLOC (new_size); - jmem_heap_insert_block ((jmem_heap_free_t *)((uint8_t *) block_p + aligned_new_size), + jmem_heap_insert_block ((jmem_heap_free_t *) ((uint8_t *) block_p + aligned_new_size), jmem_heap_find_prev (block_p), aligned_old_size - aligned_new_size); @@ -662,7 +662,15 @@ jmem_heap_realloc_block (void *ptr, /**< memory region to reallocate */ JMEM_HEAP_STAT_ALLOC (new_size); return ret_block_p; #else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */ - JERRY_CONTEXT (jmem_heap_allocated_size) += (new_size - old_size); + const size_t required_size = new_size - old_size; +#if !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) + if (JERRY_CONTEXT (jmem_heap_allocated_size) + required_size >= JERRY_CONTEXT (jmem_heap_limit)) +#endif /* !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */ + { + ecma_free_unused_memory (JMEM_PRESSURE_LOW); + } + + JERRY_CONTEXT (jmem_heap_allocated_size) += required_size; while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) { diff --git a/jerry-core/jmem/jmem.h b/jerry-core/jmem/jmem.h index 18ad2f38..a89f705d 100644 --- a/jerry-core/jmem/jmem.h +++ b/jerry-core/jmem/jmem.h @@ -40,6 +40,37 @@ */ #define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG) +/** + * Pointer value can be directly stored without compression + */ +#if UINTPTR_MAX <= UINT32_MAX +#define JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY +#endif /* UINTPTR_MAX <= UINT32_MAX */ + +/** + * Mask for tag part in jmem_cpointer_tag_t + */ +#define JMEM_TAG_MASK 0x7u + +/** + * Shift for tag part in jmem_cpointer_tag_t + */ +#if defined (JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY) && ENABLED (JERRY_CPOINTER_32_BIT) +#define JMEM_TAG_SHIFT 0 +#else /* !JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY || !ENABLED (JERRY_CPOINTER_32_BIT) */ +#define JMEM_TAG_SHIFT 3 +#endif /* JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY && ENABLED (JERRY_CPOINTER_32_BIT) */ + +/** + * Bit mask for tag part in jmem_cpointer_tag_t + */ +enum +{ + JMEM_FIRST_TAG_BIT_MASK = (1u << 0), /**< first tag bit mask **/ + JMEM_SECOND_TAG_BIT_MASK = (1u << 1), /**< second tag bit mask **/ + JMEM_THIRD_TAG_BIT_MASK = (1u << 2), /**< third tag bit mask **/ +}; + /** * Compressed pointer representations * @@ -69,6 +100,11 @@ typedef uint32_t jmem_cpointer_t; typedef uint16_t jmem_cpointer_t; #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ +/** + * Compressed pointer with tag value + */ +typedef uint32_t jmem_cpointer_tag_t; + /** * Memory usage pressure for reclaiming unused memory. * @@ -223,6 +259,44 @@ void * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer); } \ } while (false); +/** + * Set value of pointer-tag value so that it will correspond + * to specified non_compressed_pointer along with tag + */ +#define JMEM_CP_SET_NON_NULL_POINTER_TAG(cp_value, pointer, tag) \ + do \ + { \ + JERRY_ASSERT ((uintptr_t) tag < (uintptr_t) (JMEM_ALIGNMENT)); \ + jmem_cpointer_tag_t compressed_ptr = jmem_compress_pointer (pointer); \ + (cp_value) = (jmem_cpointer_tag_t) ((compressed_ptr << JMEM_TAG_SHIFT) | tag); \ + } while (false); + +/** + * Extract value of pointer from specified pointer-tag value + */ +#define JMEM_CP_GET_NON_NULL_POINTER_FROM_POINTER_TAG(type, cp_value) \ + ((type *) (jmem_decompress_pointer ((cp_value & ~JMEM_TAG_MASK) >> JMEM_TAG_SHIFT))) + +/** + * Get value of each tag from specified pointer-tag value + */ +#define JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG(cp_value) \ + (cp_value & JMEM_FIRST_TAG_BIT_MASK) /**< get first tag bit **/ +#define JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG(cp_value) \ + (cp_value & JMEM_SECOND_TAG_BIT_MASK) /**< get second tag bit **/ +#define JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG(cp_value) \ + (cp_value & JMEM_THIRD_TAG_BIT_MASK) /**< get third tag bit **/ + +/** + * Set value of each tag to specified pointer-tag value + */ +#define JMEM_CP_SET_FIRST_BIT_TO_POINTER_TAG(cp_value) \ + (cp_value) = (cp_value | JMEM_FIRST_TAG_BIT_MASK) /**< set first tag bit **/ +#define JMEM_CP_SET_SECOND_BIT_TO_POINTER_TAG(cp_value) \ + (cp_value) = (cp_value | JMEM_SECOND_TAG_BIT_MASK) /**< set second tag bit **/ +#define JMEM_CP_SET_THIRD_BIT_TO_POINTER_TAG(cp_value) \ + (cp_value) = (cp_value | JMEM_THIRD_TAG_BIT_MASK) /**< set third tag bit **/ + /** * @} * \addtogroup poolman Memory pool manager diff --git a/jerry-core/jrt/jrt-fatals.c b/jerry-core/jrt/jrt-fatals.c index d262734a..e5e6a87a 100644 --- a/jerry-core/jrt/jrt-fatals.c +++ b/jerry-core/jrt/jrt-fatals.c @@ -34,6 +34,7 @@ # define MSG_SIZE_TYPE size_t #endif +#if defined (_WIN32) || defined (_WIN64) || !defined (JERRY_NDEBUG) || defined (__APPLE__) #if ENABLED (JERRY_MEM_STATS) static void jerry_dump_memstats_on_error (void) @@ -64,6 +65,7 @@ jerry_dump_memstats_on_error (void) JERRY_ERROR_MSG ("\tpeak allocated memory for properties: %"PRI_SIZET"\n", (MSG_SIZE_TYPE)(jmem_heap_stats.peak_property_bytes)); } #endif +#endif /* Windows/Mac Or !defined (JERRY_NDEBUG) */ /* * Exit with specified status code. @@ -87,6 +89,11 @@ jerry_fatal (jerry_fatal_code_t code) /**< status code */ JERRY_ERROR_MSG ("Error: ERR_REF_COUNT_LIMIT\n"); break; } + case ERR_UNTERMINATED_GC_LOOPS: + { + JERRY_ERROR_MSG ("Error: ERR_UNTERMINATED_GC_LOOPS\n"); + break; + } case ERR_DISABLED_BYTE_CODE: { JERRY_ERROR_MSG ("Error: ERR_DISABLED_BYTE_CODE\n"); @@ -107,7 +114,7 @@ jerry_fatal (jerry_fatal_code_t code) /**< status code */ #if ENABLED (JERRY_MEM_STATS) jerry_dump_memstats_on_error (); #endif -#endif +#endif /* Windows/Mac Or !defined (JERRY_NDEBUG) */ jerry_port_fatal (code); diff --git a/jerry-core/libjerry-core.pc.in b/jerry-core/libjerry-core.pc.in index ed38855c..97717239 100644 --- a/jerry-core/libjerry-core.pc.in +++ b/jerry-core/libjerry-core.pc.in @@ -9,4 +9,4 @@ Version: 1.0 Requires.private: @JERRY_CORE_PKGCONFIG_REQUIRES@ # NOTE: libjerry-port-default* is not added as a required package Libs: -L${libdir} -ljerry-core Libs.private: @JERRY_CORE_PKGCONFIG_LIBS@ -Cflags: -I${includedir} +Cflags: -I${includedir} @JERRY_CORE_PKGCONFIG_CFLAGS@ diff --git a/jerry-core/lit/lit-char-helpers.c b/jerry-core/lit/lit-char-helpers.c index 29ec4fae..90606d32 100644 --- a/jerry-core/lit/lit-char-helpers.c +++ b/jerry-core/lit/lit-char-helpers.c @@ -103,31 +103,32 @@ search_char_in_interval_array (ecma_char_t c, /**< code unit */ } /* search_char_in_interval_array */ /** - * Check if specified character is one of the Whitespace characters including those - * that fall into "Space, Separator" ("Zs") Unicode character category. + * Check if specified character is one of the Whitespace characters including those that fall into + * "Space, Separator" ("Zs") Unicode character category or one of the Line Terminator characters. * * @return true - if the character is one of characters, listed in ECMA-262 v5, Table 2, * false - otherwise */ bool -lit_char_is_white_space (ecma_char_t c) /**< code unit */ +lit_char_is_white_space (lit_code_point_t c) /**< code point */ { if (c <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) { - return (c == LIT_CHAR_TAB - || c == LIT_CHAR_VTAB - || c == LIT_CHAR_FF - || c == LIT_CHAR_SP); + return (c == LIT_CHAR_SP || (c >= LIT_CHAR_TAB && c <= LIT_CHAR_CR)); } else { - return (c == LIT_CHAR_NBSP - || c == LIT_CHAR_BOM - || (c >= lit_unicode_separator_char_interval_sps[0] - && c <= lit_unicode_separator_char_interval_sps[0] + lit_unicode_separator_char_interval_lengths[0]) - || search_char_in_char_array (c, - lit_unicode_separator_chars, - NUM_OF_ELEMENTS (lit_unicode_separator_chars))); + if (c == LIT_CHAR_NBSP || c == LIT_CHAR_BOM || c == LIT_CHAR_LS || c == LIT_CHAR_PS) + { + return true; + } + + return (c <= LIT_UTF16_CODE_UNIT_MAX + && ((c >= lit_unicode_separator_char_interval_sps[0] + && c < lit_unicode_separator_char_interval_sps[0] + lit_unicode_separator_char_interval_lengths[0]) + || search_char_in_char_array ((ecma_char_t) c, + lit_unicode_separator_chars, + NUM_OF_ELEMENTS (lit_unicode_separator_chars)))); } } /* lit_char_is_white_space */ @@ -200,73 +201,35 @@ lit_char_is_unicode_non_letter_ident_part (ecma_char_t c) /**< code unit */ NUM_OF_ELEMENTS (lit_unicode_non_letter_ident_part_chars))); } /* lit_char_is_unicode_non_letter_ident_part */ -/** - * Checks whether the next UTF8 character is a valid identifier start. - * - * @return true if it is. - */ -bool -lit_char_is_identifier_start (const uint8_t *src_p) /**< pointer to a vaild UTF8 character */ -{ - if (*src_p <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) - { - return lit_char_is_identifier_start_character (*src_p); - } - - /* ECMAScript 2015 specification allows some code points in supplementary plane. - * However, we don't permit characters in supplementary characters as start of identifier. - */ - if ((*src_p & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER) - { - return false; - } - - return lit_char_is_identifier_start_character (lit_utf8_peek_next (src_p)); -} /* lit_char_is_identifier_start */ - /** * Checks whether the character is a valid identifier start. * * @return true if it is. */ bool -lit_char_is_identifier_start_character (uint16_t chr) /**< EcmaScript character */ +lit_code_point_is_identifier_start (lit_code_point_t code_point) /**< code point */ { /* Fast path for ASCII-defined letters. */ - if (chr <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) + if (code_point <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) { - return ((LEXER_TO_ASCII_LOWERCASE (chr) >= LIT_CHAR_LOWERCASE_A - && LEXER_TO_ASCII_LOWERCASE (chr) <= LIT_CHAR_LOWERCASE_Z) - || chr == LIT_CHAR_DOLLAR_SIGN - || chr == LIT_CHAR_UNDERSCORE); + return ((LEXER_TO_ASCII_LOWERCASE (code_point) >= LIT_CHAR_LOWERCASE_A + && LEXER_TO_ASCII_LOWERCASE (code_point) <= LIT_CHAR_LOWERCASE_Z) + || code_point == LIT_CHAR_DOLLAR_SIGN + || code_point == LIT_CHAR_UNDERSCORE); } - return lit_char_is_unicode_letter (chr); -} /* lit_char_is_identifier_start_character */ - -/** - * Checks whether the next UTF8 character is a valid identifier part. - * - * @return true if it is. - */ -bool -lit_char_is_identifier_part (const uint8_t *src_p) /**< pointer to a vaild UTF8 character */ -{ - if (*src_p <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) +#if ENABLED (JERRY_ES2015) + if (code_point >= LIT_UTF8_4_BYTE_CODE_POINT_MIN) { - return lit_char_is_identifier_part_character (*src_p); + /* TODO: detect these ranges correctly. */ + return (code_point >= 0x10C80 && code_point <= 0x10CF2); } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (code_point <= LIT_UTF8_4_BYTE_CODE_POINT_MIN); +#endif /* ENABLED (JERRY_ES2015) */ - /* ECMAScript 2015 specification allows some code points in supplementary plane. - * However, we don't permit characters in supplementary characters as part of identifier. - */ - if ((*src_p & LIT_UTF8_4_BYTE_MASK) == LIT_UTF8_4_BYTE_MARKER) - { - return false; - } - - return lit_char_is_identifier_part_character (lit_utf8_peek_next (src_p)); -} /* lit_char_is_identifier_part */ + return lit_char_is_unicode_letter ((ecma_char_t) code_point); +} /* lit_code_point_is_identifier_start */ /** * Checks whether the character is a valid identifier part. @@ -274,21 +237,31 @@ lit_char_is_identifier_part (const uint8_t *src_p) /**< pointer to a vaild UTF8 * @return true if it is. */ bool -lit_char_is_identifier_part_character (uint16_t chr) /**< EcmaScript character */ +lit_code_point_is_identifier_part (lit_code_point_t code_point) /**< code point */ { /* Fast path for ASCII-defined letters. */ - if (chr <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) + if (code_point <= LIT_UTF8_1_BYTE_CODE_POINT_MAX) { - return ((LEXER_TO_ASCII_LOWERCASE (chr) >= LIT_CHAR_LOWERCASE_A - && LEXER_TO_ASCII_LOWERCASE (chr) <= LIT_CHAR_LOWERCASE_Z) - || (chr >= LIT_CHAR_0 && chr <= LIT_CHAR_9) - || chr == LIT_CHAR_DOLLAR_SIGN - || chr == LIT_CHAR_UNDERSCORE); + return ((LEXER_TO_ASCII_LOWERCASE (code_point) >= LIT_CHAR_LOWERCASE_A + && LEXER_TO_ASCII_LOWERCASE (code_point) <= LIT_CHAR_LOWERCASE_Z) + || (code_point >= LIT_CHAR_0 && code_point <= LIT_CHAR_9) + || code_point == LIT_CHAR_DOLLAR_SIGN + || code_point == LIT_CHAR_UNDERSCORE); } - return (lit_char_is_unicode_letter (chr) - || lit_char_is_unicode_non_letter_ident_part (chr)); -} /* lit_char_is_identifier_part_character */ +#if ENABLED (JERRY_ES2015) + if (code_point >= LIT_UTF8_4_BYTE_CODE_POINT_MIN) + { + /* TODO: detect these ranges correctly. */ + return (code_point >= 0x10C80 && code_point <= 0x10CF2); + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (code_point <= LIT_UTF8_4_BYTE_CODE_POINT_MIN); +#endif /* ENABLED (JERRY_ES2015) */ + + return (lit_char_is_unicode_letter ((ecma_char_t) code_point) + || lit_char_is_unicode_non_letter_ident_part ((ecma_char_t) code_point)); +} /* lit_code_point_is_identifier_part */ /** * Check if specified character is one of OctalDigit characters (ECMA-262 v5, B.1.2) @@ -325,6 +298,19 @@ lit_char_is_hex_digit (ecma_char_t c) /**< code unit */ && LEXER_TO_ASCII_LOWERCASE (c) <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_END)); } /* lit_char_is_hex_digit */ +#if ENABLED (JERRY_ES2015) +/** + * Check if specified character is one of BinaryDigits characters (ECMA-262 v6, 11.8.3) + * + * @return true / false + */ +bool +lit_char_is_binary_digit (ecma_char_t c) /** code unit */ +{ + return (c == LIT_CHAR_0 || c == LIT_CHAR_1); +} /* lit_char_is_binary_digit */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * Convert a HexDigit character to its numeric value, as defined in ECMA-262 v5, 7.8.3 * @@ -356,30 +342,47 @@ lit_char_hex_to_int (ecma_char_t c) /**< code unit, corresponding to * @return length of the UTF8 representation. */ size_t -lit_char_to_utf8_bytes (uint8_t *dst_p, /**< destination buffer */ - ecma_char_t chr) /**< EcmaScript character */ +lit_code_point_to_cesu8_bytes (uint8_t *dst_p, /**< destination buffer */ + lit_code_point_t code_point) /**< code point */ { - if (!(chr & ~LIT_UTF8_1_BYTE_CODE_POINT_MAX)) + if (code_point < LIT_UTF8_2_BYTE_CODE_POINT_MIN) { /* 00000000 0xxxxxxx -> 0xxxxxxx */ - *dst_p = (uint8_t) chr; + dst_p[0] = (uint8_t) code_point; return 1; } - if (!(chr & ~LIT_UTF8_2_BYTE_CODE_POINT_MAX)) + if (code_point < LIT_UTF8_3_BYTE_CODE_POINT_MIN) { /* 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx */ - *(dst_p++) = (uint8_t) (LIT_UTF8_2_BYTE_MARKER | ((chr >> 6) & LIT_UTF8_LAST_5_BITS_MASK)); - *dst_p = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | (chr & LIT_UTF8_LAST_6_BITS_MASK)); + dst_p[0] = (uint8_t) (LIT_UTF8_2_BYTE_MARKER | ((code_point >> 6) & LIT_UTF8_LAST_5_BITS_MASK)); + dst_p[1] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | (code_point & LIT_UTF8_LAST_6_BITS_MASK)); return 2; } - /* zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx */ - *(dst_p++) = (uint8_t) (LIT_UTF8_3_BYTE_MARKER | ((chr >> 12) & LIT_UTF8_LAST_4_BITS_MASK)); - *(dst_p++) = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | ((chr >> 6) & LIT_UTF8_LAST_6_BITS_MASK)); - *dst_p = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | (chr & LIT_UTF8_LAST_6_BITS_MASK)); - return 3; -} /* lit_char_to_utf8_bytes */ + if (code_point < LIT_UTF8_4_BYTE_CODE_POINT_MIN) + { + /* zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx */ + dst_p[0] = (uint8_t) (LIT_UTF8_3_BYTE_MARKER | ((code_point >> 12) & LIT_UTF8_LAST_4_BITS_MASK)); + dst_p[1] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | ((code_point >> 6) & LIT_UTF8_LAST_6_BITS_MASK)); + dst_p[2] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | (code_point & LIT_UTF8_LAST_6_BITS_MASK)); + return 3; + } + + JERRY_ASSERT (code_point <= LIT_UNICODE_CODE_POINT_MAX); + + code_point -= LIT_UTF8_4_BYTE_CODE_POINT_MIN; + + dst_p[0] = (uint8_t) (LIT_UTF8_3_BYTE_MARKER | 0xd); + dst_p[1] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | 0x20 | ((code_point >> 16) & LIT_UTF8_LAST_4_BITS_MASK)); + dst_p[2] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | ((code_point >> 10) & LIT_UTF8_LAST_6_BITS_MASK)); + + dst_p[3] = (uint8_t) (LIT_UTF8_3_BYTE_MARKER | 0xd); + dst_p[4] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | 0x30 | ((code_point >> 6) & LIT_UTF8_LAST_4_BITS_MASK)); + dst_p[5] = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | (code_point & LIT_UTF8_LAST_6_BITS_MASK)); + + return 3 * 2; +} /* lit_code_point_to_cesu8_bytes */ /** * Returns the length of the UTF8 representation of a character. @@ -387,70 +390,112 @@ lit_char_to_utf8_bytes (uint8_t *dst_p, /**< destination buffer */ * @return length of the UTF8 representation. */ size_t -lit_char_get_utf8_length (ecma_char_t chr) /**< EcmaScript character */ +lit_code_point_get_cesu8_length (lit_code_point_t code_point) /**< code point */ { - if (!(chr & ~LIT_UTF8_1_BYTE_CODE_POINT_MAX)) + if (code_point < LIT_UTF8_2_BYTE_CODE_POINT_MIN) { /* 00000000 0xxxxxxx */ return 1; } - if (!(chr & ~LIT_UTF8_2_BYTE_CODE_POINT_MAX)) + if (code_point < LIT_UTF8_3_BYTE_CODE_POINT_MIN) { /* 00000yyy yyxxxxxx */ return 2; } - /* zzzzyyyy yyxxxxxx */ - return 3; -} /* lit_char_get_utf8_length */ - -/** - * Parse the next number_of_characters hexadecimal character, - * and construct a code unit from them. The buffer must - * be zero terminated. - * - * @return true if decoding was successful, false otherwise - */ -bool -lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, /**< buffer with characters */ - lit_utf8_size_t number_of_characters, /**< number of characters to be read */ - ecma_char_t *out_code_unit_p) /**< [out] decoded result */ -{ - ecma_char_t code_unit = LIT_CHAR_NULL; - - JERRY_ASSERT (number_of_characters >= 2 && number_of_characters <= 4); - - for (lit_utf8_size_t i = 0; i < number_of_characters; i++) + if (code_point < LIT_UTF8_4_BYTE_CODE_POINT_MIN) { - code_unit = (ecma_char_t) (code_unit << 4u); - - if (*buf_p >= LIT_CHAR_ASCII_DIGITS_BEGIN - && *buf_p <= LIT_CHAR_ASCII_DIGITS_END) - { - code_unit |= (ecma_char_t) (*buf_p - LIT_CHAR_ASCII_DIGITS_BEGIN); - } - else if (*buf_p >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN - && *buf_p <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_END) - { - code_unit |= (ecma_char_t) (*buf_p - (LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN - 10)); - } - else if (*buf_p >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_HEX_BEGIN - && *buf_p <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_HEX_END) - { - code_unit |= (ecma_char_t) (*buf_p - (LIT_CHAR_ASCII_UPPERCASE_LETTERS_HEX_BEGIN - 10)); - } - else - { - return false; - } - - buf_p++; + /* zzzzyyyy yyxxxxxx */ + return 3; } - *out_code_unit_p = code_unit; - return true; -} /* lit_read_code_unit_from_hex */ + /* high + low surrogate */ + return 2 * 3; +} /* lit_code_point_get_cesu8_length */ + +/** + * Convert a four byte long utf8 character to two three byte long cesu8 characters + */ +void +lit_four_byte_utf8_char_to_cesu8 (uint8_t *dst_p, /**< destination buffer */ + const uint8_t *source_p) /**< source buffer */ +{ + lit_code_point_t code_point = ((((uint32_t) source_p[0]) & LIT_UTF8_LAST_3_BITS_MASK) << 18); + code_point |= ((((uint32_t) source_p[1]) & LIT_UTF8_LAST_6_BITS_MASK) << 12); + code_point |= ((((uint32_t) source_p[2]) & LIT_UTF8_LAST_6_BITS_MASK) << 6); + code_point |= (((uint32_t) source_p[3]) & LIT_UTF8_LAST_6_BITS_MASK); + + lit_code_point_to_cesu8_bytes (dst_p, code_point); +} /* lit_four_byte_utf8_char_to_cesu8 */ + +/** + * Lookup hex digits in a buffer + * + * @return UINT32_MAX - if next 'lookup' number of characters do not form a valid hex number + * value of hex number, otherwise + */ +uint32_t +lit_char_hex_lookup (const lit_utf8_byte_t *buf_p, /**< buffer */ + const lit_utf8_byte_t *const buf_end_p, /**< buffer end */ + uint32_t lookup) /**< size of lookup */ +{ + JERRY_ASSERT (lookup <= 4); + + if (JERRY_UNLIKELY (buf_p + lookup > buf_end_p)) + { + return UINT32_MAX; + } + + uint32_t value = 0; + + while (lookup--) + { + lit_utf8_byte_t ch = *buf_p++; + if (!lit_char_is_hex_digit (ch)) + { + return UINT32_MAX; + } + + value <<= 4; + value += lit_char_hex_to_int (ch); + } + + JERRY_ASSERT (value <= LIT_UTF16_CODE_UNIT_MAX); + return value; +} /* lit_char_hex_lookup */ + +/** + * Parse a decimal number with the value clamped to UINT32_MAX. + * + * @returns uint32_t number + */ +uint32_t +lit_parse_decimal (const lit_utf8_byte_t **buffer_p, /**< [in/out] character buffer */ + const lit_utf8_byte_t *buffer_end_p) /**< buffer end */ +{ + const lit_utf8_byte_t *current_p = *buffer_p; + JERRY_ASSERT (lit_char_is_decimal_digit (*current_p)); + + uint32_t value = (uint32_t) (*current_p++ - LIT_CHAR_0); + + while (current_p < buffer_end_p && lit_char_is_decimal_digit (*current_p)) + { + const uint32_t digit = (uint32_t) (*current_p++ - LIT_CHAR_0); + uint32_t new_value = value * 10 + digit; + + if (JERRY_UNLIKELY (value > UINT32_MAX / 10) || JERRY_UNLIKELY (new_value < value)) + { + value = UINT32_MAX; + continue; + } + + value = new_value; + } + + *buffer_p = current_p; + return value; +} /* lit_parse_decimal */ /** * Check if specified character is a word character (part of IsWordChar abstract operation) @@ -461,7 +506,7 @@ lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, /**< buffer with char * false - otherwise */ bool -lit_char_is_word_char (ecma_char_t c) /**< code unit */ +lit_char_is_word_char (lit_code_point_t c) /**< code point */ { return ((c >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && c <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END) || (c >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && c <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) diff --git a/jerry-core/lit/lit-char-helpers.h b/jerry-core/lit/lit-char-helpers.h index 08c0439a..3ad25b7f 100644 --- a/jerry-core/lit/lit-char-helpers.h +++ b/jerry-core/lit/lit-char-helpers.h @@ -18,8 +18,6 @@ #include "lit-globals.h" -#define LIT_CHAR_UNDEF ((ecma_char_t) 0xFFFF) /* undefined character */ - /* * Format control characters (ECMA-262 v5, Table 1) */ @@ -37,7 +35,7 @@ #define LIT_CHAR_NBSP ((ecma_char_t) 0x00A0) /* no-break space */ /* LIT_CHAR_BOM is defined above */ -bool lit_char_is_white_space (ecma_char_t c); +bool lit_char_is_white_space (lit_code_point_t c); /* * Line terminator characters (ECMA-262 v5, Table 3) @@ -75,10 +73,8 @@ bool lit_char_is_line_terminator (ecma_char_t c); #define LIT_CHAR_UNDERSCORE ((ecma_char_t) '_') /* low line (underscore) */ /* LIT_CHAR_BACKSLASH defined above */ -bool lit_char_is_identifier_start (const uint8_t *src_p); -bool lit_char_is_identifier_part (const uint8_t *src_p); -bool lit_char_is_identifier_start_character (ecma_char_t chr); -bool lit_char_is_identifier_part_character (ecma_char_t chr); +bool lit_code_point_is_identifier_start (lit_code_point_t code_point); +bool lit_code_point_is_identifier_part (lit_code_point_t code_point); /* * Punctuator characters (ECMA-262 v5, 7.7) @@ -214,13 +210,15 @@ bool lit_char_is_identifier_part_character (ecma_char_t chr); bool lit_char_is_octal_digit (ecma_char_t c); bool lit_char_is_decimal_digit (ecma_char_t c); bool lit_char_is_hex_digit (ecma_char_t c); +#if ENABLED (JERRY_ES2015) +bool lit_char_is_binary_digit (ecma_char_t c); +#endif /* ENABLED (JERRY_ES2015) */ uint32_t lit_char_hex_to_int (ecma_char_t c); -size_t lit_char_to_utf8_bytes (uint8_t *dst_p, ecma_char_t chr); -size_t lit_char_get_utf8_length (ecma_char_t chr); - -/* read a hex encoded code point from a zero terminated buffer */ -bool lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, lit_utf8_size_t number_of_characters, - ecma_char_t *out_code_unit_p); +size_t lit_code_point_to_cesu8_bytes (uint8_t *dst_p, lit_code_point_t code_point); +size_t lit_code_point_get_cesu8_length (lit_code_point_t code_point); +void lit_four_byte_utf8_char_to_cesu8 (uint8_t *dst_p, const uint8_t *source_p); +uint32_t lit_char_hex_lookup (const lit_utf8_byte_t *buf_p, const lit_utf8_byte_t *const buf_end_p, uint32_t lookup); +uint32_t lit_parse_decimal (const lit_utf8_byte_t **buffer_p, const lit_utf8_byte_t *const buffer_end_p); /** * Null character @@ -230,7 +228,7 @@ bool lit_read_code_unit_from_hex (const lit_utf8_byte_t *buf_p, lit_utf8_size_t /* * Part of IsWordChar abstract operation (ECMA-262 v5, 15.10.2.6, step 3) */ -bool lit_char_is_word_char (ecma_char_t c); +bool lit_char_is_word_char (lit_code_point_t c); /* * Utility functions for uppercasing / lowercasing diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index faf636b4..1ab61aa2 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -41,13 +41,15 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE, /**< [[Resolve]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT, /**< [[Reject]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY, /**< [[Capability]] property */ - LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_HANDLER, /**< [[Handler]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED, /**< [[AlreadyCalled]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */ LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT, /**< [[RemainingElement]] property */ LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX, /**< [[%Iterator%NextIndex]] property */ LIT_INTERNAL_MAGIC_STRING_MAP_KEY, /**< Property key used when an object is a key in a map object */ + LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */ + LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, /**< %ArrayProto_values% intrinsic routine */ + LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */ /* List of well known symbols */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */ @@ -68,7 +70,8 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */ LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal * magic strings */ - LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */ + LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ + LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT, /**< Internal object ID for internal properties */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index be61e781..5c8b6c4f 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -16,17 +16,15 @@ /* This file is automatically generated by the gen-magic-strings.py script * from lit-magic-strings.ini. Do not edit! */ - LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__EMPTY, "") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPACE_CHAR, " ") -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_PAREN, ")") -#endif #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASTERIX_CHAR, "*") #endif +#if ENABLED (JERRY_BUILTIN_ARRAY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",") -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COLON_CHAR, ":") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_E_U, "E") #endif @@ -35,18 +33,22 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR, "]") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PI_U, "PI") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS, "is") +#endif +#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OF, "of") #endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LN2_U, "LN2") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_UL, "Map") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAN, "NaN") -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) \ +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UL, "Set") #endif @@ -56,7 +58,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ABS, "abs") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015) && ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ADD, "add") #endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) @@ -66,12 +70,16 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ALL, "all") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COS, "cos") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXP, "exp") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FOR, "for") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET, "get") #if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SET) +|| ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS, "has") #endif #if ENABLED (JERRY_BUILTIN_MATH) @@ -94,6 +102,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_POP, "pop") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_POW, "pow") #endif +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RAW, "raw") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET, "set") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SIN, "sin") @@ -118,33 +129,44 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATAN, "atan") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIND, "bind") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CALL, "call") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CBRT, "cbrt") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CEIL, "ceil") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COSH, "cosh") +#endif +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DONE, "done") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVAL, "eval") #if ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXEC, "exec") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FILL, "fill") -#endif -#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN) \ +#if ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FILL, "fill") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FIND, "find") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FROM, "from") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IMUL, "imul") +#endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_JOIN, "join") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_KEYS, "keys") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG2, "log2") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAME, "name") -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +#if ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_MAP) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NEXT, "next") @@ -157,8 +179,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PUSH, "push") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RACE, "race") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal") -#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SIGN, "sign") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SINH, "sinh") #endif #if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) @@ -172,6 +195,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SORT, "sort") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT, "sqrt") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TANH, "tanh") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TEST, "test") #endif @@ -186,12 +212,26 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARRAY_UL, "Array") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ERROR_UL, "Error") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG2E_U, "LOG2E") +#endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROXY_UL, "Proxy") +#endif +#if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT2_U, "SQRT2") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ACOSH, "acosh") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_APPLY, "apply") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASINH, "asinh") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATAN2, "atan2") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATANH, "atanh") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch") #endif @@ -199,10 +239,16 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch") || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLEAR, "clear") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLZ32, "clz32") +#endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVERY, "every") #endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXPM1, "expm1") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FALSE, "false") #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FLAGS, "flags") @@ -210,22 +256,29 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FLAGS, "flags") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FLOOR, "floor") #endif -#if ENABLED (JERRY_BUILTIN_REGEXP) \ -|| ENABLED (JERRY_BUILTIN_STRING) -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INDEX, "index") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HYPOT, "hypot") #endif #if ENABLED (JERRY_BUILTIN_REGEXP) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INDEX, "index") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INPUT, "input") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_NAN, "isNaN") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG10, "log10") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG1P, "log1p") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +|| ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MATCH, "match") #endif #if ENABLED (JERRY_BUILTIN_DATE) \ || ENABLED (JERRY_BUILTIN_JSON) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE, "parse") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROXY, "proxy") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ROUND, "round") #endif @@ -238,10 +291,13 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SHIFT, "shift") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLICE, "slice") #endif #if ENABLED (JERRY_BUILTIN_STRING) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +|| ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPLIT, "split") #endif -#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_THROW, "throw") +#endif +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TRUNC, "trunc") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_VALUE, "value") @@ -255,10 +311,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NUMBER_UL, "Number") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OBJECT_UL, "Object") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REGEXP_UL, "RegExp") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING_UL, "String") -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_UL, "Symbol") -#endif -#if ENABLED (JERRY_ES2015_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASSIGN, "assign") #endif #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) \ @@ -276,7 +330,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONCAT, "concat") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CREATE, "create") #if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SET) +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE, "delete") #endif #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -287,19 +343,19 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ESCAPE, "escape") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FILTER, "filter") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FREEZE, "freeze") +#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FROUND, "fround") +#endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_DAY_UL, "getDay") #endif -#if !ENABLED (JERRY_ES2015) && ENABLED (JERRY_BUILTIN_REGEXP) \ -|| ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ -|| ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_ES2015) \ -|| ENABLED (JERRY_BUILTIN_REGEXP) && !( ENABLED (JERRY_ES2015)) +#if ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GLOBAL, "global") #endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_VIEW_UL, "isView") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_KEY_FOR, "keyFor") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LENGTH, "length") @@ -315,11 +371,17 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REDUCE, "reduce") #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REJECT, "reject") #endif -#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPEAT, "repeat") #endif +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RETURN, "return") +#endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REVOKE, "revoke") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +|| ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEARCH, "search") #endif #if !ENABLED (JERRY_ES2015) && ENABLED (JERRY_BUILTIN_REGEXP) \ @@ -330,45 +392,55 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SOURCE, "source") #if ENABLED (JERRY_BUILTIN_ARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPLICE, "splice") #endif +#if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_BUILTIN_REGEXP) && !( !ENABLED (JERRY_ES2015)) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STICKY, "sticky") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING, "string") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SUBSTR, "substr") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL, "symbol") #endif #if ENABLED (JERRY_BUILTIN_DATE) \ || ENABLED (JERRY_BUILTIN_JSON) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_JSON_UL, "toJSON") #endif -#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_SET) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_VALUES, "values") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN_UL, "Boolean") +#if ENABLED (JERRY_BUILTIN_NUMBER) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EPSILON_U, "EPSILON") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROMISE_UL, "Promise") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REFLECT_UL, "Reflect") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT1_2_U, "SQRT1_2") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_LEFT_PAREN_UL, "Symbol(") -LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_DOT_UL, "Symbol.") +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKMAP_UL, "WeakMap") +#endif +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKSET_UL, "WeakSet") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile") #endif -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) +#if ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_MODULE_SYSTEM) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEFAULT, "default") #endif -#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_SET) \ -|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) && ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENTRIES, "entries") #endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ @@ -398,8 +470,12 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INDEX_OF_UL, "indexOf") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_ARRAY_UL, "isArray") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MESSAGE, "message") +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OWN_KEYS_UL, "ownKeys") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +|| ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPLACE, "replace") #endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) @@ -421,12 +497,15 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_TIME_UL, "setTime") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_YEAR_UL, "setYear") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPECIES, "species") #endif #if ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_FIXED_UL, "toFixed") #endif +#if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNICODE, "unicode") +#endif #if ENABLED (JERRY_BUILTIN_ARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNSHIFT, "unshift") #endif @@ -439,7 +518,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INFINITY_UL, "Infinity") #if ENABLED (JERRY_BUILTIN_ERRORS) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_URI_ERROR_UL, "URIError") #endif -#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENDS_WITH, "endsWith") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION, "function") @@ -456,17 +535,19 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_MONTH_UL, "getMonth") #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UINT8_UL, "getUint8") #endif -#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INCLUDES, "includes") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_FINITE, "isFinite") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_FROZEN_UL, "isFrozen") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_SEALED_UL, "isSealed") -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ITERATOR, "iterator") #endif +#if ENABLED (JERRY_ES2015) \ +|| !( ENABLED (JERRY_ES2015)) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE_INT, "parseInt") +#endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_HOURS_UL, "setHours") #endif @@ -493,6 +574,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARGUMENTS_UL, "Arguments") #if ENABLED (JERRY_BUILTIN_ERRORS) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVAL_ERROR_UL, "EvalError") #endif +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GENERATOR_UL, "Generator") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INT8_ARRAY_UL, "Int8Array") #endif @@ -504,10 +588,15 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MIN_VALUE_U, "MIN_VALUE") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TYPE_ERROR_UL, "TypeError") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNDEFINED_UL, "Undefined") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__PROTO__, "__proto__") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARGUMENTS, "arguments") +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONSTRUCT, "construct") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DECODE_URI, "decodeURI") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENCODE_URI, "encodeURI") -#if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN) \ +#if ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FIND_INDEX, "findIndex") #endif @@ -518,7 +607,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_DAY_UL, "getUTCDay") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UINT16_UL, "getUint16") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UINT32_UL, "getUint32") #endif -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_INTEGER, "isInteger") #endif #if ENABLED (JERRY_BUILTIN_REGEXP) @@ -530,6 +619,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LASTINDEX_UL, "lastIndex") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MULTILINE, "multiline") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROTOTYPE, "prototype") +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REVOCABLE, "revocable") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UINT16_UL, "setUint16") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UINT32_UL, "setUint32") @@ -560,7 +652,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTE_OFFSET_UL, "byteOffset") #if ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, "charCodeAt") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#if ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COPY_WITHIN, "copyWithin") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENUMERABLE, "enumerable") @@ -580,7 +673,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_DATE_UL, "getUTCDate") || ENABLED (JERRY_BUILTIN_REGEXP) && !( ENABLED (JERRY_ES2015)) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IGNORECASE_UL, "ignoreCase") #endif +#if ENABLED (JERRY_ES2015) \ +|| !( ENABLED (JERRY_ES2015)) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE_FLOAT, "parseFloat") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_FLOAT_32_UL, "setFloat32") #endif @@ -592,12 +688,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_MINUTES_UL, "setMinutes") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_SECONDS_UL, "setSeconds") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UTC_DATE_UL, "setUTCDate") #endif -#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STARTS_WITH, "startsWith") #endif -#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RESOURCE_ANON, "") -#endif #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARRAY_BUFFER_UL, "ArrayBuffer") @@ -609,13 +703,16 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYNTAX_ERROR_UL, "SyntaxError") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UINT16_ARRAY_UL, "Uint16Array") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UINT32_ARRAY_UL, "Uint32Array") #endif +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CODE_POINT_AT, "codePointAt") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONSTRUCTOR, "constructor") #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FULL_YEAR_UL, "getFullYear") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_HOURS_UL, "getUTCHours") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_MONTH_UL, "getUTCMonth") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS_INSTANCE, "hasInstance") #endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ @@ -644,7 +741,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_LOWER_CASE_UL, "toLowerCase") #if ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_PRECISION_UL, "toPrecision") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_PRIMITIVE, "toPrimitive") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_STRING_TAG, "toStringTag") #endif @@ -654,7 +751,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_UTC_STRING_UL, "toUTCString") #if ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_UPPER_CASE_UL, "toUpperCase") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNSCOPABLES, "unscopables") #endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -666,11 +763,11 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FLOAT64_ARRAY_UL, "Float64Array") #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INVALID_DATE_UL, "Invalid Date") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +#if ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_ITERATOR_UL, "Map Iterator") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +#if ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_ITERATOR_UL, "Set Iterator") #endif @@ -682,11 +779,16 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_EXTENSIBLE, "isExtensible") #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_DATE_STRING_UL, "toDateString") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_TIME_STRING_UL, "toTimeString") +#endif +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FROM_CODE_POINT_UL, "fromCodePoint") +#endif +#if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_MINUTES_UL, "getUTCMinutes") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_SECONDS_UL, "getUTCSeconds") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL, "isPrototypeOf") -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_SAFE_INTEGER, "isSafeInteger") #endif #if ENABLED (JERRY_BUILTIN_STRING) @@ -699,36 +801,49 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UTC_SECONDS_UL, "setUTCSeconds") #if ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_EXPONENTIAL_UL, "toExponential") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARRAY_ITERATOR_UL, "Array Iterator") #endif #if ENABLED (JERRY_BUILTIN_ERRORS) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REFERENCE_ERROR_UL, "ReferenceError") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEFINE_PROPERTY_UL, "defineProperty") +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE_PROPERTY_UL, "deleteProperty") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL, "getPrototypeOf") #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_FULL_YEAR_UL, "getUTCFullYear") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS_OWN_PROPERTY_UL, "hasOwnProperty") -#if ENABLED (JERRY_ES2015_BUILTIN) +#if ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_PROXY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_REFLECT) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_PROTOTYPE_OF_UL, "setPrototypeOf") #endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UTC_FULL_YEAR_UL, "setUTCFullYear") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_LOCALE_STRING_UL, "toLocaleString") -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING_ITERATOR_UL, "String Iterator") #endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_MILLISECONDS_UL, "getMilliseconds") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_MILLISECONDS_UL, "setMilliseconds") #endif +#if ENABLED (JERRY_BUILTIN_NUMBER) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAX_SAFE_INTEGER_U, "MAX_SAFE_INTEGER") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MIN_SAFE_INTEGER_U, "MIN_SAFE_INTEGER") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL, "defineProperties") #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U, "BYTES_PER_ELEMENT") #endif +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, "GeneratorFunction") +#endif #if ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NEGATIVE_INFINITY_U, "NEGATIVE_INFINITY") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_POSITIVE_INFINITY_U, "POSITIVE_INFINITY") @@ -749,7 +864,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENCODE_URI_COMPONENT, "encodeURIComponent #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_MILLISECONDS_UL, "getUTCMilliseconds") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_CONCAT_SPREADABLE, "isConcatSpreadable") #endif #if ENABLED (JERRY_BUILTIN_DATE) @@ -759,7 +874,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_LOCALE_TIME_STRING_UL, "toLocaleTimeSt #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL, "getOwnPropertyNames") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL, "propertyIsEnumerable") -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL, "getOwnPropertySymbols") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL, "getOwnPropertyDescriptor") @@ -769,20 +884,23 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (0, LIT_MAGIC_STRING__EMPTY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (1, LIT_MAGIC_STRING_SPACE_CHAR) #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_PI_U) -#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#elif ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_IS) +#elif ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_OF) #elif ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_LN2_U) -#elif ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#elif ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_MAP_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_NAN) #endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_LN2_U) -#elif ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#elif ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_MAP_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_NAN) @@ -818,60 +936,60 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_TYPED_ARRAY_UL) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_BYTE_LENGTH_UL) #elif ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_CHAR_CODE_AT_UL) -#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +#elif ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_COPY_WITHIN) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_ENUMERABLE) #endif -#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (11, LIT_MAGIC_STRING_RESOURCE_ANON) -#elif ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) \ -|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) -LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (11, LIT_MAGIC_STRING_ARRAY_BUFFER_UL) -#elif ENABLED (JERRY_BUILTIN_ERRORS) -LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (11, LIT_MAGIC_STRING_SYNTAX_ERROR_UL) -#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) -LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (11, LIT_MAGIC_STRING_UINT16_ARRAY_UL) -#else -LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (11, LIT_MAGIC_STRING_CONSTRUCTOR) -#endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_FLOAT32_ARRAY_UL) #elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) && ENABLED (JERRY_NUMBER_TYPE_FLOAT64) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_FLOAT64_ARRAY_UL) #elif ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_INVALID_DATE_UL) -#elif ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +#elif ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_MAP_ITERATOR_UL) -#elif ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +#elif ENABLED (JERRY_ES2015) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_SET_ITERATOR_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_CONFIGURABLE) #endif -#if ENABLED (JERRY_BUILTIN_DATE) +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_FROM_CODE_POINT_UL) +#elif ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_GET_UTC_MINUTES_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL) #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (14, LIT_MAGIC_STRING_ARRAY_ITERATOR_UL) #elif ENABLED (JERRY_BUILTIN_ERRORS) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (14, LIT_MAGIC_STRING_REFERENCE_ERROR_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (14, LIT_MAGIC_STRING_DEFINE_PROPERTY_UL) #endif -#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (15, LIT_MAGIC_STRING_STRING_ITERATOR_UL) #elif ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (15, LIT_MAGIC_STRING_GET_MILLISECONDS_UL) +#elif ENABLED (JERRY_BUILTIN_NUMBER) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (15, LIT_MAGIC_STRING_MAX_SAFE_INTEGER_U) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (15, LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL) #endif +#if ENABLED (JERRY_BUILTIN_NUMBER) && ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (16, LIT_MAGIC_STRING_MAX_SAFE_INTEGER_U) +#else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (16, LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL) +#endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U) +#elif ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL) #elif ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_NEGATIVE_INFINITY_U) #elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -884,7 +1002,7 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_PREVENT_EXTENSIONS LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (18, LIT_MAGIC_STRING_DECODE_URI_COMPONENT) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (19, LIT_MAGIC_STRING_GET_OWN_PROPERTY_NAMES_UL) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (20, LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL) -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (21, LIT_MAGIC_STRING_GET_OWN_PROPERTY_SYMBOLS_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (21, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL) diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 6662ffcf..75180dba 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -25,13 +25,12 @@ LIT_MAGIC_STRING__EMPTY = "" LIT_MAGIC_STRING_ASTERIX_CHAR = "*" LIT_MAGIC_STRING_SPACE_CHAR = " " -LIT_MAGIC_STRING_RIGHT_PAREN = ")" LIT_MAGIC_STRING_COMMA_CHAR = "," -LIT_MAGIC_STRING_COLON_CHAR = ":" LIT_MAGIC_STRING_E_U = "E" LIT_MAGIC_STRING_LEFT_SQUARE_CHAR = "[" LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR = "]" LIT_MAGIC_STRING_PI_U = "PI" +LIT_MAGIC_STRING_IS = "is" LIT_MAGIC_STRING_OF = "of" LIT_MAGIC_STRING_LN2_U = "LN2" LIT_MAGIC_STRING_MAP_UL = "Map" @@ -53,6 +52,7 @@ LIT_MAGIC_STRING_MIN = "min" LIT_MAGIC_STRING_NOW = "now" LIT_MAGIC_STRING_POP = "pop" LIT_MAGIC_STRING_POW = "pow" +LIT_MAGIC_STRING_RAW = "raw" LIT_MAGIC_STRING_SET = "set" LIT_MAGIC_STRING_SIN = "sin" LIT_MAGIC_STRING_TAN = "tan" @@ -67,15 +67,19 @@ LIT_MAGIC_STRING_ASIN = "asin" LIT_MAGIC_STRING_ATAN = "atan" LIT_MAGIC_STRING_BIND = "bind" LIT_MAGIC_STRING_CALL = "call" +LIT_MAGIC_STRING_CBRT = "cbrt" LIT_MAGIC_STRING_CEIL = "ceil" +LIT_MAGIC_STRING_COSH = "cosh" LIT_MAGIC_STRING_DONE = "done" LIT_MAGIC_STRING_EVAL = "eval" LIT_MAGIC_STRING_EXEC = "exec" LIT_MAGIC_STRING_FILL = "fill" LIT_MAGIC_STRING_FIND = "find" LIT_MAGIC_STRING_FROM = "from" +LIT_MAGIC_STRING_IMUL = "imul" LIT_MAGIC_STRING_JOIN = "join" LIT_MAGIC_STRING_KEYS = "keys" +LIT_MAGIC_STRING_LOG2 = "log2" LIT_MAGIC_STRING_NAME = "name" LIT_MAGIC_STRING_NULL = "null" LIT_MAGIC_STRING_NEXT = "next" @@ -84,34 +88,47 @@ LIT_MAGIC_STRING_RACE = "race" LIT_MAGIC_STRING_SEAL = "seal" LIT_MAGIC_STRING_SIGN = "sign" LIT_MAGIC_STRING_SIZE = "size" +LIT_MAGIC_STRING_SINH = "sinh" LIT_MAGIC_STRING_SOME = "some" LIT_MAGIC_STRING_SORT = "sort" LIT_MAGIC_STRING_SQRT = "sqrt" +LIT_MAGIC_STRING_TANH = "tanh" LIT_MAGIC_STRING_TEST = "test" LIT_MAGIC_STRING_THEN = "then" LIT_MAGIC_STRING_TRIM = "trim" LIT_MAGIC_STRING_TRUE = "true" LIT_MAGIC_STRING_ARRAY_UL = "Array" LIT_MAGIC_STRING_ERROR_UL = "Error" +LIT_MAGIC_STRING_PROXY_UL = "Proxy" LIT_MAGIC_STRING_LOG2E_U = "LOG2E" LIT_MAGIC_STRING_SQRT2_U = "SQRT2" +LIT_MAGIC_STRING_ACOSH = "acosh" LIT_MAGIC_STRING_APPLY = "apply" +LIT_MAGIC_STRING_ASINH = "asinh" LIT_MAGIC_STRING_ATAN2 = "atan2" +LIT_MAGIC_STRING_ATANH = "atanh" LIT_MAGIC_STRING_CATCH = "catch" LIT_MAGIC_STRING_CLEAR = "clear" +LIT_MAGIC_STRING_CLZ32 = "clz32" LIT_MAGIC_STRING_EVERY = "every" +LIT_MAGIC_STRING_EXPM1 = "expm1" LIT_MAGIC_STRING_FALSE = "false" LIT_MAGIC_STRING_FLAGS = "flags" LIT_MAGIC_STRING_FLOOR = "floor" +LIT_MAGIC_STRING_HYPOT = "hypot" LIT_MAGIC_STRING_INDEX = "index" LIT_MAGIC_STRING_INPUT = "input" LIT_MAGIC_STRING_IS_NAN = "isNaN" +LIT_MAGIC_STRING_LOG1P = "log1p" +LIT_MAGIC_STRING_LOG10 = "log10" LIT_MAGIC_STRING_MATCH = "match" LIT_MAGIC_STRING_PARSE = "parse" +LIT_MAGIC_STRING_PROXY = "proxy" LIT_MAGIC_STRING_ROUND = "round" LIT_MAGIC_STRING_SHIFT = "shift" LIT_MAGIC_STRING_SLICE = "slice" LIT_MAGIC_STRING_SPLIT = "split" +LIT_MAGIC_STRING_THROW = "throw" LIT_MAGIC_STRING_TRUNC = "trunc" LIT_MAGIC_STRING_VALUE = "value" LIT_MAGIC_STRING_RESOURCE_EVAL = "" @@ -132,6 +149,7 @@ LIT_MAGIC_STRING_DELETE = "delete" LIT_MAGIC_STRING_ESCAPE = "escape" LIT_MAGIC_STRING_FILTER = "filter" LIT_MAGIC_STRING_FREEZE = "freeze" +LIT_MAGIC_STRING_FROUND = "fround" LIT_MAGIC_STRING_GET_DAY_UL = "getDay" LIT_MAGIC_STRING_GLOBAL = "global" LIT_MAGIC_STRING_IS_VIEW_UL = "isView" @@ -143,10 +161,13 @@ LIT_MAGIC_STRING_RANDOM = "random" LIT_MAGIC_STRING_REDUCE = "reduce" LIT_MAGIC_STRING_REJECT = "reject" LIT_MAGIC_STRING_REPEAT = "repeat" +LIT_MAGIC_STRING_REVOKE = "revoke" +LIT_MAGIC_STRING_RETURN = "return" LIT_MAGIC_STRING_SEARCH = "search" LIT_MAGIC_STRING_SOURCE = "source" LIT_MAGIC_STRING_SPLICE = "splice" LIT_MAGIC_STRING_STRING = "string" +LIT_MAGIC_STRING_STICKY = "sticky" LIT_MAGIC_STRING_SYMBOL = "symbol" LIT_MAGIC_STRING_SUBSTR = "substr" LIT_MAGIC_STRING_ENTRIES = "entries" @@ -154,9 +175,8 @@ LIT_MAGIC_STRING_TO_JSON_UL = "toJSON" LIT_MAGIC_STRING_VALUES = "values" LIT_MAGIC_STRING_BOOLEAN_UL = "Boolean" LIT_MAGIC_STRING_PROMISE_UL = "Promise" +LIT_MAGIC_STRING_REFLECT_UL = "Reflect" LIT_MAGIC_STRING_SQRT1_2_U = "SQRT1_2" -LIT_MAGIC_STRING_SYMBOL_LEFT_PAREN_UL = "Symbol(" -LIT_MAGIC_STRING_SYMBOL_DOT_UL = "Symbol." LIT_MAGIC_STRING_BOOLEAN = "boolean" LIT_MAGIC_STRING_COMPILE = "compile" LIT_MAGIC_STRING_DEFAULT = "default" @@ -168,6 +188,7 @@ LIT_MAGIC_STRING_GET_YEAR_UL = "getYear" LIT_MAGIC_STRING_INDEX_OF_UL = "indexOf" LIT_MAGIC_STRING_IS_ARRAY_UL = "isArray" LIT_MAGIC_STRING_MESSAGE = "message" +LIT_MAGIC_STRING_OWN_KEYS_UL = "ownKeys" LIT_MAGIC_STRING_REPLACE = "replace" LIT_MAGIC_STRING_RESOLVE = "resolve" LIT_MAGIC_STRING_REVERSE = "reverse" @@ -177,8 +198,12 @@ LIT_MAGIC_STRING_SET_INT8_UL = "setInt8" LIT_MAGIC_STRING_SET_YEAR_UL = "setYear" LIT_MAGIC_STRING_SPECIES = "species" LIT_MAGIC_STRING_TO_FIXED_UL = "toFixed" +LIT_MAGIC_STRING_UNICODE = "unicode" LIT_MAGIC_STRING_UNSHIFT = "unshift" LIT_MAGIC_STRING_VALUE_OF_UL = "valueOf" +LIT_MAGIC_STRING_WEAKMAP_UL = "WeakMap" +LIT_MAGIC_STRING_WEAKSET_UL = "WeakSet" +LIT_MAGIC_STRING_EPSILON_U = "EPSILON" LIT_MAGIC_STRING_DATAVIEW_UL = "DataView" LIT_MAGIC_STRING_FUNCTION_UL = "Function" LIT_MAGIC_STRING_INFINITY_UL = "Infinity" @@ -207,6 +232,7 @@ LIT_MAGIC_STRING_UNESCAPE = "unescape" LIT_MAGIC_STRING_WRITABLE = "writable" LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL = "-Infinity" LIT_MAGIC_STRING_ARGUMENTS_UL = "Arguments" +LIT_MAGIC_STRING_CONSTRUCT = "construct" LIT_MAGIC_STRING_EVAL_ERROR_UL = "EvalError" LIT_MAGIC_STRING_INT8_ARRAY_UL = "Int8Array" LIT_MAGIC_STRING_IS_INTEGER = "isInteger" @@ -214,16 +240,19 @@ LIT_MAGIC_STRING_MAX_VALUE_U = "MAX_VALUE" LIT_MAGIC_STRING_MIN_VALUE_U = "MIN_VALUE" LIT_MAGIC_STRING_TYPE_ERROR_UL = "TypeError" LIT_MAGIC_STRING_UNDEFINED_UL = "Undefined" +LIT_MAGIC_STRING__PROTO__ = "__proto__" LIT_MAGIC_STRING_ARGUMENTS = "arguments" LIT_MAGIC_STRING_DECODE_URI = "decodeURI" LIT_MAGIC_STRING_ENCODE_URI = "encodeURI" LIT_MAGIC_STRING_FIND_INDEX = "findIndex" +LIT_MAGIC_STRING_GENERATOR_UL = "Generator" LIT_MAGIC_STRING_GET_UTC_DAY_UL = "getUTCDay" LIT_MAGIC_STRING_GET_UINT16_UL = "getUint16" LIT_MAGIC_STRING_GET_UINT32_UL = "getUint32" LIT_MAGIC_STRING_LASTINDEX_UL = "lastIndex" LIT_MAGIC_STRING_MULTILINE = "multiline" LIT_MAGIC_STRING_PROTOTYPE = "prototype" +LIT_MAGIC_STRING_REVOCABLE = "revocable" LIT_MAGIC_STRING_STRINGIFY = "stringify" LIT_MAGIC_STRING_SET_UINT16_UL = "setUint16" LIT_MAGIC_STRING_SET_UINT32_UL = "setUint32" @@ -258,6 +287,7 @@ LIT_MAGIC_STRING_SYNTAX_ERROR_UL = "SyntaxError" LIT_MAGIC_STRING_UINT16_ARRAY_UL = "Uint16Array" LIT_MAGIC_STRING_UINT32_ARRAY_UL = "Uint32Array" LIT_MAGIC_STRING_CONSTRUCTOR = "constructor" +LIT_MAGIC_STRING_CODE_POINT_AT = "codePointAt" LIT_MAGIC_STRING_GET_FULL_YEAR_UL = "getFullYear" LIT_MAGIC_STRING_GET_UTC_HOURS_UL = "getUTCHours" LIT_MAGIC_STRING_GET_UTC_MONTH_UL = "getUTCMonth" @@ -283,6 +313,7 @@ LIT_MAGIC_STRING_SET_ITERATOR_UL = "Set Iterator" LIT_MAGIC_STRING_MAP_ITERATOR_UL = "Map Iterator" LIT_MAGIC_STRING_CONFIGURABLE = "configurable" LIT_MAGIC_STRING_FROM_CHAR_CODE_UL = "fromCharCode" +LIT_MAGIC_STRING_FROM_CODE_POINT_UL = "fromCodePoint" LIT_MAGIC_STRING_IS_EXTENSIBLE = "isExtensible" LIT_MAGIC_STRING_TO_DATE_STRING_UL = "toDateString" LIT_MAGIC_STRING_TO_TIME_STRING_UL = "toTimeString" @@ -297,6 +328,7 @@ LIT_MAGIC_STRING_TO_EXPONENTIAL_UL = "toExponential" LIT_MAGIC_STRING_ARRAY_ITERATOR_UL = "Array Iterator" LIT_MAGIC_STRING_REFERENCE_ERROR_UL = "ReferenceError" LIT_MAGIC_STRING_DEFINE_PROPERTY_UL = "defineProperty" +LIT_MAGIC_STRING_DELETE_PROPERTY_UL = "deleteProperty" LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL = "getPrototypeOf" LIT_MAGIC_STRING_GET_UTC_FULL_YEAR_UL = "getUTCFullYear" LIT_MAGIC_STRING_HAS_OWN_PROPERTY_UL = "hasOwnProperty" @@ -307,9 +339,12 @@ LIT_MAGIC_STRING_STRING_ITERATOR_UL = "String Iterator" LIT_MAGIC_STRING_GET_MILLISECONDS_UL = "getMilliseconds" LIT_MAGIC_STRING_SET_MILLISECONDS_UL = "setMilliseconds" LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL = "defineProperties" +LIT_MAGIC_STRING_MAX_SAFE_INTEGER_U = "MAX_SAFE_INTEGER" +LIT_MAGIC_STRING_MIN_SAFE_INTEGER_U = "MIN_SAFE_INTEGER" LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U = "BYTES_PER_ELEMENT" LIT_MAGIC_STRING_NEGATIVE_INFINITY_U = "NEGATIVE_INFINITY" LIT_MAGIC_STRING_POSITIVE_INFINITY_U = "POSITIVE_INFINITY" +LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL = "GeneratorFunction" LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL = "Uint8ClampedArray" LIT_MAGIC_STRING_GET_TIMEZONE_OFFSET_UL = "getTimezoneOffset" LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL = "preventExtensions" diff --git a/jerry-core/lit/lit-strings.c b/jerry-core/lit/lit-strings.c index 223d11ba..c2fbb35f 100644 --- a/jerry-core/lit/lit-strings.c +++ b/jerry-core/lit/lit-strings.c @@ -243,17 +243,42 @@ convert_code_point_to_high_surrogate (lit_code_point_t code_point) /**< code poi return (LIT_UTF16_HIGH_SURROGATE_MARKER | code_unit_bits); } /* convert_code_point_to_high_surrogate */ +/** + * UTF16 Encoding method for a code point + * + * See also: + * ECMA-262 v6, 10.1.1 + * + * @return uint8_t, the number of returning code points + */ +uint8_t +lit_utf16_encode_code_point (lit_code_point_t cp, /**< the code point we encode */ + ecma_char_t *cu_p) /**< result of the encoding */ +{ + if (cp <= LIT_UTF16_CODE_UNIT_MAX) + { + cu_p[0] = (ecma_char_t) cp; + return 1; + } + + cu_p[0] = convert_code_point_to_high_surrogate (cp); + cu_p[1] = convert_code_point_to_low_surrogate (cp); + return 2; +} /* lit_utf16_encode_code_point */ + /** * Calculate size of a zero-terminated utf-8 string * * NOTE: - * string should not contain zero characters in the middel + * - string cannot be NULL + * - string should not contain zero characters in the middle * * @return size of a string */ lit_utf8_size_t lit_zt_utf8_string_size (const lit_utf8_byte_t *utf8_str_p) /**< zero-terminated utf-8 string */ { + JERRY_ASSERT (utf8_str_p != NULL); return (lit_utf8_size_t) strlen ((const char *) utf8_str_p); } /* lit_zt_utf8_string_size */ @@ -456,7 +481,7 @@ lit_read_prev_code_unit_from_utf8 (const lit_utf8_byte_t *buf_p, /**< buffer wit * @return next code unit */ ecma_char_t -lit_utf8_read_next (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with characters */ +lit_cesu8_read_next (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with characters */ { JERRY_ASSERT (*buf_p); ecma_char_t ch; @@ -464,7 +489,7 @@ lit_utf8_read_next (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with cha *buf_p += lit_read_code_unit_from_utf8 (*buf_p, &ch); return ch; -} /* lit_utf8_read_next */ +} /* lit_cesu8_read_next */ /** * Decodes a unicode code unit from non-empty cesu-8-encoded buffer @@ -472,7 +497,7 @@ lit_utf8_read_next (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with cha * @return previous code unit */ ecma_char_t -lit_utf8_read_prev (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with characters */ +lit_cesu8_read_prev (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with characters */ { JERRY_ASSERT (*buf_p); ecma_char_t ch; @@ -481,44 +506,44 @@ lit_utf8_read_prev (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with cha lit_read_code_unit_from_utf8 (*buf_p, &ch); return ch; -} /* lit_utf8_read_prev */ +} /* lit_cesu8_read_prev */ /** * Decodes a unicode code unit from non-empty cesu-8-encoded buffer * * @return next code unit */ -ecma_char_t -lit_utf8_peek_next (const lit_utf8_byte_t *buf_p) /**< [in,out] buffer with characters */ +ecma_char_t JERRY_ATTR_NOINLINE +lit_cesu8_peek_next (const lit_utf8_byte_t *buf_p) /**< [in,out] buffer with characters */ { - JERRY_ASSERT (buf_p); + JERRY_ASSERT (buf_p != NULL); ecma_char_t ch; lit_read_code_unit_from_utf8 (buf_p, &ch); return ch; -} /* lit_utf8_peek_next */ +} /* lit_cesu8_peek_next */ /** * Decodes a unicode code unit from non-empty cesu-8-encoded buffer * * @return previous code unit */ -ecma_char_t -lit_utf8_peek_prev (const lit_utf8_byte_t *buf_p) /**< [in,out] buffer with characters */ +ecma_char_t JERRY_ATTR_NOINLINE +lit_cesu8_peek_prev (const lit_utf8_byte_t *buf_p) /**< [in,out] buffer with characters */ { - JERRY_ASSERT (buf_p); + JERRY_ASSERT (buf_p != NULL); ecma_char_t ch; lit_read_prev_code_unit_from_utf8 (buf_p, &ch); return ch; -} /* lit_utf8_peek_prev */ +} /* lit_cesu8_peek_prev */ /** * Increase cesu-8 encoded string pointer by one code unit. */ -void +inline void JERRY_ATTR_ALWAYS_INLINE lit_utf8_incr (const lit_utf8_byte_t **buf_p) /**< [in,out] buffer with characters */ { JERRY_ASSERT (*buf_p); diff --git a/jerry-core/lit/lit-strings.h b/jerry-core/lit/lit-strings.h index 208108bd..458ca0a0 100644 --- a/jerry-core/lit/lit-strings.h +++ b/jerry-core/lit/lit-strings.h @@ -46,7 +46,6 @@ #define LIT_UTF8_2_BYTE_MARKER (0xC0) #define LIT_UTF8_3_BYTE_MARKER (0xE0) #define LIT_UTF8_4_BYTE_MARKER (0xF0) -#define LIT_UTF8_5_BYTE_MARKER (0xF8) #define LIT_UTF8_EXTRA_BYTE_MARKER (0x80) #define LIT_UTF8_1_BYTE_MASK (0x80) @@ -82,7 +81,7 @@ /** * Byte values >= LIT_UTF8_FIRST_BYTE_MAX are not allowed in internal strings */ -#define LIT_UTF8_FIRST_BYTE_MAX LIT_UTF8_5_BYTE_MARKER +#define LIT_UTF8_FIRST_BYTE_MAX (0xF8) /* validation */ bool lit_is_valid_utf8_string (const lit_utf8_byte_t *utf8_buf_p, lit_utf8_size_t buf_size); @@ -123,6 +122,8 @@ lit_code_point_t lit_convert_surrogate_pair_to_code_point (ecma_char_t high_surr bool lit_compare_utf8_strings_relational (const lit_utf8_byte_t *string1_p, lit_utf8_size_t string1_size, const lit_utf8_byte_t *string2_p, lit_utf8_size_t string2_size); +uint8_t lit_utf16_encode_code_point (lit_code_point_t cp, ecma_char_t *cu_p); + /* read code point from buffer */ lit_utf8_size_t lit_read_code_point_from_utf8 (const lit_utf8_byte_t *buf_p, lit_utf8_size_t buf_size, lit_code_point_t *code_point); @@ -133,10 +134,10 @@ lit_utf8_size_t lit_read_code_unit_from_utf8 (const lit_utf8_byte_t *buf_p, lit_utf8_size_t lit_read_prev_code_unit_from_utf8 (const lit_utf8_byte_t *buf_p, ecma_char_t *code_point); -ecma_char_t lit_utf8_read_next (const lit_utf8_byte_t **buf_p); -ecma_char_t lit_utf8_read_prev (const lit_utf8_byte_t **buf_p); -ecma_char_t lit_utf8_peek_next (const lit_utf8_byte_t *buf_p); -ecma_char_t lit_utf8_peek_prev (const lit_utf8_byte_t *buf_p); +ecma_char_t lit_cesu8_read_next (const lit_utf8_byte_t **buf_p); +ecma_char_t lit_cesu8_read_prev (const lit_utf8_byte_t **buf_p); +ecma_char_t lit_cesu8_peek_next (const lit_utf8_byte_t *buf_p); +ecma_char_t lit_cesu8_peek_prev (const lit_utf8_byte_t *buf_p); void lit_utf8_incr (const lit_utf8_byte_t **buf_p); void lit_utf8_decr (const lit_utf8_byte_t **buf_p); diff --git a/jerry-core/lit/lit-unicode-conversions.inc.h b/jerry-core/lit/lit-unicode-conversions.inc.h index 1398597e..b0b83a04 100644 --- a/jerry-core/lit/lit-unicode-conversions.inc.h +++ b/jerry-core/lit/lit-unicode-conversions.inc.h @@ -14,7 +14,7 @@ */ /* This file is automatically generated by the gen-unicode.py script - * from UnicodeData-9.0.0.txt and SpecialCasing-9.0.0.txt files. Do not edit! */ + * from UnicodeData-13.0.0d6.txt and SpecialCasing-13.0.0d1.txt files. Do not edit! */ /* Contains start points of character case ranges (these are bidirectional conversions). */ static const uint16_t lit_character_case_ranges[] JERRY_ATTR_CONST_DATA = @@ -22,19 +22,20 @@ static const uint16_t lit_character_case_ranges[] JERRY_ATTR_CONST_DATA = 0x00c0, 0x00e0, 0x00d8, 0x00f8, 0x0189, 0x0256, 0x01b1, 0x028a, 0x0388, 0x03ad, 0x038e, 0x03cd, 0x0391, 0x03b1, 0x03a3, 0x03c3, 0x03fd, 0x037b, 0x0400, 0x0450, 0x0410, 0x0430, 0x0531, 0x0561, 0x10a0, 0x2d00, 0x13a0, 0xab70, 0x13f0, 0x13f8, - 0x1f08, 0x1f00, 0x1f18, 0x1f10, 0x1f28, 0x1f20, 0x1f38, 0x1f30, 0x1f48, 0x1f40, - 0x1f68, 0x1f60, 0x1fb8, 0x1fb0, 0x1fba, 0x1f70, 0x1fc8, 0x1f72, 0x1fd8, 0x1fd0, - 0x1fda, 0x1f76, 0x1fe8, 0x1fe0, 0x1fea, 0x1f7a, 0x1ff8, 0x1f78, 0x1ffa, 0x1f7c, - 0x2160, 0x2170, 0x24b6, 0x24d0, 0x2c00, 0x2c30, 0x2c7e, 0x023f, 0xff21, 0xff41 + 0x1c90, 0x10d0, 0x1cbd, 0x10fd, 0x1f08, 0x1f00, 0x1f18, 0x1f10, 0x1f28, 0x1f20, + 0x1f38, 0x1f30, 0x1f48, 0x1f40, 0x1f68, 0x1f60, 0x1fb8, 0x1fb0, 0x1fba, 0x1f70, + 0x1fc8, 0x1f72, 0x1fd8, 0x1fd0, 0x1fda, 0x1f76, 0x1fe8, 0x1fe0, 0x1fea, 0x1f7a, + 0x1ff8, 0x1f78, 0x1ffa, 0x1f7c, 0x2160, 0x2170, 0x24b6, 0x24d0, 0x2c00, 0x2c30, + 0x2c7e, 0x023f, 0xff21, 0xff41 }; /* Interval lengths of start points in `character_case_ranges` table. */ static const uint8_t lit_character_case_range_lengths[] JERRY_ATTR_CONST_DATA = { 0x0017, 0x0007, 0x0002, 0x0002, 0x0003, 0x0002, 0x0011, 0x0009, 0x0003, 0x0010, - 0x0020, 0x0026, 0x0026, 0x0050, 0x0006, 0x0008, 0x0006, 0x0008, 0x0008, 0x0006, - 0x0008, 0x0002, 0x0002, 0x0004, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, - 0x0010, 0x001a, 0x002f, 0x0002, 0x001a + 0x0020, 0x0026, 0x0026, 0x0050, 0x0006, 0x002b, 0x0003, 0x0008, 0x0006, 0x0008, + 0x0008, 0x0006, 0x0008, 0x0002, 0x0002, 0x0004, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0010, 0x001a, 0x002f, 0x0002, 0x001a }; /* Contains the start points of bidirectional conversion ranges. */ @@ -45,7 +46,7 @@ static const uint16_t lit_character_pair_ranges[] JERRY_ATTR_CONST_DATA = 0x01f8, 0x0222, 0x023b, 0x0241, 0x0246, 0x0370, 0x0376, 0x03d8, 0x03f7, 0x03fa, 0x0460, 0x048a, 0x04c1, 0x04d0, 0x1e00, 0x1ea0, 0x2183, 0x2c60, 0x2c67, 0x2c72, 0x2c75, 0x2c80, 0x2ceb, 0x2cf2, 0xa640, 0xa680, 0xa722, 0xa732, 0xa779, 0xa77e, - 0xa78b, 0xa790, 0xa796, 0xa7b4 + 0xa78b, 0xa790, 0xa796, 0xa7b4, 0xa7c2, 0xa7c7, 0xa7f5 }; /* Interval lengths of start points in `character_pair_ranges` table. */ @@ -56,7 +57,7 @@ static const uint8_t lit_character_pair_range_lengths[] JERRY_ATTR_CONST_DATA = 0x0028, 0x0012, 0x0002, 0x0002, 0x000a, 0x0004, 0x0002, 0x0018, 0x0002, 0x0002, 0x0022, 0x0036, 0x000e, 0x0060, 0x0096, 0x0060, 0x0002, 0x0002, 0x0006, 0x0002, 0x0002, 0x0064, 0x0004, 0x0002, 0x002e, 0x001c, 0x000e, 0x003e, 0x0004, 0x000a, - 0x0002, 0x0004, 0x0014, 0x0004 + 0x0002, 0x0004, 0x0014, 0x000c, 0x0002, 0x0004, 0x0002 }; /* Contains lower/upper case bidirectional conversion pairs. */ @@ -74,7 +75,7 @@ static const uint16_t lit_character_pairs[] JERRY_ATTR_CONST_DATA = 0x2c63, 0x1d7d, 0x2c64, 0x027d, 0x2c6d, 0x0251, 0x2c6e, 0x0271, 0x2c6f, 0x0250, 0x2c70, 0x0252, 0xa77d, 0x1d79, 0xa78d, 0x0265, 0xa7aa, 0x0266, 0xa7ab, 0x025c, 0xa7ac, 0x0261, 0xa7ad, 0x026c, 0xa7ae, 0x026a, 0xa7b0, 0x029e, 0xa7b1, 0x0287, - 0xa7b2, 0x029d, 0xa7b3, 0xab53 + 0xa7b2, 0x029d, 0xa7b3, 0xab53, 0xa7c4, 0xa794, 0xa7c5, 0x0282, 0xa7c6, 0x1d8e }; /* Contains start points of one-to-two uppercase ranges where the second character diff --git a/jerry-core/lit/lit-unicode-ranges.inc.h b/jerry-core/lit/lit-unicode-ranges.inc.h index 1749feaf..49d402a2 100644 --- a/jerry-core/lit/lit-unicode-ranges.inc.h +++ b/jerry-core/lit/lit-unicode-ranges.inc.h @@ -14,7 +14,7 @@ */ /* This file is automatically generated by the gen-unicode.py script - * from UnicodeData-9.0.0.txt. Do not edit! */ + * from UnicodeData-13.0.0d6.txt. Do not edit! */ /** * Character interval starting points for the unicode letters. @@ -25,23 +25,23 @@ static const uint16_t lit_unicode_letter_interval_sps[] JERRY_ATTR_CONST_DATA = { 0x00c0, 0x00d8, 0x00f8, 0x01f8, 0x02c6, 0x02e0, 0x0370, 0x0376, 0x037a, 0x0388, - 0x038e, 0x03a3, 0x03f7, 0x048a, 0x0531, 0x0561, 0x05d0, 0x05f0, 0x0620, 0x066e, + 0x038e, 0x03a3, 0x03f7, 0x048a, 0x0531, 0x0560, 0x05d0, 0x05ef, 0x0620, 0x066e, 0x0671, 0x06e5, 0x06ee, 0x06fa, 0x0712, 0x074d, 0x07ca, 0x07f4, 0x0800, 0x0840, - 0x08a0, 0x08b6, 0x0904, 0x0958, 0x0971, 0x0985, 0x098f, 0x0993, 0x09aa, 0x09b6, - 0x09dc, 0x09df, 0x09f0, 0x0a05, 0x0a0f, 0x0a13, 0x0a2a, 0x0a32, 0x0a35, 0x0a38, - 0x0a59, 0x0a72, 0x0a85, 0x0a8f, 0x0a93, 0x0aaa, 0x0ab2, 0x0ab5, 0x0ae0, 0x0b05, - 0x0b0f, 0x0b13, 0x0b2a, 0x0b32, 0x0b35, 0x0b5c, 0x0b5f, 0x0b85, 0x0b8e, 0x0b92, - 0x0b99, 0x0b9e, 0x0ba3, 0x0ba8, 0x0bae, 0x0c05, 0x0c0e, 0x0c12, 0x0c2a, 0x0c58, - 0x0c60, 0x0c85, 0x0c8e, 0x0c92, 0x0caa, 0x0cb5, 0x0ce0, 0x0cf1, 0x0d05, 0x0d0e, - 0x0d12, 0x0d54, 0x0d5f, 0x0d7a, 0x0d85, 0x0d9a, 0x0db3, 0x0dc0, 0x0e01, 0x0e32, - 0x0e40, 0x0e81, 0x0e87, 0x0e94, 0x0e99, 0x0ea1, 0x0eaa, 0x0ead, 0x0eb2, 0x0ec0, - 0x0edc, 0x0f40, 0x0f49, 0x0f88, 0x1000, 0x1050, 0x105a, 0x1065, 0x106e, 0x1075, - 0x10a0, 0x10d0, 0x10fc, 0x11fc, 0x124a, 0x1250, 0x125a, 0x1260, 0x128a, 0x1290, - 0x12b2, 0x12b8, 0x12c2, 0x12c8, 0x12d8, 0x1312, 0x1318, 0x1380, 0x13a0, 0x13f8, - 0x1401, 0x1501, 0x1601, 0x166f, 0x1681, 0x16a0, 0x16ee, 0x1700, 0x170e, 0x1720, - 0x1740, 0x1760, 0x176e, 0x1780, 0x1820, 0x1880, 0x1887, 0x18b0, 0x1900, 0x1950, - 0x1970, 0x1980, 0x19b0, 0x1a00, 0x1a20, 0x1b05, 0x1b45, 0x1b83, 0x1bae, 0x1bba, - 0x1c00, 0x1c4d, 0x1c5a, 0x1c80, 0x1ce9, 0x1cee, 0x1cf5, 0x1d00, 0x1e00, 0x1f00, + 0x0860, 0x08a0, 0x08b6, 0x0904, 0x0958, 0x0971, 0x0985, 0x098f, 0x0993, 0x09aa, + 0x09b6, 0x09dc, 0x09df, 0x09f0, 0x0a05, 0x0a0f, 0x0a13, 0x0a2a, 0x0a32, 0x0a35, + 0x0a38, 0x0a59, 0x0a72, 0x0a85, 0x0a8f, 0x0a93, 0x0aaa, 0x0ab2, 0x0ab5, 0x0ae0, + 0x0b05, 0x0b0f, 0x0b13, 0x0b2a, 0x0b32, 0x0b35, 0x0b5c, 0x0b5f, 0x0b85, 0x0b8e, + 0x0b92, 0x0b99, 0x0b9e, 0x0ba3, 0x0ba8, 0x0bae, 0x0c05, 0x0c0e, 0x0c12, 0x0c2a, + 0x0c58, 0x0c60, 0x0c85, 0x0c8e, 0x0c92, 0x0caa, 0x0cb5, 0x0ce0, 0x0cf1, 0x0d04, + 0x0d0e, 0x0d12, 0x0d54, 0x0d5f, 0x0d7a, 0x0d85, 0x0d9a, 0x0db3, 0x0dc0, 0x0e01, + 0x0e32, 0x0e40, 0x0e81, 0x0e86, 0x0e8c, 0x0ea7, 0x0eb2, 0x0ec0, 0x0edc, 0x0f40, + 0x0f49, 0x0f88, 0x1000, 0x1050, 0x105a, 0x1065, 0x106e, 0x1075, 0x10a0, 0x10d0, + 0x10fc, 0x11fc, 0x124a, 0x1250, 0x125a, 0x1260, 0x128a, 0x1290, 0x12b2, 0x12b8, + 0x12c2, 0x12c8, 0x12d8, 0x1312, 0x1318, 0x1380, 0x13a0, 0x13f8, 0x1401, 0x1501, + 0x1601, 0x166f, 0x1681, 0x16a0, 0x16ee, 0x1700, 0x170e, 0x1720, 0x1740, 0x1760, + 0x176e, 0x1780, 0x1820, 0x1880, 0x1887, 0x18b0, 0x1900, 0x1950, 0x1970, 0x1980, + 0x19b0, 0x1a00, 0x1a20, 0x1b05, 0x1b45, 0x1b83, 0x1bae, 0x1bba, 0x1c00, 0x1c4d, + 0x1c5a, 0x1c80, 0x1c90, 0x1cbd, 0x1ce9, 0x1cee, 0x1cf5, 0x1d00, 0x1e00, 0x1f00, 0x1f18, 0x1f20, 0x1f48, 0x1f50, 0x1f5f, 0x1f80, 0x1fb6, 0x1fc2, 0x1fc6, 0x1fd0, 0x1fd6, 0x1fe0, 0x1ff2, 0x1ff6, 0x2090, 0x210a, 0x2119, 0x212a, 0x212f, 0x213c, 0x2145, 0x2160, 0x2c00, 0x2c30, 0x2c60, 0x2ceb, 0x2cf2, 0x2d00, 0x2d30, 0x2d80, @@ -59,17 +59,17 @@ static const uint16_t lit_unicode_letter_interval_sps[] JERRY_ATTR_CONST_DATA = 0x8e00, 0x8f00, 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, 0x9800, 0x9900, 0x9a00, 0x9b00, 0x9c00, 0x9d00, 0x9e00, 0x9f00, 0xa000, 0xa100, 0xa200, 0xa300, 0xa400, 0xa4d0, 0xa500, 0xa600, 0xa610, 0xa62a, 0xa640, 0xa67f, - 0xa6a0, 0xa717, 0xa722, 0xa78b, 0xa7b0, 0xa7f7, 0xa803, 0xa807, 0xa80c, 0xa840, - 0xa882, 0xa8f2, 0xa90a, 0xa930, 0xa960, 0xa984, 0xa9e0, 0xa9e6, 0xa9fa, 0xaa00, - 0xaa40, 0xaa44, 0xaa60, 0xaa7e, 0xaab5, 0xaab9, 0xaadb, 0xaae0, 0xaaf2, 0xab01, - 0xab09, 0xab11, 0xab20, 0xab28, 0xab30, 0xab5c, 0xab70, 0xac00, 0xad00, 0xae00, - 0xaf00, 0xb000, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700, 0xb800, - 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00, 0xc000, 0xc100, 0xc200, - 0xc300, 0xc400, 0xc500, 0xc600, 0xc700, 0xc800, 0xc900, 0xca00, 0xcb00, 0xcc00, - 0xcd00, 0xce00, 0xcf00, 0xd000, 0xd100, 0xd200, 0xd300, 0xd400, 0xd500, 0xd600, - 0xd700, 0xd7b0, 0xd7cb, 0xf900, 0xfa00, 0xfa70, 0xfb00, 0xfb13, 0xfb1f, 0xfb2a, - 0xfb38, 0xfb40, 0xfb43, 0xfb46, 0xfbd3, 0xfcd3, 0xfd50, 0xfd92, 0xfdf0, 0xfe70, - 0xfe76, 0xff21, 0xff41, 0xff66, 0xffc2, 0xffca, 0xffd2, 0xffda + 0xa6a0, 0xa717, 0xa722, 0xa78b, 0xa7c2, 0xa7f5, 0xa803, 0xa807, 0xa80c, 0xa840, + 0xa882, 0xa8f2, 0xa8fd, 0xa90a, 0xa930, 0xa960, 0xa984, 0xa9e0, 0xa9e6, 0xa9fa, + 0xaa00, 0xaa40, 0xaa44, 0xaa60, 0xaa7e, 0xaab5, 0xaab9, 0xaadb, 0xaae0, 0xaaf2, + 0xab01, 0xab09, 0xab11, 0xab20, 0xab28, 0xab30, 0xab5c, 0xab70, 0xac00, 0xad00, + 0xae00, 0xaf00, 0xb000, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700, + 0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00, 0xc000, 0xc100, + 0xc200, 0xc300, 0xc400, 0xc500, 0xc600, 0xc700, 0xc800, 0xc900, 0xca00, 0xcb00, + 0xcc00, 0xcd00, 0xce00, 0xcf00, 0xd000, 0xd100, 0xd200, 0xd300, 0xd400, 0xd500, + 0xd600, 0xd700, 0xd7b0, 0xd7cb, 0xf900, 0xfa00, 0xfa70, 0xfb00, 0xfb13, 0xfb1f, + 0xfb2a, 0xfb38, 0xfb40, 0xfb43, 0xfb46, 0xfbd3, 0xfcd3, 0xfd50, 0xfd92, 0xfdf0, + 0xfe70, 0xfe76, 0xff21, 0xff41, 0xff66, 0xffc2, 0xffca, 0xffd2, 0xffda }; /** @@ -81,31 +81,31 @@ static const uint16_t lit_unicode_letter_interval_sps[] JERRY_ATTR_CONST_DATA = static const uint8_t lit_unicode_letter_interval_lengths[] JERRY_ATTR_CONST_DATA = { 0x0016, 0x001e, 0x00ff, 0x00c9, 0x000b, 0x0004, 0x0004, 0x0001, 0x0003, 0x0002, - 0x0013, 0x0052, 0x008a, 0x00a5, 0x0025, 0x0026, 0x001a, 0x0002, 0x002a, 0x0001, + 0x0013, 0x0052, 0x008a, 0x00a5, 0x0025, 0x0028, 0x001a, 0x0003, 0x002a, 0x0001, 0x0062, 0x0001, 0x0001, 0x0002, 0x001d, 0x0058, 0x0020, 0x0001, 0x0015, 0x0018, - 0x0014, 0x0007, 0x0035, 0x0009, 0x000f, 0x0007, 0x0001, 0x0015, 0x0006, 0x0003, - 0x0001, 0x0002, 0x0001, 0x0005, 0x0001, 0x0015, 0x0006, 0x0001, 0x0001, 0x0001, - 0x0003, 0x0002, 0x0008, 0x0002, 0x0015, 0x0006, 0x0001, 0x0004, 0x0001, 0x0007, - 0x0001, 0x0015, 0x0006, 0x0001, 0x0004, 0x0001, 0x0002, 0x0005, 0x0002, 0x0003, - 0x0001, 0x0001, 0x0001, 0x0002, 0x000b, 0x0007, 0x0002, 0x0016, 0x000f, 0x0002, - 0x0001, 0x0007, 0x0002, 0x0016, 0x0009, 0x0004, 0x0001, 0x0001, 0x0007, 0x0002, - 0x0028, 0x0002, 0x0002, 0x0005, 0x0011, 0x0017, 0x0008, 0x0006, 0x002f, 0x0001, - 0x0006, 0x0001, 0x0001, 0x0003, 0x0006, 0x0002, 0x0001, 0x0003, 0x0001, 0x0004, - 0x0003, 0x0007, 0x0023, 0x0004, 0x002a, 0x0005, 0x0003, 0x0001, 0x0002, 0x000c, - 0x0025, 0x002a, 0x00ff, 0x004c, 0x0003, 0x0006, 0x0003, 0x0028, 0x0003, 0x0020, - 0x0003, 0x0006, 0x0003, 0x000e, 0x0038, 0x0003, 0x0042, 0x000f, 0x0055, 0x0005, - 0x00ff, 0x00ff, 0x006b, 0x0010, 0x0019, 0x004a, 0x000a, 0x000c, 0x0003, 0x0011, - 0x0011, 0x000c, 0x0002, 0x0033, 0x0057, 0x0004, 0x0021, 0x0045, 0x001e, 0x001d, - 0x0004, 0x002b, 0x0019, 0x0016, 0x0034, 0x002e, 0x0006, 0x001d, 0x0001, 0x002b, - 0x0023, 0x0002, 0x0023, 0x0008, 0x0003, 0x0003, 0x0001, 0x00bf, 0x00ff, 0x0015, + 0x000a, 0x0014, 0x0011, 0x0035, 0x0009, 0x000f, 0x0007, 0x0001, 0x0015, 0x0006, + 0x0003, 0x0001, 0x0002, 0x0001, 0x0005, 0x0001, 0x0015, 0x0006, 0x0001, 0x0001, + 0x0001, 0x0003, 0x0002, 0x0008, 0x0002, 0x0015, 0x0006, 0x0001, 0x0004, 0x0001, + 0x0007, 0x0001, 0x0015, 0x0006, 0x0001, 0x0004, 0x0001, 0x0002, 0x0005, 0x0002, + 0x0003, 0x0001, 0x0001, 0x0001, 0x0002, 0x000b, 0x0007, 0x0002, 0x0016, 0x000f, + 0x0002, 0x0001, 0x0007, 0x0002, 0x0016, 0x0009, 0x0004, 0x0001, 0x0001, 0x0008, + 0x0002, 0x0028, 0x0002, 0x0002, 0x0005, 0x0011, 0x0017, 0x0008, 0x0006, 0x002f, + 0x0001, 0x0006, 0x0001, 0x0004, 0x0017, 0x0009, 0x0001, 0x0004, 0x0003, 0x0007, + 0x0023, 0x0004, 0x002a, 0x0005, 0x0003, 0x0001, 0x0002, 0x000c, 0x0025, 0x002a, + 0x00ff, 0x004c, 0x0003, 0x0006, 0x0003, 0x0028, 0x0003, 0x0020, 0x0003, 0x0006, + 0x0003, 0x000e, 0x0038, 0x0003, 0x0042, 0x000f, 0x0055, 0x0005, 0x00ff, 0x00ff, + 0x006b, 0x0010, 0x0019, 0x004a, 0x000a, 0x000c, 0x0003, 0x0011, 0x0011, 0x000c, + 0x0002, 0x0033, 0x0058, 0x0004, 0x0021, 0x0045, 0x001e, 0x001d, 0x0004, 0x002b, + 0x0019, 0x0016, 0x0034, 0x002e, 0x0006, 0x001d, 0x0001, 0x002b, 0x0023, 0x0002, + 0x0023, 0x0008, 0x002a, 0x0002, 0x0003, 0x0005, 0x0001, 0x00bf, 0x00ff, 0x0015, 0x0005, 0x0025, 0x0005, 0x0007, 0x001e, 0x0034, 0x0006, 0x0002, 0x0006, 0x0003, 0x0005, 0x000c, 0x0002, 0x0006, 0x000c, 0x0009, 0x0004, 0x0003, 0x000a, 0x0003, 0x0004, 0x0028, 0x002e, 0x002e, 0x0084, 0x0003, 0x0001, 0x0025, 0x0037, 0x0016, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0002, 0x0008, - 0x0004, 0x0004, 0x0055, 0x0002, 0x0059, 0x0003, 0x0028, 0x005d, 0x001a, 0x000f, + 0x0004, 0x0004, 0x0055, 0x0002, 0x0059, 0x0003, 0x002a, 0x005d, 0x001f, 0x000f, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, - 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00b5, 0x00ff, 0x00ff, 0x00ff, 0x00ff, + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00bf, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, @@ -113,19 +113,19 @@ static const uint8_t lit_unicode_letter_interval_lengths[] JERRY_ATTR_CONST_DATA 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, - 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00d5, 0x00ff, 0x00ff, + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00fc, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x008c, 0x002d, 0x00ff, 0x000c, 0x000f, 0x0001, 0x002e, 0x001e, - 0x004f, 0x0008, 0x0066, 0x0023, 0x0007, 0x000a, 0x0002, 0x0003, 0x0016, 0x0033, - 0x0031, 0x0005, 0x001b, 0x0016, 0x001c, 0x002e, 0x0004, 0x0009, 0x0004, 0x0028, - 0x0002, 0x0007, 0x0016, 0x0031, 0x0001, 0x0004, 0x0002, 0x000a, 0x0002, 0x0005, - 0x0005, 0x0005, 0x0006, 0x0006, 0x002a, 0x0009, 0x0072, 0x00ff, 0x00ff, 0x00ff, + 0x004f, 0x0008, 0x0066, 0x0034, 0x0008, 0x000c, 0x0002, 0x0003, 0x0016, 0x0033, + 0x0031, 0x0005, 0x0001, 0x001b, 0x0016, 0x001c, 0x002e, 0x0004, 0x0009, 0x0004, + 0x0028, 0x0002, 0x0007, 0x0016, 0x0031, 0x0001, 0x0004, 0x0002, 0x000a, 0x0002, + 0x0005, 0x0005, 0x0005, 0x0006, 0x0006, 0x002a, 0x000d, 0x0072, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, - 0x00a3, 0x0016, 0x0030, 0x00ff, 0x006d, 0x0069, 0x0006, 0x0004, 0x0009, 0x000c, - 0x0004, 0x0001, 0x0001, 0x006b, 0x00ff, 0x006a, 0x003f, 0x0035, 0x000b, 0x0004, - 0x0086, 0x0019, 0x0019, 0x0058, 0x0005, 0x0005, 0x0005, 0x0002 + 0x00ff, 0x00a3, 0x0016, 0x0030, 0x00ff, 0x006d, 0x0069, 0x0006, 0x0004, 0x0009, + 0x000c, 0x0004, 0x0001, 0x0001, 0x006b, 0x00ff, 0x006a, 0x003f, 0x0035, 0x000b, + 0x0004, 0x0086, 0x0019, 0x0019, 0x0058, 0x0005, 0x0005, 0x0005, 0x0002 }; /** @@ -139,13 +139,13 @@ static const uint16_t lit_unicode_letter_chars[] JERRY_ATTR_CONST_DATA = { 0x00aa, 0x00b5, 0x00ba, 0x02ec, 0x02ee, 0x037f, 0x0386, 0x038c, 0x0559, 0x06d5, 0x06ff, 0x0710, 0x07b1, 0x07fa, 0x081a, 0x0824, 0x0828, 0x093d, 0x0950, 0x09b2, - 0x09bd, 0x09ce, 0x0a5e, 0x0abd, 0x0ad0, 0x0af9, 0x0b3d, 0x0b71, 0x0b83, 0x0b9c, - 0x0bd0, 0x0c3d, 0x0c80, 0x0cbd, 0x0cde, 0x0d3d, 0x0d4e, 0x0dbd, 0x0e84, 0x0e8a, - 0x0e8d, 0x0ea5, 0x0ea7, 0x0ebd, 0x0ec6, 0x0f00, 0x103f, 0x1061, 0x108e, 0x10c7, - 0x10cd, 0x1258, 0x12c0, 0x17d7, 0x17dc, 0x18aa, 0x1aa7, 0x1f59, 0x1f5b, 0x1f5d, - 0x1fbe, 0x2071, 0x207f, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x214e, - 0x2d27, 0x2d2d, 0x2d6f, 0x2e2f, 0x3400, 0x4e00, 0xa8fb, 0xa8fd, 0xa9cf, 0xaa7a, - 0xaab1, 0xaac0, 0xaac2, 0xac00, 0xfb1d, 0xfb3e + 0x09bd, 0x09ce, 0x09fc, 0x0a5e, 0x0abd, 0x0ad0, 0x0af9, 0x0b3d, 0x0b71, 0x0b83, + 0x0b9c, 0x0bd0, 0x0c3d, 0x0c80, 0x0cbd, 0x0cde, 0x0d3d, 0x0d4e, 0x0dbd, 0x0e84, + 0x0ea5, 0x0ebd, 0x0ec6, 0x0f00, 0x103f, 0x1061, 0x108e, 0x10c7, 0x10cd, 0x1258, + 0x12c0, 0x17d7, 0x17dc, 0x18aa, 0x1aa7, 0x1cfa, 0x1f59, 0x1f5b, 0x1f5d, 0x1fbe, + 0x2071, 0x207f, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x214e, 0x2d27, + 0x2d2d, 0x2d6f, 0x2e2f, 0x3400, 0x4e00, 0xa8fb, 0xa9cf, 0xaa7a, 0xaab1, 0xaac0, + 0xaac2, 0xac00, 0xfb1d, 0xfb3e }; /** @@ -159,23 +159,23 @@ static const uint16_t lit_unicode_non_letter_ident_part_interval_sps[] JERRY_ATT { 0x0300, 0x0483, 0x0591, 0x05c1, 0x05c4, 0x0610, 0x064b, 0x06d6, 0x06df, 0x06e7, 0x06ea, 0x06f0, 0x0730, 0x07a6, 0x07c0, 0x07eb, 0x0816, 0x081b, 0x0825, 0x0829, - 0x0859, 0x08d4, 0x08e3, 0x093a, 0x093e, 0x0951, 0x0962, 0x0966, 0x0981, 0x09be, + 0x0859, 0x08d3, 0x08e3, 0x093a, 0x093e, 0x0951, 0x0962, 0x0966, 0x0981, 0x09be, 0x09c7, 0x09cb, 0x09e2, 0x09e6, 0x0a01, 0x0a3e, 0x0a47, 0x0a4b, 0x0a66, 0x0a81, - 0x0abe, 0x0ac7, 0x0acb, 0x0ae2, 0x0ae6, 0x0b01, 0x0b3e, 0x0b47, 0x0b4b, 0x0b56, - 0x0b62, 0x0b66, 0x0bbe, 0x0bc6, 0x0bca, 0x0be6, 0x0c00, 0x0c3e, 0x0c46, 0x0c4a, - 0x0c55, 0x0c62, 0x0c66, 0x0c81, 0x0cbe, 0x0cc6, 0x0cca, 0x0cd5, 0x0ce2, 0x0ce6, - 0x0d01, 0x0d3e, 0x0d46, 0x0d4a, 0x0d62, 0x0d66, 0x0d82, 0x0dcf, 0x0dd8, 0x0de6, - 0x0df2, 0x0e34, 0x0e47, 0x0e50, 0x0eb4, 0x0ebb, 0x0ec8, 0x0ed0, 0x0f18, 0x0f20, - 0x0f3e, 0x0f71, 0x0f86, 0x0f8d, 0x0f99, 0x102b, 0x1040, 0x1056, 0x105e, 0x1062, - 0x1067, 0x1071, 0x1082, 0x108f, 0x135d, 0x1712, 0x1732, 0x1752, 0x1772, 0x17b4, - 0x17e0, 0x180b, 0x1810, 0x1885, 0x1920, 0x1930, 0x1946, 0x19d0, 0x1a17, 0x1a55, - 0x1a60, 0x1a7f, 0x1a90, 0x1ab0, 0x1b00, 0x1b34, 0x1b50, 0x1b6b, 0x1b80, 0x1ba1, - 0x1bb0, 0x1be6, 0x1c24, 0x1c40, 0x1c50, 0x1cd0, 0x1cd4, 0x1cf2, 0x1cf8, 0x1dc0, - 0x1dfb, 0x203f, 0x20d0, 0x20e5, 0x2cef, 0x2de0, 0x302a, 0x3099, 0xa620, 0xa674, - 0xa69e, 0xa6f0, 0xa823, 0xa880, 0xa8b4, 0xa8d0, 0xa8e0, 0xa900, 0xa926, 0xa947, - 0xa980, 0xa9b3, 0xa9d0, 0xa9f0, 0xaa29, 0xaa4c, 0xaa50, 0xaa7b, 0xaab2, 0xaab7, - 0xaabe, 0xaaeb, 0xaaf5, 0xabe3, 0xabec, 0xabf0, 0xfe00, 0xfe20, 0xfe33, 0xfe4d, - 0xff10 + 0x0abe, 0x0ac7, 0x0acb, 0x0ae2, 0x0ae6, 0x0afa, 0x0b01, 0x0b3e, 0x0b47, 0x0b4b, + 0x0b55, 0x0b62, 0x0b66, 0x0bbe, 0x0bc6, 0x0bca, 0x0be6, 0x0c00, 0x0c3e, 0x0c46, + 0x0c4a, 0x0c55, 0x0c62, 0x0c66, 0x0c81, 0x0cbe, 0x0cc6, 0x0cca, 0x0cd5, 0x0ce2, + 0x0ce6, 0x0d00, 0x0d3b, 0x0d3e, 0x0d46, 0x0d4a, 0x0d62, 0x0d66, 0x0d81, 0x0dcf, + 0x0dd8, 0x0de6, 0x0df2, 0x0e34, 0x0e47, 0x0e50, 0x0eb4, 0x0ec8, 0x0ed0, 0x0f18, + 0x0f20, 0x0f3e, 0x0f71, 0x0f86, 0x0f8d, 0x0f99, 0x102b, 0x1040, 0x1056, 0x105e, + 0x1062, 0x1067, 0x1071, 0x1082, 0x108f, 0x135d, 0x1712, 0x1732, 0x1752, 0x1772, + 0x17b4, 0x17e0, 0x180b, 0x1810, 0x1885, 0x1920, 0x1930, 0x1946, 0x19d0, 0x1a17, + 0x1a55, 0x1a60, 0x1a7f, 0x1a90, 0x1ab0, 0x1abf, 0x1b00, 0x1b34, 0x1b50, 0x1b6b, + 0x1b80, 0x1ba1, 0x1bb0, 0x1be6, 0x1c24, 0x1c40, 0x1c50, 0x1cd0, 0x1cd4, 0x1cf7, + 0x1dc0, 0x1dfb, 0x200c, 0x203f, 0x20d0, 0x20e5, 0x2cef, 0x2de0, 0x302a, 0x3099, + 0xa620, 0xa674, 0xa69e, 0xa6f0, 0xa823, 0xa880, 0xa8b4, 0xa8d0, 0xa8e0, 0xa8ff, + 0xa926, 0xa947, 0xa980, 0xa9b3, 0xa9d0, 0xa9f0, 0xaa29, 0xaa4c, 0xaa50, 0xaa7b, + 0xaab2, 0xaab7, 0xaabe, 0xaaeb, 0xaaf5, 0xabe3, 0xabec, 0xabf0, 0xfe00, 0xfe20, + 0xfe33, 0xfe4d, 0xff10 }; /** @@ -189,23 +189,23 @@ static const uint8_t lit_unicode_non_letter_ident_part_interval_lengths[] JERRY_ { 0x006f, 0x0004, 0x002c, 0x0001, 0x0001, 0x000a, 0x001e, 0x0006, 0x0005, 0x0001, 0x0003, 0x0009, 0x001a, 0x000a, 0x0009, 0x0008, 0x0003, 0x0008, 0x0002, 0x0004, - 0x0002, 0x000d, 0x0020, 0x0002, 0x0011, 0x0006, 0x0001, 0x0009, 0x0002, 0x0006, + 0x0002, 0x000e, 0x0020, 0x0002, 0x0011, 0x0006, 0x0001, 0x0009, 0x0002, 0x0006, 0x0001, 0x0002, 0x0001, 0x0009, 0x0002, 0x0004, 0x0001, 0x0002, 0x000b, 0x0002, - 0x0007, 0x0002, 0x0002, 0x0001, 0x0009, 0x0002, 0x0006, 0x0001, 0x0002, 0x0001, - 0x0001, 0x0009, 0x0004, 0x0002, 0x0003, 0x0009, 0x0003, 0x0006, 0x0002, 0x0003, - 0x0001, 0x0001, 0x0009, 0x0002, 0x0006, 0x0002, 0x0003, 0x0001, 0x0001, 0x0009, - 0x0002, 0x0006, 0x0002, 0x0003, 0x0001, 0x0009, 0x0001, 0x0005, 0x0007, 0x0009, - 0x0001, 0x0006, 0x0007, 0x0009, 0x0005, 0x0001, 0x0005, 0x0009, 0x0001, 0x0009, - 0x0001, 0x0013, 0x0001, 0x000a, 0x0023, 0x0013, 0x0009, 0x0003, 0x0002, 0x0002, - 0x0006, 0x0003, 0x000b, 0x000e, 0x0002, 0x0002, 0x0002, 0x0001, 0x0001, 0x001f, - 0x0009, 0x0002, 0x0009, 0x0001, 0x000b, 0x000b, 0x0009, 0x0009, 0x0004, 0x0009, - 0x001c, 0x000a, 0x0009, 0x000d, 0x0004, 0x0010, 0x0009, 0x0008, 0x0002, 0x000c, - 0x0009, 0x000d, 0x0013, 0x0009, 0x0009, 0x0002, 0x0014, 0x0002, 0x0001, 0x0035, - 0x0004, 0x0001, 0x000c, 0x000b, 0x0002, 0x001f, 0x0005, 0x0001, 0x0009, 0x0009, - 0x0001, 0x0001, 0x0004, 0x0001, 0x0011, 0x0009, 0x0011, 0x0009, 0x0007, 0x000c, - 0x0003, 0x000d, 0x0009, 0x0009, 0x000d, 0x0001, 0x0009, 0x0002, 0x0002, 0x0001, - 0x0001, 0x0004, 0x0001, 0x0007, 0x0001, 0x0009, 0x000f, 0x000f, 0x0001, 0x0002, - 0x0009 + 0x0007, 0x0002, 0x0002, 0x0001, 0x0009, 0x0005, 0x0002, 0x0006, 0x0001, 0x0002, + 0x0002, 0x0001, 0x0009, 0x0004, 0x0002, 0x0003, 0x0009, 0x0004, 0x0006, 0x0002, + 0x0003, 0x0001, 0x0001, 0x0009, 0x0002, 0x0006, 0x0002, 0x0003, 0x0001, 0x0001, + 0x0009, 0x0003, 0x0001, 0x0006, 0x0002, 0x0003, 0x0001, 0x0009, 0x0002, 0x0005, + 0x0007, 0x0009, 0x0001, 0x0006, 0x0007, 0x0009, 0x0008, 0x0005, 0x0009, 0x0001, + 0x0009, 0x0001, 0x0013, 0x0001, 0x000a, 0x0023, 0x0013, 0x0009, 0x0003, 0x0002, + 0x0002, 0x0006, 0x0003, 0x000b, 0x000e, 0x0002, 0x0002, 0x0002, 0x0001, 0x0001, + 0x001f, 0x0009, 0x0002, 0x0009, 0x0001, 0x000b, 0x000b, 0x0009, 0x0009, 0x0004, + 0x0009, 0x001c, 0x000a, 0x0009, 0x000d, 0x0001, 0x0004, 0x0010, 0x0009, 0x0008, + 0x0002, 0x000c, 0x0009, 0x000d, 0x0013, 0x0009, 0x0009, 0x0002, 0x0014, 0x0002, + 0x0039, 0x0004, 0x0001, 0x0001, 0x000c, 0x000b, 0x0002, 0x001f, 0x0005, 0x0001, + 0x0009, 0x0009, 0x0001, 0x0001, 0x0004, 0x0001, 0x0011, 0x0009, 0x0011, 0x000a, + 0x0007, 0x000c, 0x0003, 0x000d, 0x0009, 0x0009, 0x000d, 0x0001, 0x0009, 0x0002, + 0x0002, 0x0001, 0x0001, 0x0004, 0x0001, 0x0007, 0x0001, 0x0009, 0x000f, 0x000f, + 0x0001, 0x0002, 0x0009 }; /** @@ -218,10 +218,11 @@ static const uint8_t lit_unicode_non_letter_ident_part_interval_lengths[] JERRY_ */ static const uint16_t lit_unicode_non_letter_ident_part_chars[] JERRY_ATTR_CONST_DATA = { - 0x05bf, 0x05c7, 0x0670, 0x0711, 0x09bc, 0x09d7, 0x0a3c, 0x0a51, 0x0a75, 0x0abc, - 0x0b3c, 0x0b82, 0x0bd7, 0x0cbc, 0x0d57, 0x0dca, 0x0dd6, 0x0e31, 0x0eb1, 0x0f35, - 0x0f37, 0x0f39, 0x0fc6, 0x17dd, 0x18a9, 0x1ced, 0x2054, 0x20e1, 0x2d7f, 0xa66f, - 0xa802, 0xa806, 0xa80b, 0xa9e5, 0xaa43, 0xaab0, 0xaac1, 0xfb1e, 0xff3f + 0x05bf, 0x05c7, 0x0670, 0x0711, 0x07fd, 0x09bc, 0x09d7, 0x09fe, 0x0a3c, 0x0a51, + 0x0a75, 0x0abc, 0x0b3c, 0x0b82, 0x0bd7, 0x0cbc, 0x0d57, 0x0dca, 0x0dd6, 0x0e31, + 0x0eb1, 0x0f35, 0x0f37, 0x0f39, 0x0fc6, 0x17dd, 0x18a9, 0x1ced, 0x1cf4, 0x2054, + 0x20e1, 0x2d7f, 0xa66f, 0xa802, 0xa806, 0xa80b, 0xa82c, 0xa9e5, 0xaa43, 0xaab0, + 0xaac1, 0xfb1e, 0xff3f }; /** diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 57a626a0..7354c07d 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -64,19 +64,19 @@ #define CBC_HAS_POP_STACK_BYTE_ARG (CBC_HAS_BYTE_ARG | CBC_POP_STACK_BYTE_ARG) -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) /** - * Checks whether the current opcode is a super constructor call + * CBC_NO_RESULT_OPERATION for ext opcodes */ -#define CBC_SUPER_CALL_OPERATION(opcode) \ +#define CBC_EXT_NO_RESULT_OPERATION(opcode) \ ((opcode) >= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL) \ - && (opcode) <= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL_BLOCK)) -#else /* !ENABLED (JERRY_ES2015_CLASS) */ + && (opcode) <= PARSER_TO_EXT_OPCODE (CBC_EXT_SPREAD_CALL_PROP_BLOCK)) +#else /* !ENABLED (JERRY_ES2015) */ /** - * Checks whether the current opcode is a super constructor call + * CBC_NO_RESULT_OPERATION for ext opcodes */ -#define CBC_SUPER_CALL_OPERATION(opcode) false -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#define CBC_EXT_NO_RESULT_OPERATION(opcode) false +#endif /* ENABLED (JERRY_ES2015) */ /* Debug macro. */ #define CBC_ARGS_EQ(op, types) \ @@ -84,9 +84,9 @@ /* Debug macro. */ #define CBC_SAME_ARGS(op1, op2) \ - (CBC_SUPER_CALL_OPERATION (op1) ? ((cbc_ext_flags[PARSER_GET_EXT_OPCODE (op1)] & CBC_ARG_TYPES) \ - == (cbc_ext_flags[PARSER_GET_EXT_OPCODE (op2)] & CBC_ARG_TYPES)) \ - : ((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))) + (CBC_EXT_NO_RESULT_OPERATION (op1) ? ((cbc_ext_flags[PARSER_GET_EXT_OPCODE (op1)] & CBC_ARG_TYPES) \ + == (cbc_ext_flags[PARSER_GET_EXT_OPCODE (op2)] & CBC_ARG_TYPES)) \ + : ((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))) #define CBC_UNARY_OPERATION(name, group) \ CBC_OPCODE (name, CBC_NO_FLAG, 0, \ @@ -140,7 +140,7 @@ * cannot be true for an opcode which has a result */ #define CBC_NO_RESULT_OPERATION(opcode) \ - (((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END) || CBC_SUPER_CALL_OPERATION ((opcode))) + (((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END) || CBC_EXT_NO_RESULT_OPERATION ((opcode))) /** * Branch instructions are organized in group of 8 opcodes. @@ -188,16 +188,16 @@ /* Stack consumption of opcodes with context. */ -/* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 3 */ -#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3 -/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4 -/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1 -/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1 /* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */ #define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2 +/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */ +#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4 +/* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 3 */ +#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3 +/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */ +#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1 +/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */ +#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1 /** * Opcode definitions. @@ -244,6 +244,10 @@ VM_OC_PUSH_ELISON | VM_OC_PUT_STACK) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_STRICT_EQUAL, -1, \ VM_OC_BRANCH_IF_STRICT_EQUAL) \ + CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \ + CBC_FORWARD_BRANCH (CBC_BLOCK_CREATE_CONTEXT, \ + PARSER_BLOCK_CONTEXT_STACK_ALLOCATION, VM_OC_BLOCK_CREATE_CONTEXT) \ \ /* Basic opcodes. Note: These 4 opcodes must me in this order */ \ CBC_OPCODE (CBC_PUSH_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ @@ -260,8 +264,6 @@ VM_OC_PUSH_TRUE | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_PUSH_FALSE, CBC_NO_FLAG, 1, \ VM_OC_PUSH_FALSE | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_PUSH_THIS, CBC_NO_FLAG, 1, \ VM_OC_PUSH_THIS | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \ @@ -298,22 +300,44 @@ VM_OC_NEW | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \ VM_OC_EVAL) \ - CBC_OPCODE (CBC_DEFINE_VARS, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_NONE) \ - CBC_OPCODE (CBC_INITIALIZE_VAR, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ - VM_OC_NONE) \ - CBC_OPCODE (CBC_INITIALIZE_VARS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ - VM_OC_NONE) \ + CBC_OPCODE (CBC_CHECK_VAR, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CHECK_VAR) \ + CBC_OPCODE (CBC_CHECK_LET, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CHECK_LET) \ + CBC_OPCODE (CBC_CREATE_VAR, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CREATE_BINDING) \ + CBC_OPCODE (CBC_CREATE_LET, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CREATE_BINDING) \ + CBC_OPCODE (CBC_CREATE_CONST, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CREATE_BINDING) \ + CBC_OPCODE (CBC_CREATE_LOCAL, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_CREATE_BINDING) \ + CBC_OPCODE (CBC_INIT_ARG_OR_CATCH, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_LET, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_CONST, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_ARG_OR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_INIT_ARG_OR_FUNC) \ + CBC_OPCODE (CBC_CREATE_VAR_EVAL, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_VAR_EVAL) \ + CBC_OPCODE (CBC_CREATE_VAR_FUNC_EVAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_VAR_EVAL) \ + CBC_OPCODE (CBC_SET_VAR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \ CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \ - VM_OC_NONE) \ + VM_OC_SET_BYTECODE_PTR) \ CBC_OPCODE (CBC_RETURN, CBC_NO_FLAG, -1, \ - VM_OC_RET | VM_OC_GET_STACK) \ + VM_OC_RETURN | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_RETURN_WITH_BLOCK, CBC_NO_FLAG, 0, \ - VM_OC_RET) \ + VM_OC_RETURN) \ CBC_OPCODE (CBC_RETURN_WITH_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_RET | VM_OC_GET_LITERAL) \ + VM_OC_RETURN | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_SET_LITERAL_PROPERTY, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ VM_OC_SET_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \ + CBC_OPCODE (CBC_COPY_TO_GLOBAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_COPY_TO_GLOBAL | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_BREAKPOINT_ENABLED, CBC_NO_FLAG, 0, \ VM_OC_BREAKPOINT_ENABLED) \ CBC_OPCODE (CBC_BREAKPOINT_DISABLED, CBC_NO_FLAG, 0, \ @@ -378,6 +402,8 @@ DIV) \ CBC_BINARY_OPERATION (CBC_MODULO, \ MOD) \ + CBC_BINARY_OPERATION (CBC_EXPONENTIATION, \ + EXP) \ \ /* Unary lvalue opcodes. */ \ CBC_OPCODE (CBC_DELETE_PUSH_RESULT, CBC_NO_FLAG, -1, \ @@ -476,6 +502,16 @@ VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_MOV_IDENT, CBC_HAS_LITERAL_ARG, -1, \ VM_OC_MOV_IDENT | VM_OC_GET_STACK | VM_OC_PUT_IDENT) \ + CBC_OPCODE (CBC_ASSIGN_LET_CONST, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_ASSIGN_LET_CONST | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_ASSIGN_LET_CONST_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_ASSIGN_LET_CONST | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_ASSIGN_SUPER, CBC_NO_FLAG, -3, \ + VM_OC_ASSIGN_SUPER) \ + CBC_OPCODE (CBC_ASSIGN_SUPER_PUSH_RESULT, CBC_NO_FLAG, -2, \ + VM_OC_ASSIGN_SUPER | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_ASSIGN_SUPER_BLOCK, CBC_NO_FLAG, -3, \ + VM_OC_ASSIGN_SUPER | VM_OC_PUT_BLOCK) \ \ /* Last opcode (not a real opcode). */ \ CBC_OPCODE (CBC_END, CBC_NO_FLAG, 0, \ @@ -510,18 +546,18 @@ VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \ CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \ VM_OC_TRY) \ - CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \ - VM_OC_THROW_REFERENCE_ERROR) \ + CBC_OPCODE (CBC_EXT_TRY_CREATE_ENV, CBC_NO_FLAG, 0, \ + VM_OC_BLOCK_CREATE_CONTEXT) \ CBC_FORWARD_BRANCH (CBC_EXT_CATCH, 1, \ VM_OC_CATCH) \ - CBC_OPCODE (CBC_EXT_PUSH_UNDEFINED_BASE, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_UNDEFINED_BASE | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_RESOLVE_BASE, CBC_NO_FLAG, 0, \ + VM_OC_RESOLVE_BASE_FOR_CALL) \ CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \ VM_OC_FINALLY) \ - CBC_OPCODE (CBC_EXT_CLASS_EXPR_CONTEXT_END, CBC_NO_FLAG, 0, \ - VM_OC_CLASS_EXPR_CONTEXT_END) \ - CBC_FORWARD_BRANCH (CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, \ - -1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_PROP, CBC_NO_FLAG, 0, \ + VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_STACK) \ + CBC_FORWARD_BRANCH (CBC_EXT_DEFAULT_INITIALIZER, -1, \ + VM_OC_DEFAULT_INITIALIZER) \ \ /* Basic opcodes. */ \ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \ @@ -530,10 +566,38 @@ VM_OC_PUSH_LIT_POS_BYTE | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \ VM_OC_PUSH_LIT_NEG_BYTE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_CREATE_VAR_EVAL, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_EXT_VAR_EVAL) \ + CBC_OPCODE (CBC_EXT_CREATE_VAR_FUNC_EVAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_EXT_VAR_EVAL) \ + CBC_OPCODE (CBC_EXT_COPY_FROM_ARG, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_COPY_FROM_ARG) \ + CBC_OPCODE (CBC_EXT_STRING_CONCAT, CBC_NO_FLAG, -1, \ + VM_OC_STRING_CONCAT | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_STRING_CONCAT | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \ + VM_OC_STRING_CONCAT | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_GET_TAGGED_TEMPLATE_LITERAL, CBC_HAS_BYTE_ARG, 1, \ + VM_OC_GET_TEMPLATE_OBJECT | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_CLONE_CONTEXT, CBC_NO_FLAG, 0, \ + VM_OC_CLONE_CONTEXT) \ + CBC_OPCODE (CBC_EXT_CLONE_FULL_CONTEXT, CBC_NO_FLAG, 0, \ + VM_OC_CLONE_CONTEXT) \ CBC_OPCODE (CBC_EXT_RESOURCE_NAME, CBC_NO_FLAG, 0, \ VM_OC_RESOURCE_NAME) \ CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \ VM_OC_LINE) \ + CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \ + VM_OC_ERROR) \ + CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \ + VM_OC_THROW_REFERENCE_ERROR) \ + CBC_OPCODE (CBC_EXT_THROW_ASSIGN_CONST_ERROR, CBC_NO_FLAG, 0, \ + VM_OC_THROW_CONST_ERROR) \ + CBC_OPCODE (CBC_EXT_REQUIRE_OBJECT_COERCIBLE, CBC_NO_FLAG, 0, \ + VM_OC_REQUIRE_OBJECT_COERCIBLE) \ + \ + /* Computed / class property related opcodes. */ \ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY, CBC_NO_FLAG, -2, \ VM_OC_SET_COMPUTED_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG, -1, \ @@ -554,44 +618,114 @@ VM_OC_SET_GETTER | VM_OC_GET_STACK_LITERAL) \ CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_SETTER, CBC_HAS_LITERAL_ARG, -1, \ VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \ - CBC_OPCODE (CBC_EXT_RESOLVE_BASE, CBC_NO_FLAG, 0, \ - VM_OC_RESOLVE_BASE_FOR_CALL) \ + CBC_OPCODE (CBC_EXT_SET__PROTO__, CBC_NO_FLAG, -1, \ + VM_OC_SET__PROTO__ | VM_OC_GET_STACK) \ \ - /* Class opcodes */ \ - CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \ - VM_OC_CLASS_INHERITANCE) \ - CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, CBC_NO_FLAG, 2, \ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL, CBC_NO_FLAG, 0, \ - VM_OC_PUSH_IMPL_CONSTRUCTOR) \ - CBC_OPCODE (CBC_EXT_SET_CLASS_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_SET_CLASS_CONSTRUCTOR | VM_OC_GET_LITERAL) \ - CBC_OPCODE (CBC_EXT_CLASS_EVAL, CBC_HAS_BYTE_ARG, 0, \ - VM_OC_CLASS_EVAL) \ + /* Class related opcodes. */ \ + CBC_OPCODE (CBC_EXT_PUSH_NAMED_CLASS_ENV, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_PUSH_CLASS_ENVIRONMENT | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_PUSH_ANONYMOUS_CLASS_ENV, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_CLASS_ENVIRONMENT) \ + CBC_OPCODE (CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_IMPLICIT_CTOR | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_IMPLICIT_CTOR | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_INIT_CLASS, CBC_NO_FLAG, 0, \ + VM_OC_INIT_CLASS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_FINALIZE_NAMED_CLASS, CBC_HAS_LITERAL_ARG, -2, \ + VM_OC_FINALIZE_CLASS | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_FINALIZE_ANONYMOUS_CLASS, CBC_NO_FLAG, -2, \ + VM_OC_FINALIZE_CLASS) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \ + VM_OC_NONE) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_SUPER_CONSTRUCTOR) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_PROP, CBC_NO_FLAG, 0, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_REFERENCE, CBC_NO_FLAG, 2, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_ASSIGNMENT_REFERENCE, CBC_NO_FLAG, 1, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_ASSIGNMENT_REFERENCE, CBC_HAS_LITERAL_ARG, 2, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_RESOLVE_LEXICAL_THIS, CBC_NO_FLAG, 1, \ + VM_OC_RESOLVE_LEXICAL_THIS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_LOCAL_EVAL, CBC_HAS_BYTE_ARG, 0, \ + VM_OC_LOCAL_EVAL) \ CBC_OPCODE (CBC_EXT_SUPER_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_SUPER_CALL) \ CBC_OPCODE (CBC_EXT_SUPER_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_SUPER_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_SUPER_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_SUPER_CALL | VM_OC_PUT_BLOCK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_STATIC_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_THIS, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_THIS | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_SUPER_PROP_CALL, CBC_NO_FLAG, 0, \ - VM_OC_SUPER_PROP_REFERENCE) \ - CBC_OPCODE (CBC_EXT_SUPER_PROP_ASSIGN, CBC_NO_FLAG, 0, \ - VM_OC_SUPER_PROP_REFERENCE) \ - CBC_OPCODE (CBC_EXT_CONSTRUCTOR_RETURN, CBC_NO_FLAG, -1, \ - VM_OC_CONSTRUCTOR_RET | VM_OC_GET_STACK) \ - CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \ - VM_OC_ERROR) \ + CBC_OPCODE (CBC_EXT_SPREAD_SUPER_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ + VM_OC_SUPER_CALL) \ + CBC_OPCODE (CBC_EXT_SPREAD_SUPER_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ + VM_OC_SUPER_CALL | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_SPREAD_SUPER_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ + VM_OC_SUPER_CALL | VM_OC_PUT_BLOCK) \ + \ + /* Spread / rest operation related opcodes. */ \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ + VM_OC_SPREAD_ARGUMENTS) \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ + VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ + VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_BLOCK) \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL_PROP, CBC_HAS_POP_STACK_BYTE_ARG, -3, \ + VM_OC_SPREAD_ARGUMENTS) \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL_PROP_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, -2, \ + VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_SPREAD_CALL_PROP_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -3, \ + VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_BLOCK) \ + CBC_OPCODE (CBC_EXT_PUSH_SPREAD_ELEMENT, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_SPREAD_ELEMENT) \ + CBC_OPCODE (CBC_EXT_SPREAD_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ + VM_OC_APPEND_ARRAY) \ + CBC_OPCODE (CBC_EXT_REST_INITIALIZER, CBC_NO_FLAG, 1, \ + VM_OC_REST_INITIALIZER) \ + CBC_OPCODE (CBC_EXT_REST_INITIALIZER_2, CBC_NO_FLAG, 1, \ + VM_OC_REST_INITIALIZER) \ + CBC_OPCODE (CBC_EXT_REST_INITIALIZER_3, CBC_NO_FLAG, 1, \ + VM_OC_REST_INITIALIZER) \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_SPREAD_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ + VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ + \ + /* Iterator related opcodes. */ \ + CBC_OPCODE (CBC_EXT_GET_ITERATOR, CBC_NO_FLAG, 1, \ + VM_OC_GET_ITERATOR) \ + CBC_OPCODE (CBC_EXT_ITERATOR_STEP, CBC_NO_FLAG, 1, \ + VM_OC_ITERATOR_STEP) \ + CBC_OPCODE (CBC_EXT_ITERATOR_STEP_2, CBC_NO_FLAG, 1, \ + VM_OC_ITERATOR_STEP) \ + CBC_OPCODE (CBC_EXT_ITERATOR_STEP_3, CBC_NO_FLAG, 1, \ + VM_OC_ITERATOR_STEP) \ + CBC_OPCODE (CBC_EXT_ITERATOR_CLOSE, CBC_NO_FLAG, -1, \ + VM_OC_ITERATOR_CLOSE | VM_OC_GET_STACK) \ + \ + /* Executable object related opcodes. */ \ + CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 1, \ + VM_OC_CREATE_GENERATOR) \ + CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, 0, \ + VM_OC_YIELD) \ + CBC_OPCODE (CBC_EXT_YIELD_ITERATOR, CBC_NO_FLAG, 0, \ + VM_OC_YIELD) \ + CBC_OPCODE (CBC_EXT_AWAIT, CBC_NO_FLAG, 0, \ + VM_OC_AWAIT) \ + CBC_OPCODE (CBC_EXT_RETURN, CBC_NO_FLAG, -1, \ + VM_OC_EXT_RETURN | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_RETURN_PROMISE, CBC_NO_FLAG, -1, \ + VM_OC_RETURN_PROMISE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_RETURN_PROMISE_UNDEFINED, CBC_NO_FLAG, 0, \ + VM_OC_RETURN_PROMISE) \ + CBC_OPCODE (CBC_EXT_PUSH_NEW_TARGET, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_NEW_TARGET | VM_OC_PUT_STACK) \ \ /* Last opcode (not a real opcode). */ \ CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \ @@ -674,21 +808,25 @@ typedef enum CBC_CODE_FLAGS_FULL_LITERAL_ENCODING = (1u << 1), /**< full literal encoding mode is enabled */ CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 2), /**< compiled code data is cbc_uint16_arguments_t */ CBC_CODE_FLAGS_STRICT_MODE = (1u << 3), /**< strict mode is enabled */ - CBC_CODE_FLAGS_ARGUMENTS_NEEDED = (1u << 4), /**< arguments object must be constructed */ - CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */ - CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 6), /**< this function is an arrow function */ - CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 7), /**< this function is a static snapshot function */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 8), /**< this function should be ignored by debugger */ - CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 9), /**< this function is a constructor */ - CBC_CODE_FLAGS_REST_PARAMETER = (1u << 10), /**< this function has rest parameter */ + CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED = (1u << 4), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED = (1u << 5), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 6), /**< no need to create a lexical environment */ + CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_CLASS_CONSTRUCTOR = (1u << 10), /**< this function is a class constructor */ + CBC_CODE_FLAGS_GENERATOR = (1u << 11), /**< this function is a generator */ + CBC_CODE_FLAGS_REST_PARAMETER = (1u << 12), /**< this function has rest parameter */ + CBC_CODE_FLAG_HAS_TAGGED_LITERALS = (1u << 13), /**< this function has tagged template literal list */ + CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 14), /**< compiled code needs a lexical block */ + CBC_CODE_FLAGS_ACCESSOR = (1u << 15) /**< accessor propety 'get' and 'set' functions */ } cbc_code_flags; /** - * Non-strict arguments object must be constructed + * Any arguments object is needed */ -#define CBC_NON_STRICT_ARGUMENTS_NEEDED(compiled_code_p) \ - (((compiled_code_p)->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) \ - && !((compiled_code_p)->status_flags & CBC_CODE_FLAGS_STRICT_MODE)) +#define CBC_CODE_FLAGS_IS_ARGUMENTS_NEEDED \ + (CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED | CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED) #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, diff --git a/jerry-core/parser/js/common.c b/jerry-core/parser/js/common.c index d3a54093..5aeca88d 100644 --- a/jerry-core/parser/js/common.c +++ b/jerry-core/parser/js/common.c @@ -85,14 +85,7 @@ util_print_literal (lexer_literal_t *literal_p) /**< literal */ { if (literal_p->type == LEXER_IDENT_LITERAL) { - if (literal_p->status_flags & LEXER_FLAG_VAR) - { - JERRY_DEBUG_MSG ("var_ident("); - } - else - { - JERRY_DEBUG_MSG ("ident("); - } + JERRY_DEBUG_MSG ("ident("); util_print_chars (literal_p->u.char_p, literal_p->prop.length); } else if (literal_p->type == LEXER_FUNCTION_LITERAL) diff --git a/jerry-core/parser/js/common.h b/jerry-core/parser/js/common.h index 18479772..3f504c90 100644 --- a/jerry-core/parser/js/common.h +++ b/jerry-core/parser/js/common.h @@ -55,6 +55,8 @@ typedef enum LEXER_REGEXP_LITERAL = 4, /**< regexp literal */ LEXER_UNUSED_LITERAL = 5, /**< unused literal, can only be used by the byte code generator. */ + LEXER_NEW_IDENT_LITERAL = 6, /**< new local variable, can only be + used by the byte code generator. */ } lexer_literal_type_t; /** @@ -67,15 +69,14 @@ typedef enum */ typedef enum { - LEXER_FLAG_VAR = (1 << 0), /**< local identifier (var, function arg) */ - LEXER_FLAG_NO_REG_STORE = (1 << 1), /**< this local identifier cannot be stored in register */ - LEXER_FLAG_INITIALIZED = (1 << 2), /**< this local identifier is initialized with a value */ - LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 3), /**< this local identifier is a function argument */ - LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions, - * but not referenced by the currently parsed function */ - LEXER_FLAG_SOURCE_PTR = (1 << 5), /**< the literal is directly referenced in the source code + LEXER_FLAG_USED = (1 << 0), /**< this local identifier needs to be stored in the constant pool */ + LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 1), /**< this local identifier is a function argument */ + LEXER_FLAG_SOURCE_PTR = (1 << 2), /**< the literal is directly referenced in the source code * (no need to allocate memory) */ - LEXER_FLAG_LATE_INIT = (1 << 6), /**< initialize this variable after the byte code is freed */ + LEXER_FLAG_LATE_INIT = (1 << 3), /**< initialize this variable after the byte code is freed */ +#if ENABLED (JERRY_ES2015) + LEXER_FLAG_GLOBAL = (1 << 4), /**< this local identifier is not a let or const declaration */ +#endif /* ENABLED (JERRY_ES2015) */ } lexer_literal_status_flags_t; /** diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index f5022f2d..b06ff84d 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -33,6 +33,9 @@ * @{ */ +JERRY_STATIC_ASSERT (LEXER_NUMBER_BINARY > LEXER_NUMBER_OCTAL, + lexer_number_binary_must_be_greater_than_lexer_number_octal); + /** * Check whether the UTF-8 intermediate is an octet or not */ @@ -53,14 +56,13 @@ align_column_to_tab (parser_line_counter_t column) /**< current column */ /** * Parse hexadecimal character sequence * - * @return character value + * @return character value or UINT32_MAX on error */ -ecma_char_t -lexer_hex_to_character (parser_context_t *context_p, /**< context */ - const uint8_t *source_p, /**< current source position */ - int length) /**< source length */ +static lit_code_point_t +lexer_hex_to_code_point (const uint8_t *source_p, /**< current source position */ + parser_line_counter_t length) /**< source length */ { - uint32_t result = 0; + lit_code_point_t result = 0; do { @@ -81,29 +83,94 @@ lexer_hex_to_character (parser_context_t *context_p, /**< context */ } else { - parser_raise_error (context_p, PARSER_ERR_INVALID_ESCAPE_SEQUENCE); + return UINT32_MAX; } } } while (--length > 0); - return (ecma_char_t) result; -} /* lexer_hex_to_character */ + return result; +} /* lexer_hex_to_code_point */ + +#if ENABLED (JERRY_ES2015) + +/** + * Parse hexadecimal character sequence enclosed in braces + * + * @return character value or UINT32_MAX on error + */ +static lit_code_point_t +lexer_hex_in_braces_to_code_point (const uint8_t *source_p, /**< current source position */ + const uint8_t *source_end_p, /**< source end */ + uint32_t *length_p) /**< [out] length of the sequence */ +{ + lit_code_point_t result = 0; + /* Four is the size of \u{} sequence. */ + uint32_t length = 4; + + JERRY_ASSERT (source_p[-1] == LIT_CHAR_LEFT_BRACE); + JERRY_ASSERT (source_p < source_end_p); + + do + { + uint32_t byte = *source_p++; + + result <<= 4; + + if (byte >= LIT_CHAR_0 && byte <= LIT_CHAR_9) + { + result += byte - LIT_CHAR_0; + } + else + { + byte = LEXER_TO_ASCII_LOWERCASE (byte); + if (byte >= LIT_CHAR_LOWERCASE_A && byte <= LIT_CHAR_LOWERCASE_F) + { + result += byte - (LIT_CHAR_LOWERCASE_A - 10); + } + else + { + return UINT32_MAX; + } + } + + if (result >= (LIT_UNICODE_CODE_POINT_MAX + 1) || source_p >= source_end_p) + { + return UINT32_MAX; + } + length++; + } + while (*source_p != LIT_CHAR_RIGHT_BRACE); + + *length_p = length; + return result; +} /* lexer_hex_in_braces_to_code_point */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Parse hexadecimal character sequence * * @return character value */ -static ecma_char_t -lexer_unchecked_hex_to_character (const uint8_t *source_p, /**< current source position */ - int length) /**< source length */ +static lit_code_point_t +lexer_unchecked_hex_to_character (const uint8_t **source_p) /**< [in, out] current source position */ { - uint32_t result = 0; + lit_code_point_t result = 0; + const uint8_t *char_p = *source_p; + uint32_t length = (char_p[-1] == LIT_CHAR_LOWERCASE_U) ? 4 : 2; - do +#if ENABLED (JERRY_ES2015) + if (char_p[0] == LIT_CHAR_LEFT_BRACE) { - uint32_t byte = *source_p++; + length = 0; + char_p++; + } +#endif /* ENABLED (JERRY_ES2015) */ + + while (true) + { + uint32_t byte = *char_p++; result <<= 4; @@ -118,10 +185,27 @@ lexer_unchecked_hex_to_character (const uint8_t *source_p, /**< current source p result += LEXER_TO_ASCII_LOWERCASE (byte) - (LIT_CHAR_LOWERCASE_A - 10); } - } - while (--length > 0); - return (ecma_char_t) result; + JERRY_ASSERT (result <= LIT_UNICODE_CODE_POINT_MAX); + +#if ENABLED (JERRY_ES2015) + if (length == 0) + { + if (*char_p != LIT_CHAR_RIGHT_BRACE) + { + continue; + } + *source_p = char_p + 1; + return result; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (--length == 0) + { + *source_p = char_p; + return result; + } + } } /* lexer_unchecked_hex_to_character */ /** @@ -145,7 +229,7 @@ lexer_skip_spaces (parser_context_t *context_p) /**< context */ if (context_p->token.flags & LEXER_NO_SKIP_SPACES) { - context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES); + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; return; } @@ -304,14 +388,14 @@ lexer_skip_spaces (parser_context_t *context_p) /**< context */ context_p->source_p++; if (context_p->source_p < source_end_p - && IS_UTF8_INTERMEDIATE_OCTET (context_p->source_p[0])) + && !IS_UTF8_INTERMEDIATE_OCTET (context_p->source_p[0])) { context_p->column++; } } } /* lexer_skip_spaces */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) /** * Skip all the continuous empty statements. */ @@ -323,13 +407,13 @@ lexer_skip_empty_statements (parser_context_t *context_p) /**< context */ while (context_p->source_p < context_p->source_end_p && *context_p->source_p == LIT_CHAR_SEMICOLON) { - context_p->source_p++; + lexer_consume_next_character (context_p); lexer_skip_spaces (context_p); } context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); } /* lexer_skip_empty_statements */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Keyword data. @@ -348,6 +432,16 @@ typedef struct #define LEXER_KEYWORD_LIST_LENGTH(name) (const uint8_t) (sizeof ((name)) / sizeof ((name)[0])) /** @} */ +/** + * Length of the shortest keyword. + */ +#define LEXER_KEYWORD_MIN_LENGTH 2 + +/** + * Length of the longest keyword. + */ +#define LEXER_KEYWORD_MAX_LENGTH 10 + /** * Keywords with 2 characters. */ @@ -378,6 +472,7 @@ static const keyword_string_t keywords_with_length_4[] = LEXER_KEYWORD ("case", LEXER_KEYW_CASE), LEXER_KEYWORD ("else", LEXER_KEYW_ELSE), LEXER_KEYWORD ("enum", LEXER_KEYW_ENUM), + LEXER_KEYWORD ("eval", LEXER_KEYW_EVAL), LEXER_KEYWORD ("null", LEXER_LIT_NULL), LEXER_KEYWORD ("this", LEXER_KEYW_THIS), LEXER_KEYWORD ("true", LEXER_LIT_TRUE), @@ -391,6 +486,7 @@ static const keyword_string_t keywords_with_length_4[] = static const keyword_string_t keywords_with_length_5[] = { #if ENABLED (JERRY_ES2015) + LEXER_KEYWORD ("async", LEXER_KEYW_ASYNC), LEXER_KEYWORD ("await", LEXER_KEYW_AWAIT), #endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYWORD ("break", LEXER_KEYW_BREAK), @@ -446,6 +542,7 @@ static const keyword_string_t keywords_with_length_8[] = */ static const keyword_string_t keywords_with_length_9[] = { + LEXER_KEYWORD ("arguments", LEXER_KEYW_ARGUMENTS), LEXER_KEYWORD ("interface", LEXER_KEYW_INTERFACE), LEXER_KEYWORD ("protected", LEXER_KEYW_PROTECTED), }; @@ -475,6 +572,10 @@ static const keyword_string_t * const keyword_strings_list[] = keywords_with_length_10 }; +JERRY_STATIC_ASSERT (sizeof (keyword_strings_list) / sizeof (const keyword_string_t *) + == (LEXER_KEYWORD_MAX_LENGTH - LEXER_KEYWORD_MIN_LENGTH) + 1, + keyword_strings_list_size_must_equal_to_keyword_max_length_difference); + /** * List of the keyword groups length. */ @@ -495,100 +596,210 @@ static const uint8_t keyword_lengths_list[] = #undef LEXER_KEYWORD_LIST_LENGTH /** - * Parse identifier. + * Flags for lexer_parse_identifier. */ -static void +typedef enum +{ + LEXER_PARSE_NO_OPTS = 0, /**< no options */ + LEXER_PARSE_CHECK_KEYWORDS = (1 << 0), /**< check keywords */ + LEXER_PARSE_CHECK_START_AND_RETURN = (1 << 1), /**< check identifier start and return */ + LEXER_PARSE_CHECK_PART_AND_RETURN = (1 << 2), /**< check identifier part and return */ +} lexer_parse_options_t; + +JERRY_STATIC_ASSERT (LEXER_FIRST_NON_RESERVED_KEYWORD < LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD, + lexer_first_non_reserved_keyword_must_be_before_lexer_first_future_strict_reserved_word); + +/** + * Parse identifier. + * + * @return true, if an identifier is parsed, false otherwise + */ +static bool lexer_parse_identifier (parser_context_t *context_p, /**< context */ - bool check_keywords) /**< check keywords */ + lexer_parse_options_t options) /**< check keywords */ { /* Only very few identifiers contains \u escape sequences. */ const uint8_t *source_p = context_p->source_p; - const uint8_t *ident_start_p = context_p->source_p; /* Note: newline or tab cannot be part of an identifier. */ parser_line_counter_t column = context_p->column; const uint8_t *source_end_p = context_p->source_end_p; size_t length = 0; - - context_p->token.type = LEXER_LITERAL; - context_p->token.literal_is_reserved = false; - context_p->token.lit_location.type = LEXER_IDENT_LITERAL; - context_p->token.lit_location.has_escape = false; + uint8_t has_escape = false; do { if (*source_p == LIT_CHAR_BACKSLASH) { - uint16_t character; + /* After a backslash an identifier must start. */ + lit_code_point_t code_point = UINT32_MAX; + uint32_t escape_length = 6; - context_p->token.lit_location.has_escape = true; - context_p->source_p = source_p; - context_p->token.column = column; - - if ((source_p + 6 > source_end_p) || (source_p[1] != LIT_CHAR_LOWERCASE_U)) + if (options & (LEXER_PARSE_CHECK_START_AND_RETURN | LEXER_PARSE_CHECK_PART_AND_RETURN)) { + return true; + } + + has_escape = true; + +#if ENABLED (JERRY_ES2015) + if (source_p + 5 <= source_end_p && source_p[1] == LIT_CHAR_LOWERCASE_U) + { + if (source_p[2] == LIT_CHAR_LEFT_BRACE) + { + code_point = lexer_hex_in_braces_to_code_point (source_p + 3, source_end_p, &escape_length); + } + else if (source_p + 6 <= source_end_p) + { + code_point = lexer_hex_to_code_point (source_p + 2, 4); + } + } +#else /* !ENABLED (JERRY_ES2015) */ + if (source_p + 6 <= source_end_p && source_p[1] == LIT_CHAR_LOWERCASE_U) + { + code_point = lexer_hex_to_code_point (source_p + 2, 4); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (code_point == UINT32_MAX) + { + context_p->source_p = source_p; + context_p->token.column = column; parser_raise_error (context_p, PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE); } - character = lexer_hex_to_character (context_p, source_p + 2, 4); - if (length == 0) { - if (!lit_char_is_identifier_start_character (character)) + if (!lit_code_point_is_identifier_start (code_point)) { parser_raise_error (context_p, PARSER_ERR_INVALID_IDENTIFIER_START); } } else { - if (!lit_char_is_identifier_part_character (character)) + if (!lit_code_point_is_identifier_part (code_point)) { parser_raise_error (context_p, PARSER_ERR_INVALID_IDENTIFIER_PART); } } - length += lit_char_get_utf8_length (character); - source_p += 6; - PARSER_PLUS_EQUAL_LC (column, 6); + length += lit_code_point_get_cesu8_length (code_point); + source_p += escape_length; + PARSER_PLUS_EQUAL_LC (column, escape_length); continue; } - /* Valid identifiers cannot contain 4 byte long utf-8 - * characters, since those characters are represented - * by 2 ecmascript (UTF-16) characters, and those - * characters cannot be literal characters. */ - JERRY_ASSERT (source_p[0] < LEXER_UTF8_4BYTE_START); + lit_code_point_t code_point = *source_p; + lit_utf8_size_t utf8_length = 1, decoded_length = 1, char_count = 1; - source_p++; - length++; - column++; - - while (source_p < source_end_p - && IS_UTF8_INTERMEDIATE_OCTET (source_p[0])) + if (JERRY_UNLIKELY (code_point >= LIT_UTF8_2_BYTE_MARKER)) { - source_p++; - length++; +#if ENABLED (JERRY_ES2015) + utf8_length = lit_read_code_point_from_utf8 (source_p, + (lit_utf8_size_t) (source_end_p - source_p), + &code_point); + decoded_length = utf8_length; + + /* Only ES2015 supports code points outside of the basic plane which can be part of an identifier. */ + if ((code_point >= LIT_UTF16_HIGH_SURROGATE_MIN && code_point <= LIT_UTF16_HIGH_SURROGATE_MAX) + && source_p + 3 < source_end_p) + { + lit_code_point_t low_surrogate; + lit_read_code_point_from_utf8 (source_p + 3, + (lit_utf8_size_t) (source_end_p - (source_p + 3)), + &low_surrogate); + + if (low_surrogate >= LIT_UTF16_LOW_SURROGATE_MIN && low_surrogate <= LIT_UTF16_LOW_SURROGATE_MAX) + { + code_point = lit_convert_surrogate_pair_to_code_point ((ecma_char_t) code_point, + (ecma_char_t) low_surrogate); + utf8_length = 2 * 3; + decoded_length = 2 * 3; + char_count = 2; + } + } + else if (source_p[0] >= LIT_UTF8_4_BYTE_MARKER) + { + decoded_length = 2 * 3; + has_escape = true; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (code_point < LIT_UTF8_4_BYTE_MARKER) + { + utf8_length = lit_read_code_point_from_utf8 (source_p, + (lit_utf8_size_t) (source_end_p - source_p), + &code_point); + decoded_length = utf8_length; + } + else + { + code_point = 0; + } +#endif /* ENABLED (JERRY_ES2015) */ } + + if (length == 0) + { + if (JERRY_UNLIKELY (options & (LEXER_PARSE_CHECK_START_AND_RETURN | LEXER_PARSE_CHECK_PART_AND_RETURN))) + { + if (options & LEXER_PARSE_CHECK_START_AND_RETURN) + { + return lit_code_point_is_identifier_start (code_point); + } + else + { + return lit_code_point_is_identifier_part (code_point); + } + } + + if (!lit_code_point_is_identifier_start (code_point)) + { + return false; + } + } + else if (!lit_code_point_is_identifier_part (code_point)) + { + break; + } + + source_p += utf8_length; + length += decoded_length; + PARSER_PLUS_EQUAL_LC (column, char_count); } - while (source_p < source_end_p - && (lit_char_is_identifier_part (source_p) || *source_p == LIT_CHAR_BACKSLASH)); + while (source_p < source_end_p); + + JERRY_ASSERT (length > 0); + + context_p->token.type = LEXER_LITERAL; + context_p->token.keyword_type = LEXER_EOS; + context_p->token.lit_location.type = LEXER_IDENT_LITERAL; + context_p->token.lit_location.has_escape = has_escape; - context_p->source_p = ident_start_p; context_p->token.column = context_p->column; + context_p->token.lit_location.char_p = context_p->source_p; + context_p->token.lit_location.length = (prop_length_t) length; - if (length > PARSER_MAXIMUM_IDENT_LENGTH) + if (JERRY_UNLIKELY (length > PARSER_MAXIMUM_IDENT_LENGTH)) { parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_TOO_LONG); } - /* Check keywords (Only if there is no \u escape sequence in the pattern). */ - if (check_keywords - && !context_p->token.lit_location.has_escape - && (length >= 2 && length <= 10)) + /* Check keywords. */ + if ((options & LEXER_PARSE_CHECK_KEYWORDS) + && (length >= LEXER_KEYWORD_MIN_LENGTH && length <= LEXER_KEYWORD_MAX_LENGTH)) { - const keyword_string_t *keyword_list_p = keyword_strings_list[length - 2]; + const uint8_t *ident_start_p = context_p->source_p; + uint8_t buffer_p[LEXER_KEYWORD_MAX_LENGTH]; + + if (JERRY_UNLIKELY (context_p->token.lit_location.has_escape)) + { + lexer_convert_ident_to_cesu8 (buffer_p, ident_start_p, (prop_length_t) length); + ident_start_p = buffer_p; + } + + const keyword_string_t *keyword_list_p = keyword_strings_list[length - LEXER_KEYWORD_MIN_LENGTH]; int start = 0; - int end = keyword_lengths_list[length - 2]; + int end = keyword_lengths_list[length - LEXER_KEYWORD_MIN_LENGTH]; int middle = end / 2; do @@ -602,18 +813,76 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */ if (compare_result == 0) { - if (JERRY_UNLIKELY (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD)) + context_p->token.keyword_type = (uint8_t) keyword_p->type; + + if (JERRY_LIKELY (keyword_p->type < LEXER_FIRST_NON_RESERVED_KEYWORD)) { - if (context_p->status_flags & PARSER_IS_STRICT) +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (keyword_p->type == LEXER_KEYW_AWAIT)) { - parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED); + if (!(context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + && !(context_p->global_status_flags & ECMA_PARSE_MODULE)) + { + break; + } + + if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD) + { + if (ident_start_p == buffer_p) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + parser_raise_error (context_p, PARSER_ERR_AWAIT_NOT_ALLOWED); + } + + context_p->token.type = (uint8_t) LEXER_KEYW_AWAIT; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (ident_start_p == buffer_p) + { + /* Escape sequences are not allowed in a keyword. */ + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); } - context_p->token.literal_is_reserved = true; + context_p->token.type = (uint8_t) keyword_p->type; break; } - context_p->token.type = (uint8_t) keyword_p->type; +#if ENABLED (JERRY_ES2015) + if (keyword_p->type == LEXER_KEYW_LET && (context_p->status_flags & PARSER_IS_STRICT)) + { + if (ident_start_p == buffer_p) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + + context_p->token.type = (uint8_t) LEXER_KEYW_LET; + break; + } + + if (keyword_p->type == LEXER_KEYW_YIELD && (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)) + { + if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD) + { + if (ident_start_p == buffer_p) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + parser_raise_error (context_p, PARSER_ERR_YIELD_NOT_ALLOWED); + } + + context_p->token.type = (uint8_t) LEXER_KEYW_YIELD; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD + && (context_p->status_flags & PARSER_IS_STRICT)) + { + parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED); + } break; } } @@ -633,23 +902,24 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */ while (start < end); } - if (context_p->token.type == LEXER_LITERAL) - { - /* Fill literal data. */ - context_p->token.lit_location.char_p = ident_start_p; - context_p->token.lit_location.length = (prop_length_t) length; - } - context_p->source_p = source_p; context_p->column = column; + return true; } /* lexer_parse_identifier */ /** * Parse string. */ void -lexer_parse_string (parser_context_t *context_p) /**< context */ +lexer_parse_string (parser_context_t *context_p, /**< context */ + lexer_string_options_t opts) /**< options */ { +#if ENABLED (JERRY_ES2015) + int32_t raw_length_adjust = 0; +#else /* ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (opts); +#endif /* ENABLED (JERRY_ES2015) */ + uint8_t str_end_character = context_p->source_p[0]; const uint8_t *source_p = context_p->source_p + 1; const uint8_t *string_start_p = source_p; @@ -661,12 +931,12 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ size_t length = 0; uint8_t has_escape = false; -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) if (str_end_character == LIT_CHAR_RIGHT_BRACE) { str_end_character = LIT_CHAR_GRAVE_ACCENT; } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ while (true) { @@ -701,6 +971,9 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ if (source_p < source_end_p && *source_p == LIT_CHAR_LF) { +#if ENABLED (JERRY_ES2015) + raw_length_adjust--; +#endif /* ENABLED (JERRY_ES2015) */ source_p++; } @@ -723,6 +996,19 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ continue; } +#if ENABLED (JERRY_ES2015) + if (opts & LEXER_STRING_RAW) + { + if ((*source_p == LIT_CHAR_GRAVE_ACCENT) || (*source_p == LIT_CHAR_BACKSLASH)) + { + source_p++; + column++; + length++; + } + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (*source_p == LIT_CHAR_0 && source_p + 1 < source_end_p && (*(source_p + 1) < LIT_CHAR_0 || *(source_p + 1) > LIT_CHAR_9)) @@ -792,35 +1078,56 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ if (*source_p == LIT_CHAR_LOWERCASE_X || *source_p == LIT_CHAR_LOWERCASE_U) { - uint8_t hex_part_length = (*source_p == LIT_CHAR_LOWERCASE_X) ? 2 : 4; + uint32_t escape_length = (*source_p == LIT_CHAR_LOWERCASE_X) ? 3 : 5; + lit_code_point_t code_point = UINT32_MAX; context_p->token.line = line; context_p->token.column = (parser_line_counter_t) (column - 1); - if (source_p + 1 + hex_part_length > source_end_p) + +#if ENABLED (JERRY_ES2015) + if (source_p + 4 <= source_end_p + && source_p[0] == LIT_CHAR_LOWERCASE_U + && source_p[1] == LIT_CHAR_LEFT_BRACE) { - parser_raise_error (context_p, PARSER_ERR_INVALID_ESCAPE_SEQUENCE); + code_point = lexer_hex_in_braces_to_code_point (source_p + 2, source_end_p, &escape_length); + escape_length--; + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + if (source_p + escape_length <= source_end_p) + { + code_point = lexer_hex_to_code_point (source_p + 1, escape_length - 1); + } +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (code_point == UINT32_MAX) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE); } - length += lit_char_get_utf8_length (lexer_hex_to_character (context_p, - source_p + 1, - hex_part_length)); - source_p += hex_part_length + 1; - PARSER_PLUS_EQUAL_LC (column, hex_part_length + 1u); + length += lit_code_point_get_cesu8_length (code_point); + + source_p += escape_length; + PARSER_PLUS_EQUAL_LC (column, escape_length); continue; } } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) else if (str_end_character == LIT_CHAR_GRAVE_ACCENT && source_p[0] == LIT_CHAR_DOLLAR_SIGN && source_p + 1 < source_end_p && source_p[1] == LIT_CHAR_LEFT_BRACE) { + raw_length_adjust--; source_p++; break; } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ - if (*source_p >= LEXER_UTF8_4BYTE_START) + if (*source_p >= LIT_UTF8_4_BYTE_MARKER) { /* Processing 4 byte unicode sequence (even if it is * after a backslash). Always converted to two 3 byte @@ -828,6 +1135,9 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ length += 2 * 3; has_escape = true; source_p += 4; +#if ENABLED (JERRY_ES2015) + raw_length_adjust += 2; +#endif /* ENABLED (JERRY_ES2015) */ column++; continue; } @@ -837,19 +1147,21 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ /* Subtract -1 because column is increased below. */ column--; } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) else if (str_end_character == LIT_CHAR_GRAVE_ACCENT) { - /* Newline (without backslash) is part of the string. */ + /* Newline (without backslash) is part of the string. + Note: ECMAScript v6, 11.8.6.1 or are both normalized to */ if (*source_p == LIT_CHAR_CR) { + has_escape = true; source_p++; length++; if (source_p < source_end_p && *source_p == LIT_CHAR_LF) { source_p++; - length++; + raw_length_adjust--; } line++; column = 1; @@ -872,7 +1184,7 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ continue; } } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ else if (*source_p == LIT_CHAR_CR || *source_p == LIT_CHAR_LF || (*source_p == LEXER_NEWLINE_LS_PS_BYTE_1 && LEXER_NEWLINE_LS_PS_BYTE_23 (source_p))) @@ -894,17 +1206,24 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ } } +#if ENABLED (JERRY_ES2015) + if (opts & LEXER_STRING_RAW) + { + length = (size_t) ((source_p - string_start_p) + raw_length_adjust); + } +#endif /* ENABLED (JERRY_ES2015) */ + if (length > PARSER_MAXIMUM_STRING_LENGTH) { parser_raise_error (context_p, PARSER_ERR_STRING_TOO_LONG); } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) context_p->token.type = ((str_end_character != LIT_CHAR_GRAVE_ACCENT) ? LEXER_LITERAL : LEXER_TEMPLATE_LITERAL); -#else /* !ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#else /* !ENABLED (JERRY_ES2015) */ context_p->token.type = LEXER_LITERAL; -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Fill literal data. */ context_p->token.lit_location.char_p = string_start_p; @@ -917,6 +1236,28 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ context_p->column = (parser_line_counter_t) (column + 1); } /* lexer_parse_string */ +/** + * Parse octal number. + */ +static inline void +lexer_parse_octal_number (parser_context_t *context_p, /** context */ + const uint8_t **source_p) /**< current source position */ +{ + do + { + (*source_p)++; + } + while (*source_p < context_p->source_end_p + && *source_p[0] >= LIT_CHAR_0 + && *source_p[0] <= LIT_CHAR_7); + + if (*source_p < context_p->source_end_p + && (*source_p[0] == LIT_CHAR_8 || *source_p[0] == LIT_CHAR_9)) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_OCTAL_DIGIT); + } +} /* lexer_parse_octal_number */ + /** * Parse number. */ @@ -929,7 +1270,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ size_t length; context_p->token.type = LEXER_LITERAL; - context_p->token.literal_is_reserved = false; + context_p->token.keyword_type = LEXER_EOS; context_p->token.extra_value = LEXER_NUMBER_DECIMAL; context_p->token.lit_location.char_p = source_p; context_p->token.lit_location.type = LEXER_NUMBER_LITERAL; @@ -956,6 +1297,23 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ while (source_p < source_end_p && lit_char_is_hex_digit (source_p[0])); } +#if ENABLED (JERRY_ES2015) + else if (LEXER_TO_ASCII_LOWERCASE (source_p[1]) == LIT_CHAR_LOWERCASE_O) + { + context_p->token.extra_value = LEXER_NUMBER_OCTAL; + context_p->token.lit_location.char_p++; + context_p->source_p++; + source_p += 2; + + if (source_p >= source_end_p + || !lit_char_is_octal_digit (source_p[0])) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_OCTAL_DIGIT); + } + + lexer_parse_octal_number (context_p, &source_p); + } +#endif /* ENABLED (JERRY_ES2015) */ else if (source_p[1] >= LIT_CHAR_0 && source_p[1] <= LIT_CHAR_7) { @@ -966,26 +1324,35 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_OCTAL_NUMBER_NOT_ALLOWED); } - do - { - source_p++; - } - while (source_p < source_end_p - && source_p[0] >= LIT_CHAR_0 - && source_p[0] <= LIT_CHAR_7); - - if (source_p < source_end_p - && source_p[0] >= LIT_CHAR_8 - && source_p[0] <= LIT_CHAR_9) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_NUMBER); - } + lexer_parse_octal_number (context_p, &source_p); } else if (source_p[1] >= LIT_CHAR_8 && source_p[1] <= LIT_CHAR_9) { parser_raise_error (context_p, PARSER_ERR_INVALID_NUMBER); } +#if ENABLED (JERRY_ES2015) + else if (LEXER_TO_ASCII_LOWERCASE (source_p[1]) == LIT_CHAR_LOWERCASE_B) + { + context_p->token.extra_value = LEXER_NUMBER_BINARY; + context_p->token.lit_location.char_p++; + context_p->source_p++; + source_p += 2; + + if (source_p >= source_end_p + || !lit_char_is_binary_digit (source_p[0])) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_BIN_DIGIT); + } + + do + { + source_p++; + } + while (source_p < source_end_p + && lit_char_is_binary_digit (source_p[0])); + } +#endif /* ENABLED (JERRY_ES2015) */ else { can_be_float = true; @@ -1046,12 +1413,6 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ } } - if (source_p < source_end_p - && (lit_char_is_identifier_start (source_p) || source_p[0] == LIT_CHAR_BACKSLASH)) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_AFTER_NUMBER); - } - length = (size_t) (source_p - context_p->source_p); if (length > PARSER_MAXIMUM_IDENT_LENGTH) { @@ -1061,6 +1422,11 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ context_p->token.lit_location.length = (prop_length_t) length; PARSER_PLUS_EQUAL_LC (context_p->column, length); context_p->source_p = source_p; + + if (source_p < source_end_p && lexer_parse_identifier (context_p, LEXER_PARSE_CHECK_START_AND_RETURN)) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_AFTER_NUMBER); + } } /* lexer_parse_number */ /** @@ -1070,7 +1436,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ * @param type1 type */ #define LEXER_TYPE_A_TOKEN(char1, type1) \ - case (uint8_t) (char1) : \ + case (uint8_t) (char1): \ { \ context_p->token.type = (type1); \ length = 1; \ @@ -1086,7 +1452,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ * @param type2 type of the second character */ #define LEXER_TYPE_B_TOKEN(char1, type1, char2, type2) \ - case (uint8_t) (char1) : \ + case (uint8_t) (char1): \ { \ if (length >= 2 && context_p->source_p[1] == (uint8_t) (char2)) \ { \ @@ -1111,7 +1477,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ * @param type3 type of the third character */ #define LEXER_TYPE_C_TOKEN(char1, type1, char2, type2, char3, type3) \ - case (uint8_t) (char1) : \ + case (uint8_t) (char1): \ { \ if (length >= 2) \ { \ @@ -1155,10 +1521,8 @@ lexer_next_token (parser_context_t *context_p) /**< context */ return; } - if (lit_char_is_identifier_start (context_p->source_p) - || context_p->source_p[0] == LIT_CHAR_BACKSLASH) + if (lexer_parse_identifier (context_p, LEXER_PARSE_CHECK_KEYWORDS)) { - lexer_parse_identifier (context_p, true); return; } @@ -1188,7 +1552,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */ return; } -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (length >= 3 && context_p->source_p[1] == LIT_CHAR_DOT && context_p->source_p[2] == LIT_CHAR_DOT) @@ -1197,7 +1561,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */ length = 3; break; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ context_p->token.type = LEXER_DOT; length = 1; @@ -1301,14 +1665,14 @@ lexer_next_token (parser_context_t *context_p) /**< context */ break; } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) if (context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN) { context_p->token.type = LEXER_ARROW; length = 2; break; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ } context_p->token.type = LEXER_ASSIGN; @@ -1342,8 +1706,39 @@ lexer_next_token (parser_context_t *context_p) /**< context */ LEXER_TYPE_C_TOKEN (LIT_CHAR_MINUS, LEXER_SUBTRACT, LIT_CHAR_EQUALS, LEXER_ASSIGN_SUBTRACT, LIT_CHAR_MINUS, LEXER_DECREASE) - LEXER_TYPE_B_TOKEN (LIT_CHAR_ASTERISK, LEXER_MULTIPLY, LIT_CHAR_EQUALS, - LEXER_ASSIGN_MULTIPLY) + case (uint8_t) LIT_CHAR_ASTERISK: + { + if (length >= 2) + { + if (context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS) + { + context_p->token.type = LEXER_ASSIGN_MULTIPLY; + length = 2; + break; + } + +#if ENABLED (JERRY_ES2015) + if (context_p->source_p[1] == (uint8_t) LIT_CHAR_ASTERISK) + { + if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS) + { + context_p->token.type = LEXER_ASSIGN_EXPONENTIATION; + length = 3; + break; + } + + context_p->token.type = LEXER_EXPONENTIATION; + length = 2; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + context_p->token.type = LEXER_MULTIPLY; + length = 1; + break; + } + LEXER_TYPE_B_TOKEN (LIT_CHAR_SLASH, LEXER_DIVIDE, LIT_CHAR_EQUALS, LEXER_ASSIGN_DIVIDE) LEXER_TYPE_B_TOKEN (LIT_CHAR_PERCENT, LEXER_MODULO, LIT_CHAR_EQUALS, @@ -1363,11 +1758,11 @@ lexer_next_token (parser_context_t *context_p) /**< context */ case LIT_CHAR_SINGLE_QUOTE: case LIT_CHAR_DOUBLE_QUOTE: -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) case LIT_CHAR_GRAVE_ACCENT: -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ { - lexer_parse_string (context_p); + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); return; } @@ -1387,7 +1782,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */ #undef LEXER_TYPE_D_TOKEN /** - * Checks whether the next token is the specified character. + * Checks whether the next token starts with the specified character. * * @return true - if the next is the specified character * false - otherwise @@ -1406,7 +1801,98 @@ lexer_check_next_character (parser_context_t *context_p, /**< context */ && context_p->source_p[0] == (uint8_t) character); } /* lexer_check_next_character */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +/** + * Checks whether the next token starts with either specified characters. + * + * @return true - if the next is the specified character + * false - otherwise + */ +bool +lexer_check_next_characters (parser_context_t *context_p, /**< context */ + lit_utf8_byte_t character1, /**< first alternative character */ + lit_utf8_byte_t character2) /**< second alternative character */ +{ + if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)) + { + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + } + + return (context_p->source_p < context_p->source_end_p + && (context_p->source_p[0] == (uint8_t) character1 + || context_p->source_p[0] == (uint8_t) character2)); +} /* lexer_check_next_characters */ + +/** + * Consumes the next character. The character cannot be a white space. + * + * @return consumed character + */ +inline uint8_t JERRY_ATTR_ALWAYS_INLINE +lexer_consume_next_character (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->source_p < context_p->source_end_p); + + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; + + PARSER_PLUS_EQUAL_LC (context_p->column, 1); + return *context_p->source_p++; +} /* lexer_consume_next_character */ + +/** + * Checks whether the next character can be the start of a post primary expression + * + * Note: + * the result is not precise, but this inprecise result + * has no side effects for negating number literals + * + * @return true if the next character can be the start of a post primary expression + */ +bool +lexer_check_post_primary_exp (parser_context_t *context_p) /**< context */ +{ + if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)) + { + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + } + + if (context_p->source_p >= context_p->source_end_p) + { + return false; + } + + switch (context_p->source_p[0]) + { + case LIT_CHAR_DOT: + case LIT_CHAR_LEFT_PAREN: + case LIT_CHAR_LEFT_SQUARE: +#if ENABLED (JERRY_ES2015) + case LIT_CHAR_GRAVE_ACCENT: +#endif /* ENABLED (JERRY_ES2015) */ + { + return true; + } + case LIT_CHAR_PLUS: + case LIT_CHAR_MINUS: + { + return (!(context_p->token.flags & LEXER_WAS_NEWLINE) + && context_p->source_p + 1 < context_p->source_end_p + && context_p->source_p[1] == context_p->source_p[0]); + } +#if ENABLED (JERRY_ES2015) + case LIT_CHAR_ASTERISK: + { + return (context_p->source_p + 1 < context_p->source_end_p + && context_p->source_p[1] == (uint8_t) LIT_CHAR_ASTERISK); + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + return false; +} /* lexer_check_post_primary_exp */ + +#if ENABLED (JERRY_ES2015) /** * Checks whether the next token is a type used for detecting arrow functions. @@ -1428,21 +1914,449 @@ lexer_check_arrow (parser_context_t *context_p) /**< context */ && context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN); } /* lexer_check_arrow */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +/** + * Checks whether the next token is a comma or equal sign. + * + * @return true if the next token is a comma or equal sign + */ +bool +lexer_check_arrow_param (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.flags & LEXER_NO_SKIP_SPACES); + + if (context_p->source_p >= context_p->source_end_p) + { + return false; + } + + if (context_p->source_p[0] == LIT_CHAR_COMMA) + { + return true; + } + + if (context_p->source_p[0] != LIT_CHAR_EQUALS) + { + return false; + } + + return (context_p->source_p + 1 >= context_p->source_end_p + || context_p->source_p[1] != LIT_CHAR_EQUALS); +} /* lexer_check_arrow_param */ /** - * Search or append the string to the literal pool. + * Checks whether the yield expression has no argument. + * + * @return true if it has no argument */ -static void -lexer_process_char_literal (parser_context_t *context_p, /**< context */ - const uint8_t *char_p, /**< characters */ - size_t length, /**< length of string */ - uint8_t literal_type, /**< final literal type */ - bool has_escape) /**< has escape sequences */ +bool +lexer_check_yield_no_arg (parser_context_t *context_p) /**< context */ { + if (context_p->token.flags & LEXER_WAS_NEWLINE) + { + return true; + } + + switch (context_p->token.type) + { + case LEXER_RIGHT_BRACE: + case LEXER_RIGHT_PAREN: + case LEXER_RIGHT_SQUARE: + case LEXER_COMMA: + case LEXER_COLON: + case LEXER_SEMICOLON: + case LEXER_EOS: + { + return true; + } + default: + { + return false; + } + } +} /* lexer_check_yield_no_arg */ + +/** + * Checks whether the next token is a multiply and consumes it. + * + * @return true if the next token is a multiply + */ +bool +lexer_consume_generator (parser_context_t *context_p) /**< context */ +{ + if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)) + { + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + } + + if (context_p->source_p >= context_p->source_end_p + || context_p->source_p[0] != LIT_CHAR_ASTERISK + || (context_p->source_p + 1 < context_p->source_end_p + && (context_p->source_p[1] == LIT_CHAR_EQUALS || context_p->source_p[1] == LIT_CHAR_ASTERISK))) + { + return false; + } + + lexer_consume_next_character (context_p); + context_p->token.type = LEXER_MULTIPLY; + return true; +} /* lexer_consume_generator */ + +/** + * Update await / yield keywords after an arrow function with expression. + */ +void +lexer_update_await_yield (parser_context_t *context_p, /**< context */ + uint32_t status_flags) /**< parser status flags after restore */ +{ + if (!(status_flags & PARSER_IS_STRICT)) + { + if (status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + if (context_p->token.type == LEXER_LITERAL + && context_p->token.keyword_type == LEXER_KEYW_YIELD) + { + context_p->token.type = LEXER_KEYW_YIELD; + } + } + else + { + if (context_p->token.type == LEXER_KEYW_YIELD) + { + JERRY_ASSERT (context_p->token.keyword_type == LEXER_KEYW_YIELD); + context_p->token.type = LEXER_LITERAL; + } + } + } + + if (!(context_p->global_status_flags & ECMA_PARSE_MODULE)) + { + if (status_flags & PARSER_IS_ASYNC_FUNCTION) + { + if (context_p->token.type == LEXER_LITERAL + && context_p->token.keyword_type == LEXER_KEYW_AWAIT) + { + context_p->token.type = LEXER_KEYW_AWAIT; + } + } + else + { + if (context_p->token.type == LEXER_KEYW_AWAIT) + { + JERRY_ASSERT (context_p->token.keyword_type == LEXER_KEYW_AWAIT); + context_p->token.type = LEXER_LITERAL; + } + } + } +} /* lexer_update_await_yield */ + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Convert an ident with escapes to a utf8 string. + */ +void +lexer_convert_ident_to_cesu8 (uint8_t *destination_p, /**< destination string */ + const uint8_t *source_p, /**< source string */ + prop_length_t length) /**< length of destination string */ +{ + const uint8_t *destination_end_p = destination_p + length; + + JERRY_ASSERT (length <= PARSER_MAXIMUM_IDENT_LENGTH); + + do + { + if (*source_p == LIT_CHAR_BACKSLASH) + { + source_p += 2; + destination_p += lit_code_point_to_cesu8_bytes (destination_p, + lexer_unchecked_hex_to_character (&source_p)); + continue; + } + +#if ENABLED (JERRY_ES2015) + if (*source_p >= LIT_UTF8_4_BYTE_MARKER) + { + lit_four_byte_utf8_char_to_cesu8 (destination_p, source_p); + + destination_p += 6; + source_p += 4; + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + + *destination_p++ = *source_p++; + } + while (destination_p < destination_end_p); +} /* lexer_convert_ident_to_cesu8 */ + +/** + * Convert literal to character sequence + */ +const uint8_t * +lexer_convert_literal_to_chars (parser_context_t *context_p, /**< context */ + const lexer_lit_location_t *literal_p, /**< literal location */ + uint8_t *local_byte_array_p, /**< local byte array to store chars */ + lexer_string_options_t opts) /**< options */ +{ + JERRY_ASSERT (context_p->u.allocated_buffer_p == NULL); + + if (!literal_p->has_escape) + { + return literal_p->char_p; + } + + uint8_t *destination_start_p; + if (literal_p->length > LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE) + { + context_p->u.allocated_buffer_p = (uint8_t *) parser_malloc_local (context_p, literal_p->length); + context_p->allocated_buffer_size = literal_p->length; + destination_start_p = context_p->u.allocated_buffer_p; + } + else + { + destination_start_p = local_byte_array_p; + } + + if (literal_p->type == LEXER_IDENT_LITERAL) + { + lexer_convert_ident_to_cesu8 (destination_start_p, literal_p->char_p, literal_p->length); + return destination_start_p; + } + + const uint8_t *source_p = literal_p->char_p; + uint8_t *destination_p = destination_start_p; + + uint8_t str_end_character = source_p[-1]; + +#if ENABLED (JERRY_ES2015) + if (str_end_character == LIT_CHAR_RIGHT_BRACE) + { + str_end_character = LIT_CHAR_GRAVE_ACCENT; + } + + bool is_raw = (opts & LEXER_STRING_RAW) != 0; +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (opts); + bool is_raw = false; +#endif /* ENABLED (JERRY_ES2015) */ + + while (true) + { + if (*source_p == str_end_character) + { + break; + } + + if (*source_p == LIT_CHAR_BACKSLASH && !is_raw) + { + uint8_t conv_character; + + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + + /* Newline is ignored. */ + if (*source_p == LIT_CHAR_CR) + { + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + + if (*source_p == LIT_CHAR_LF) + { + source_p++; + } + continue; + } + else if (*source_p == LIT_CHAR_LF) + { + source_p++; + continue; + } + else if (*source_p == LEXER_NEWLINE_LS_PS_BYTE_1 && LEXER_NEWLINE_LS_PS_BYTE_23 (source_p)) + { + source_p += 3; + continue; + } + + if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_3) + { + lit_code_point_t octal_number = (uint32_t) (*source_p - LIT_CHAR_0); + + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + + if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) + { + octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + + if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) + { + octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + } + } + + destination_p += lit_code_point_to_cesu8_bytes (destination_p, octal_number); + continue; + } + + if (*source_p >= LIT_CHAR_4 && *source_p <= LIT_CHAR_7) + { + uint32_t octal_number = (uint32_t) (*source_p - LIT_CHAR_0); + + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + + if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) + { + octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + } + + *destination_p++ = (uint8_t) octal_number; + continue; + } + + if (*source_p == LIT_CHAR_LOWERCASE_X || *source_p == LIT_CHAR_LOWERCASE_U) + { + source_p++; + destination_p += lit_code_point_to_cesu8_bytes (destination_p, + lexer_unchecked_hex_to_character (&source_p)); + continue; + } + + conv_character = *source_p; + switch (*source_p) + { + case LIT_CHAR_LOWERCASE_B: + { + conv_character = 0x08; + break; + } + case LIT_CHAR_LOWERCASE_T: + { + conv_character = 0x09; + break; + } + case LIT_CHAR_LOWERCASE_N: + { + conv_character = 0x0a; + break; + } + case LIT_CHAR_LOWERCASE_V: + { + conv_character = 0x0b; + break; + } + case LIT_CHAR_LOWERCASE_F: + { + conv_character = 0x0c; + break; + } + case LIT_CHAR_LOWERCASE_R: + { + conv_character = 0x0d; + break; + } + } + + if (conv_character != *source_p) + { + *destination_p++ = conv_character; + source_p++; + continue; + } + } +#if ENABLED (JERRY_ES2015) + else if (str_end_character == LIT_CHAR_GRAVE_ACCENT) + { + if (source_p[0] == LIT_CHAR_DOLLAR_SIGN + && source_p[1] == LIT_CHAR_LEFT_BRACE) + { + source_p++; + JERRY_ASSERT (source_p < context_p->source_end_p); + break; + } + if (*source_p == LIT_CHAR_CR) + { + *destination_p++ = LIT_CHAR_LF; + source_p++; + if (*source_p != str_end_character + && *source_p == LIT_CHAR_LF) + { + source_p++; + } + continue; + } + if ((*source_p == LIT_CHAR_BACKSLASH) && is_raw) + { + JERRY_ASSERT (source_p + 1 < context_p->source_end_p); + if ((*(source_p + 1) == LIT_CHAR_GRAVE_ACCENT) || (*(source_p + 1) == LIT_CHAR_BACKSLASH)) + { + *destination_p++ = *source_p++; + *destination_p++ = *source_p++; + continue; + } + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (*source_p >= LIT_UTF8_4_BYTE_MARKER) + { + /* Processing 4 byte unicode sequence (even if it is + * after a backslash). Always converted to two 3 byte + * long sequence. */ + lit_four_byte_utf8_char_to_cesu8 (destination_p, source_p); + + destination_p += 6; + source_p += 4; + continue; + } + + *destination_p++ = *source_p++; + + /* There is no need to check the source_end_p + * since the string is terminated by a quotation mark. */ + while (IS_UTF8_INTERMEDIATE_OCTET (*source_p)) + { + *destination_p++ = *source_p++; + } + } + + JERRY_ASSERT (destination_p == destination_start_p + literal_p->length); + + return destination_start_p; +} /* lexer_convert_literal_to_chars */ + +/** + * Construct a literal object from an identifier. + */ +void +lexer_construct_literal_object (parser_context_t *context_p, /**< context */ + const lexer_lit_location_t *lit_location_p, /**< literal location */ + uint8_t literal_type) /**< final literal type */ +{ + uint8_t local_byte_array[LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE]; + + const uint8_t *char_p = lexer_convert_literal_to_chars (context_p, + lit_location_p, + local_byte_array, + LEXER_STRING_NO_OPTS); + + size_t length = lit_location_p->length; parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; uint32_t literal_index = 0; + bool search_scope_stack = (literal_type == LEXER_IDENT_LITERAL); + + if (JERRY_UNLIKELY (literal_type == LEXER_NEW_IDENT_LITERAL)) + { + literal_type = LEXER_IDENT_LITERAL; + } JERRY_ASSERT (literal_type == LEXER_IDENT_LITERAL || literal_type == LEXER_STRING_LITERAL); @@ -1460,7 +2374,29 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */ { context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) literal_index; - literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_UNUSED_IDENT); + + parser_free_allocated_buffer (context_p); + + if (search_scope_stack) + { + parser_scope_stack_t *scope_stack_start_p = context_p->scope_stack_p; + parser_scope_stack_t *scope_stack_p = scope_stack_start_p + context_p->scope_stack_top; + + while (scope_stack_p > scope_stack_start_p) + { + scope_stack_p--; + + if (scope_stack_p->map_from == literal_index) + { + JERRY_ASSERT (scanner_decode_map_to (scope_stack_p) >= PARSER_REGISTER_START + || (literal_p->status_flags & LEXER_FLAG_USED)); + context_p->lit_object.index = scanner_decode_map_to (scope_stack_p); + return; + } + } + + literal_p->status_flags |= LEXER_FLAG_USED; + } return; } @@ -1474,343 +2410,46 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); } - if (length == 0) - { - has_escape = false; - } - literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); literal_p->prop.length = (prop_length_t) length; literal_p->type = literal_type; - literal_p->status_flags = has_escape ? 0 : LEXER_FLAG_SOURCE_PTR; - if (has_escape) + uint8_t status_flags = LEXER_FLAG_SOURCE_PTR; + + if (length > 0 && char_p == local_byte_array) { literal_p->u.char_p = (uint8_t *) jmem_heap_alloc_block (length); memcpy ((uint8_t *) literal_p->u.char_p, char_p, length); + status_flags = 0; } else { literal_p->u.char_p = char_p; + + /* Buffer is taken over when a new literal is constructed. */ + if (context_p->u.allocated_buffer_p != NULL) + { + JERRY_ASSERT (char_p == context_p->u.allocated_buffer_p); + + context_p->u.allocated_buffer_p = NULL; + status_flags = 0; + } } + if (search_scope_stack) + { + status_flags |= LEXER_FLAG_USED; + } + + literal_p->status_flags = status_flags; + context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) literal_index; context_p->literal_count++; -} /* lexer_process_char_literal */ -/** - * Maximum local buffer size for identifiers which contains escape sequences. - */ -#define LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE 48 - -/** - * Construct a literal object from an identifier. - */ -void -lexer_construct_literal_object (parser_context_t *context_p, /**< context */ - lexer_lit_location_t *literal_p, /**< literal location */ - uint8_t literal_type) /**< final literal type */ -{ - uint8_t *destination_start_p; - const uint8_t *source_p; - uint8_t local_byte_array[LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE]; - - JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL - || literal_p->type == LEXER_STRING_LITERAL); - JERRY_ASSERT (context_p->allocated_buffer_p == NULL); - - destination_start_p = local_byte_array; - source_p = literal_p->char_p; - - if (literal_p->has_escape) - { - uint8_t *destination_p; - - if (literal_p->length > LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE) - { - destination_start_p = (uint8_t *) parser_malloc_local (context_p, literal_p->length); - context_p->allocated_buffer_p = destination_start_p; - context_p->allocated_buffer_size = literal_p->length; - } - - destination_p = destination_start_p; - - if (literal_p->type == LEXER_IDENT_LITERAL) - { - const uint8_t *source_end_p = context_p->source_end_p; - - JERRY_ASSERT (literal_p->length <= PARSER_MAXIMUM_IDENT_LENGTH); - - do - { - if (*source_p == LIT_CHAR_BACKSLASH) - { - destination_p += lit_char_to_utf8_bytes (destination_p, - lexer_unchecked_hex_to_character (source_p + 2, 4)); - source_p += 6; - continue; - } - - *destination_p++ = *source_p++; - - while (source_p < source_end_p - && IS_UTF8_INTERMEDIATE_OCTET (*source_p)) - { - *destination_p++ = *source_p++; - } - } - while (source_p < source_end_p - && (lit_char_is_identifier_part (source_p) || *source_p == LIT_CHAR_BACKSLASH)); - - JERRY_ASSERT (destination_p == destination_start_p + literal_p->length); - } - else - { - uint8_t str_end_character = source_p[-1]; - -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - if (str_end_character == LIT_CHAR_RIGHT_BRACE) - { - str_end_character = LIT_CHAR_GRAVE_ACCENT; - } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ - - while (true) - { - if (*source_p == str_end_character) - { - break; - } - - if (*source_p == LIT_CHAR_BACKSLASH) - { - uint8_t conv_character; - - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - - /* Newline is ignored. */ - if (*source_p == LIT_CHAR_CR) - { - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - - if (*source_p == LIT_CHAR_LF) - { - source_p++; - } - continue; - } - else if (*source_p == LIT_CHAR_LF) - { - source_p++; - continue; - } - else if (*source_p == LEXER_NEWLINE_LS_PS_BYTE_1 && LEXER_NEWLINE_LS_PS_BYTE_23 (source_p)) - { - source_p += 3; - continue; - } - - if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_3) - { - uint32_t octal_number = (uint32_t) (*source_p - LIT_CHAR_0); - - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - - if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) - { - octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - - if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) - { - octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - } - } - - destination_p += lit_char_to_utf8_bytes (destination_p, (uint16_t) octal_number); - continue; - } - - if (*source_p >= LIT_CHAR_4 && *source_p <= LIT_CHAR_7) - { - uint32_t octal_number = (uint32_t) (*source_p - LIT_CHAR_0); - - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - - if (*source_p >= LIT_CHAR_0 && *source_p <= LIT_CHAR_7) - { - octal_number = octal_number * 8 + (uint32_t) (*source_p - LIT_CHAR_0); - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - } - - *destination_p++ = (uint8_t) octal_number; - continue; - } - - if (*source_p == LIT_CHAR_LOWERCASE_X || *source_p == LIT_CHAR_LOWERCASE_U) - { - int hex_part_length = (*source_p == LIT_CHAR_LOWERCASE_X) ? 2 : 4; - JERRY_ASSERT (source_p + 1 + hex_part_length <= context_p->source_end_p); - - destination_p += lit_char_to_utf8_bytes (destination_p, - lexer_unchecked_hex_to_character (source_p + 1, - hex_part_length)); - source_p += hex_part_length + 1; - continue; - } - - conv_character = *source_p; - switch (*source_p) - { - case LIT_CHAR_LOWERCASE_B: - { - conv_character = 0x08; - break; - } - case LIT_CHAR_LOWERCASE_T: - { - conv_character = 0x09; - break; - } - case LIT_CHAR_LOWERCASE_N: - { - conv_character = 0x0a; - break; - } - case LIT_CHAR_LOWERCASE_V: - { - conv_character = 0x0b; - break; - } - case LIT_CHAR_LOWERCASE_F: - { - conv_character = 0x0c; - break; - } - case LIT_CHAR_LOWERCASE_R: - { - conv_character = 0x0d; - break; - } - } - - if (conv_character != *source_p) - { - *destination_p++ = conv_character; - source_p++; - continue; - } - } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - else if (str_end_character == LIT_CHAR_GRAVE_ACCENT - && source_p[0] == LIT_CHAR_DOLLAR_SIGN - && source_p[1] == LIT_CHAR_LEFT_BRACE) - { - source_p++; - JERRY_ASSERT (source_p < context_p->source_end_p); - break; - } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ - - if (*source_p >= LEXER_UTF8_4BYTE_START) - { - /* Processing 4 byte unicode sequence (even if it is - * after a backslash). Always converted to two 3 byte - * long sequence. */ - - uint32_t character = ((((uint32_t) source_p[0]) & 0x7) << 18); - character |= ((((uint32_t) source_p[1]) & LIT_UTF8_LAST_6_BITS_MASK) << 12); - character |= ((((uint32_t) source_p[2]) & LIT_UTF8_LAST_6_BITS_MASK) << 6); - character |= (((uint32_t) source_p[3]) & LIT_UTF8_LAST_6_BITS_MASK); - - JERRY_ASSERT (character >= 0x10000); - character -= 0x10000; - destination_p += lit_char_to_utf8_bytes (destination_p, - (ecma_char_t) (0xd800 | (character >> 10))); - destination_p += lit_char_to_utf8_bytes (destination_p, - (ecma_char_t) (0xdc00 | (character & LIT_UTF16_LAST_10_BITS_MASK))); - source_p += 4; - continue; - } - - *destination_p++ = *source_p++; - - /* There is no need to check the source_end_p - * since the string is terminated by a quotation mark. */ - while (IS_UTF8_INTERMEDIATE_OCTET (*source_p)) - { - *destination_p++ = *source_p++; - } - } - - JERRY_ASSERT (destination_p == destination_start_p + literal_p->length); - } - - source_p = destination_start_p; - } - - lexer_process_char_literal (context_p, - source_p, - literal_p->length, - literal_type, - literal_p->has_escape); - - JERRY_ASSERT (literal_type == context_p->lit_object.literal_p->type); - - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY; - - if (literal_type == LEXER_IDENT_LITERAL - && (context_p->status_flags & PARSER_INSIDE_WITH)) - { - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - } - - if (literal_p->length == 4 - && source_p[0] == LIT_CHAR_LOWERCASE_E - && source_p[3] == LIT_CHAR_LOWERCASE_L - && source_p[1] == LIT_CHAR_LOWERCASE_V - && source_p[2] == LIT_CHAR_LOWERCASE_A) - { - context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL; - } - - if (literal_p->length == 9 - && source_p[0] == LIT_CHAR_LOWERCASE_A - && source_p[8] == LIT_CHAR_LOWERCASE_S - && memcmp (source_p + 1, "rgument", 7) == 0) - { - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS; - if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED) - && literal_type == LEXER_IDENT_LITERAL) - { - context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED; - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - } - } - - if (destination_start_p != local_byte_array) - { - JERRY_ASSERT (context_p->allocated_buffer_p == destination_start_p); - - context_p->allocated_buffer_p = NULL; - parser_free_local (destination_start_p, - context_p->allocated_buffer_size); - } - - JERRY_ASSERT (context_p->allocated_buffer_p == NULL); + JERRY_ASSERT (context_p->u.allocated_buffer_p == NULL); } /* lexer_construct_literal_object */ -#undef LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE - /** * Construct a number object. * @@ -1827,7 +2466,7 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ uint32_t literal_index = 0; prop_length_t length = context_p->token.lit_location.length; - if (context_p->token.extra_value != LEXER_NUMBER_OCTAL) + if (context_p->token.extra_value < LEXER_NUMBER_OCTAL) { num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length); @@ -1836,12 +2475,20 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ { const uint8_t *src_p = context_p->token.lit_location.char_p; const uint8_t *src_end_p = src_p + length - 1; + ecma_number_t multiplier = 8.0; + +#if ENABLED (JERRY_ES2015) + if (context_p->token.extra_value == LEXER_NUMBER_BINARY) + { + multiplier = 2.0; + } +#endif /* ENABLED (JERRY_ES2015) */ num = 0; do { src_p++; - num = num * 8 + (ecma_number_t) (*src_p - LIT_CHAR_0); + num = num * multiplier + (ecma_number_t) (*src_p - LIT_CHAR_0); } while (src_p < src_end_p); } @@ -1874,7 +2521,6 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ { context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) literal_index; - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY; return false; } @@ -1896,7 +2542,6 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) literal_index; - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY; context_p->literal_count++; return false; @@ -2000,9 +2645,11 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); } - if (context_p->status_flags & (PARSER_RESOLVE_BASE_FOR_CALLS | PARSER_INSIDE_WITH)) + parser_flush_cbc (context_p); + + if (context_p->status_flags & PARSER_INSIDE_WITH) { - extra_status_flags |= PARSER_RESOLVE_BASE_FOR_CALLS; + extra_status_flags |= PARSER_INSIDE_WITH; } literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); @@ -2012,7 +2659,7 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */ result_index = context_p->literal_count; context_p->literal_count++; -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) if (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION)) { compiled_code_p = parser_parse_function (context_p, extra_status_flags); @@ -2021,9 +2668,9 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */ { compiled_code_p = parser_parse_arrow_function (context_p, extra_status_flags); } -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#else /* !ENABLED (JERRY_ES2015) */ compiled_code_p = parser_parse_function (context_p, extra_status_flags); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ literal_p->u.bytecode_p = compiled_code_p; literal_p->type = LEXER_FUNCTION_LITERAL; @@ -2144,6 +2791,14 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ { flag = RE_FLAG_MULTILINE; } + else if (source_p[0] == LIT_CHAR_LOWERCASE_U) + { + flag = RE_FLAG_UNICODE; + } + else if (source_p[0] == LIT_CHAR_LOWERCASE_Y) + { + flag = RE_FLAG_STICKY; + } if (flag == 0) { @@ -2160,15 +2815,14 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ column++; } - if (source_p < source_end_p - && lit_char_is_identifier_part (source_p)) + context_p->source_p = source_p; + context_p->column = column; + + if (source_p < source_end_p && lexer_parse_identifier (context_p, LEXER_PARSE_CHECK_PART_AND_RETURN)) { parser_raise_error (context_p, PARSER_ERR_UNKNOWN_REGEXP_FLAG); } - context_p->source_p = source_p; - context_p->column = column; - length = (lit_utf8_size_t) (regex_end_p - regex_start_p); if (length > PARSER_MAXIMUM_STRING_LENGTH) { @@ -2196,9 +2850,6 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ context_p->literal_count++; /* Compile the RegExp literal and store the RegExp bytecode pointer */ - const re_compiled_code_t *re_bytecode_p = NULL; - ecma_value_t completion_value; - ecma_string_t *pattern_str_p = NULL; if (lit_is_valid_cesu8_string (regex_start_p, length)) @@ -2211,19 +2862,11 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ pattern_str_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (regex_start_p, length); } - - completion_value = re_compile_bytecode (&re_bytecode_p, - pattern_str_p, - current_flags); + re_compiled_code_t *re_bytecode_p = re_compile_bytecode (pattern_str_p, current_flags); ecma_deref_ecma_string (pattern_str_p); - bool is_throw = ECMA_IS_VALUE_ERROR (completion_value) != 0; - - ecma_free_value (completion_value); - - if (is_throw) + if (JERRY_UNLIKELY (re_bytecode_p == NULL)) { - ecma_free_value (JERRY_CONTEXT (error_value)); parser_raise_error (context_p, PARSER_ERR_INVALID_REGEXP); } @@ -2231,12 +2874,11 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ literal_p->u.bytecode_p = (ecma_compiled_code_t *) re_bytecode_p; context_p->token.type = LEXER_LITERAL; - context_p->token.literal_is_reserved = false; + context_p->token.keyword_type = LEXER_EOS; context_p->token.lit_location.type = LEXER_REGEXP_LITERAL; context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) (context_p->literal_count - 1); - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY; #else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ JERRY_UNUSED (parse_only); parser_raise_error (context_p, PARSER_ERR_UNSUPPORTED_REGEXP); @@ -2251,43 +2893,37 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */ uint8_t literal_type) /**< literal type */ { JERRY_ASSERT (literal_type == LEXER_STRING_LITERAL - || literal_type == LEXER_IDENT_LITERAL); + || literal_type == LEXER_IDENT_LITERAL + || literal_type == LEXER_NEW_IDENT_LITERAL); lexer_skip_spaces (context_p); context_p->token.line = context_p->line; context_p->token.column = context_p->column; if (context_p->source_p < context_p->source_end_p - && (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH)) + && lexer_parse_identifier (context_p, (literal_type != LEXER_STRING_LITERAL ? LEXER_PARSE_CHECK_KEYWORDS + : LEXER_PARSE_NO_OPTS))) { - lexer_parse_identifier (context_p, literal_type != LEXER_STRING_LITERAL); - if (context_p->token.type == LEXER_LITERAL) { + JERRY_ASSERT (context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + lexer_construct_literal_object (context_p, &context_p->token.lit_location, literal_type); - if (literal_type == LEXER_IDENT_LITERAL - && (context_p->status_flags & PARSER_IS_STRICT) - && context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) + if (literal_type != LEXER_STRING_LITERAL + && (context_p->status_flags & PARSER_IS_STRICT)) { - parser_error_t error; - - if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_EVAL) + if (context_p->token.keyword_type == LEXER_KEYW_EVAL) { - error = PARSER_ERR_EVAL_NOT_ALLOWED; + parser_raise_error (context_p, PARSER_ERR_EVAL_NOT_ALLOWED); } - else + else if (context_p->token.keyword_type == LEXER_KEYW_ARGUMENTS) { - JERRY_ASSERT (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS); - error = PARSER_ERR_ARGUMENTS_NOT_ALLOWED; + parser_raise_error (context_p, PARSER_ERR_ARGUMENTS_NOT_ALLOWED); } - - parser_raise_error (context_p, error); } - - context_p->token.lit_location.type = literal_type; return; } } @@ -2297,17 +2933,24 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */ /* When parsing default exports for modules, it is not required by functions or classes to have identifiers. * In this case we use a synthetic name for them. */ context_p->token.type = LEXER_LITERAL; - context_p->token.literal_is_reserved = false; - context_p->token.lit_location.type = LEXER_IDENT_LITERAL; - context_p->token.lit_location.has_escape = false; - lexer_construct_literal_object (context_p, - (lexer_lit_location_t *) &lexer_default_literal, - lexer_default_literal.type); + context_p->token.keyword_type = LEXER_EOS; + context_p->token.lit_location = lexer_default_literal; + lexer_construct_literal_object (context_p, &context_p->token.lit_location, literal_type); context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC); return; } -#endif +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_KEYW_YIELD) + { + parser_raise_error (context_p, PARSER_ERR_YIELD_NOT_ALLOWED); + } + if (context_p->token.type == LEXER_KEYW_AWAIT) + { + parser_raise_error (context_p, PARSER_ERR_AWAIT_NOT_ALLOWED); + } +#endif /* ENABLED (JERRY_ES2015) */ parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } /* lexer_expect_identifier */ @@ -2320,203 +2963,360 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ { lexer_skip_spaces (context_p); -#if ENABLED (JERRY_ES2015_CLASS) + if (context_p->source_p >= context_p->source_end_p) + { + parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); + } + +#if ENABLED (JERRY_ES2015) int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD) && !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) && (context_p->token.type != LEXER_KEYW_STATIC)); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ context_p->token.line = context_p->line; context_p->token.column = context_p->column; + bool create_literal_object = false; - if (context_p->source_p < context_p->source_end_p) + if (lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS)) { - bool create_literal_object = false; - - if (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH) + if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN))) { - lexer_parse_identifier (context_p, false); + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); - if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) - && context_p->token.lit_location.length == 3) + if (context_p->source_p < context_p->source_end_p +#if ENABLED (JERRY_ES2015) + && context_p->source_p[0] != LIT_CHAR_COMMA + && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE + && context_p->source_p[0] != LIT_CHAR_LEFT_PAREN +#endif /* ENABLED (JERRY_ES2015) */ + && context_p->source_p[0] != LIT_CHAR_COLON) { - lexer_skip_spaces (context_p); - context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); - - if (context_p->source_p < context_p->source_end_p -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - && context_p->source_p[0] != LIT_CHAR_COMMA - && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - && context_p->source_p[0] != LIT_CHAR_COLON) + if (lexer_compare_literal_to_string (context_p, "get", 3)) { - if (lexer_compare_literal_to_string (context_p, "get", 3)) - { - context_p->token.type = LEXER_PROPERTY_GETTER; - return; - } - else if (lexer_compare_literal_to_string (context_p, "set", 3)) - { - context_p->token.type = LEXER_PROPERTY_SETTER; - return; - } + context_p->token.type = LEXER_PROPERTY_GETTER; + return; } - } -#if ENABLED (JERRY_ES2015_CLASS) - if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6)) - { - context_p->token.type = LEXER_KEYW_STATIC; - return; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + if (lexer_compare_literal_to_string (context_p, "set", 3)) + { + context_p->token.type = LEXER_PROPERTY_SETTER; + return; + } - create_literal_object = true; +#if ENABLED (JERRY_ES2015) + if (lexer_compare_literal_to_string (context_p, "async", 5)) + { + context_p->token.type = LEXER_KEYW_ASYNC; + return; + } +#endif /* ENABLED (JERRY_ES2015) */ + } } - else if (context_p->source_p[0] == LIT_CHAR_DOUBLE_QUOTE - || context_p->source_p[0] == LIT_CHAR_SINGLE_QUOTE) - { - lexer_parse_string (context_p); - create_literal_object = true; - } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - else if (context_p->source_p[0] == LIT_CHAR_LEFT_SQUARE) - { - context_p->source_p += 1; - context_p->column++; - lexer_next_token (context_p); - parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); - - if (context_p->token.type != LEXER_RIGHT_SQUARE) - { - parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED); - } +#if ENABLED (JERRY_ES2015) + if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6)) + { + context_p->token.type = LEXER_KEYW_STATIC; return; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - else if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) && context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE) - { - context_p->token.type = LEXER_RIGHT_BRACE; - context_p->source_p += 1; - context_p->column++; - return; - } - else - { - const uint8_t *char_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ - if (char_p[0] == LIT_CHAR_DOT) + create_literal_object = true; + } + else + { + switch (context_p->source_p[0]) + { + case LIT_CHAR_DOUBLE_QUOTE: + case LIT_CHAR_SINGLE_QUOTE: { - char_p++; + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); + create_literal_object = true; + break; } - - if (char_p < context_p->source_end_p - && char_p[0] >= LIT_CHAR_0 - && char_p[0] <= LIT_CHAR_9) +#if ENABLED (JERRY_ES2015) + case LIT_CHAR_LEFT_SQUARE: { - lexer_parse_number (context_p); - lexer_construct_number_object (context_p, false, false); + lexer_consume_next_character (context_p); + + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + + if (context_p->token.type != LEXER_RIGHT_SQUARE) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED); + } return; } - } - - if (create_literal_object) - { -#if ENABLED (JERRY_ES2015_CLASS) - if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11)) + case LIT_CHAR_ASTERISK: { - context_p->token.type = LEXER_CLASS_CONSTRUCTOR; + if (ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)) + { + break; + } + + context_p->token.type = LEXER_MULTIPLY; + lexer_consume_next_character (context_p); return; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ + case LIT_CHAR_RIGHT_BRACE: + { + if (ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) + { + break; + } - lexer_construct_literal_object (context_p, - &context_p->token.lit_location, - LEXER_STRING_LITERAL); + context_p->token.type = LEXER_RIGHT_BRACE; + lexer_consume_next_character (context_p); + return; + } + default: + { + const uint8_t *char_p = context_p->source_p; + + if (char_p[0] == LIT_CHAR_DOT) + { + char_p++; + } + + if (char_p < context_p->source_end_p + && char_p[0] >= LIT_CHAR_0 + && char_p[0] <= LIT_CHAR_9) + { + lexer_parse_number (context_p); + lexer_construct_number_object (context_p, false, false); + return; + } + break; + } + } + } + + if (create_literal_object) + { +#if ENABLED (JERRY_ES2015) + if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11)) + { + context_p->token.type = LEXER_CLASS_CONSTRUCTOR; + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; return; } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_construct_literal_object (context_p, + &context_p->token.lit_location, + LEXER_STRING_LITERAL); + return; } parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); } /* lexer_expect_object_literal_id */ /** - * Next token must be an identifier. + * Read next token without checking keywords + * + * @return true if the next literal is identifier, false otherwise */ -void -lexer_scan_identifier (parser_context_t *context_p, /**< context */ - uint32_t ident_opts) /**< lexer_scan_ident_opts_t option bits */ +bool +lexer_scan_identifier (parser_context_t *context_p) /**< context */ { lexer_skip_spaces (context_p); context_p->token.line = context_p->line; context_p->token.column = context_p->column; if (context_p->source_p < context_p->source_end_p - && (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH)) + && lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS)) { - lexer_parse_identifier (context_p, false); + return true; + } - if ((ident_opts & LEXER_SCAN_IDENT_PROPERTY) - && !(ident_opts & LEXER_SCAN_IDENT_NO_KEYW) - && context_p->token.lit_location.length == 3) - { - lexer_skip_spaces (context_p); - context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + lexer_next_token (context_p); + return false; +} /* lexer_scan_identifier */ - if (context_p->source_p < context_p->source_end_p -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - && context_p->source_p[0] != LIT_CHAR_COMMA - && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - && context_p->source_p[0] != LIT_CHAR_COLON) - { - if (lexer_compare_literal_to_string (context_p, "get", 3)) - { - context_p->token.type = LEXER_PROPERTY_GETTER; - } - else if (lexer_compare_literal_to_string (context_p, "set", 3)) - { - context_p->token.type = LEXER_PROPERTY_SETTER; - } - } - } +/** + * Check whether the identifier is a modifier in a property definition. + */ +void +lexer_check_property_modifier (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)); + JERRY_ASSERT (context_p->token.type = LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + + if (context_p->source_p >= context_p->source_end_p +#if ENABLED (JERRY_ES2015) + || context_p->source_p[0] == LIT_CHAR_COMMA + || context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE + || context_p->source_p[0] == LIT_CHAR_LEFT_PAREN + || context_p->source_p[0] == LIT_CHAR_EQUALS +#endif /* ENABLED (JERRY_ES2015) */ + || context_p->source_p[0] == LIT_CHAR_COLON) + { return; } - if (ident_opts & LEXER_SCAN_IDENT_PROPERTY) + if (lexer_compare_literal_to_string (context_p, "get", 3)) { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LITERAL -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - || context_p->token.type == LEXER_LEFT_SQUARE -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - || context_p->token.type == LEXER_RIGHT_BRACE) - { - return; - } + context_p->token.type = LEXER_PROPERTY_GETTER; + return; } -#if ENABLED (JERRY_ES2015_CLASS) - if (ident_opts & LEXER_SCAN_CLASS_PROPERTY) + + if (lexer_compare_literal_to_string (context_p, "set", 3)) { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LITERAL -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - || context_p->token.type == LEXER_LEFT_SQUARE -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - || context_p->token.type == LEXER_RIGHT_BRACE - || context_p->token.type == LEXER_SEMICOLON - || ((ident_opts & LEXER_SCAN_CLASS_LEFT_PAREN) && context_p->token.type == LEXER_LEFT_PAREN)) - { - return; - } + context_p->token.type = LEXER_PROPERTY_SETTER; + return; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); -} /* lexer_scan_identifier */ +#if ENABLED (JERRY_ES2015) + if (lexer_compare_literal_to_string (context_p, "async", 5)) + { + context_p->token.type = LEXER_KEYW_ASYNC; + return; + } +#endif /* ENABLED (JERRY_ES2015) */ +} /* lexer_check_property_modifier */ + +/** + * Compares two identifiers. + * + * Note: + * Escape sequences are allowed in the left identifier, but not in the right + * + * @return true if the two identifiers are the same + */ +static bool +lexer_compare_identifier_to_chars (const uint8_t *left_p, /**< left identifier */ + const uint8_t *right_p, /**< right identifier string */ + size_t size) /**< byte size of the two identifiers */ +{ + uint8_t utf8_buf[6]; + + do + { + if (*left_p == *right_p) + { + left_p++; + right_p++; + size--; + continue; + } + + size_t escape_size; + + if (*left_p == LIT_CHAR_BACKSLASH) + { + left_p += 2; + lit_code_point_t code_point = lexer_unchecked_hex_to_character (&left_p); + + escape_size = lit_code_point_to_cesu8_bytes (utf8_buf, code_point); + } + else if (*left_p >= LIT_UTF8_4_BYTE_MARKER) + { + lit_four_byte_utf8_char_to_cesu8 (utf8_buf, left_p); + escape_size = 3 * 2; + left_p += 4; + } + else + { + return false; + } + + size -= escape_size; + + uint8_t *utf8_p = utf8_buf; + do + { + if (*right_p++ != *utf8_p++) + { + return false; + } + } + while (--escape_size > 0); + } + while (size > 0); + + return true; +} /* lexer_compare_identifier_to_chars */ + +/** + * Compares an identifier to a string. + * + * Note: + * Escape sequences are allowed in the left identifier, but not in the right + * + * @return true if the identifier equals to string + */ +bool +lexer_compare_identifier_to_string (const lexer_lit_location_t *left_p, /**< left literal */ + const uint8_t *right_p, /**< right identifier string */ + size_t size) /**< byte size of the right identifier */ +{ + if (left_p->length != size) + { + return false; + } + + if (!left_p->has_escape) + { + return memcmp (left_p->char_p, right_p, size) == 0; + } + + return lexer_compare_identifier_to_chars (left_p->char_p, right_p, size); +} /* lexer_compare_identifier_to_string */ + +/** + * Compares two identifiers. + * + * Note: + * Escape sequences are allowed in both identifiers + * + * @return true if the two identifiers are the same + */ +bool +lexer_compare_identifiers (parser_context_t *context_p, /**< context */ + const lexer_lit_location_t *left_p, /**< left literal */ + const lexer_lit_location_t *right_p) /**< right literal */ +{ + prop_length_t length = left_p->length; + + if (length != right_p->length) + { + return false; + } + + if (!left_p->has_escape) + { + return lexer_compare_identifier_to_chars (right_p->char_p, left_p->char_p, length); + } + + if (!right_p->has_escape) + { + return lexer_compare_identifier_to_chars (left_p->char_p, right_p->char_p, length); + } + + uint8_t buf_p[64]; + + if (length <= 64) + { + lexer_convert_ident_to_cesu8 (buf_p, left_p->char_p, length); + return lexer_compare_identifier_to_chars (right_p->char_p, buf_p, length); + } + + uint8_t *dynamic_buf_p = parser_malloc (context_p, length); + + lexer_convert_ident_to_cesu8 (dynamic_buf_p, left_p->char_p, length); + bool result = lexer_compare_identifier_to_chars (right_p->char_p, dynamic_buf_p, length); + parser_free (dynamic_buf_p, length); + + return result; +} /* lexer_compare_identifiers */ /** * Compares the current identifier in the context to the parameter identifier @@ -2527,19 +3327,19 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ * @return true if the input identifiers are the same */ bool -lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context */ - const lexer_lit_location_t *right_ident_p) /**< identifier */ +lexer_current_is_literal (parser_context_t *context_p, /**< context */ + const lexer_lit_location_t *right_ident_p) /**< identifier */ { + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + lexer_lit_location_t *left_ident_p = &context_p->token.lit_location; - const uint8_t *left_p; - const uint8_t *right_p; - size_t count; JERRY_ASSERT (left_ident_p->length > 0 && right_ident_p->length > 0); if (left_ident_p->length != right_ident_p->length) { - return 0; + return false; } if (!left_ident_p->has_escape && !right_ident_p->has_escape) @@ -2547,74 +3347,49 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context * return memcmp (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length) == 0; } - left_p = left_ident_p->char_p; - right_p = right_ident_p->char_p; - count = left_ident_p->length; - - do - { - uint8_t utf8_buf[3]; - size_t utf8_len, offset; - - /* Backslash cannot be part of a multibyte UTF-8 character. */ - if (*left_p != LIT_CHAR_BACKSLASH && *right_p != LIT_CHAR_BACKSLASH) - { - if (*left_p++ != *right_p++) - { - return false; - } - count--; - continue; - } - - if (*left_p == LIT_CHAR_BACKSLASH && *right_p == LIT_CHAR_BACKSLASH) - { - uint16_t left_chr = lexer_unchecked_hex_to_character (left_p + 2, 4); - - if (left_chr != lexer_unchecked_hex_to_character (right_p + 2, 4)) - { - return false; - } - - left_p += 6; - right_p += 6; - count += lit_char_get_utf8_length (left_chr); - continue; - } - - /* One character is encoded as unicode sequence. */ - if (*right_p == LIT_CHAR_BACKSLASH) - { - /* The pointers can be swapped. */ - const uint8_t *swap_p = left_p; - left_p = right_p; - right_p = swap_p; - } - - utf8_len = lit_char_to_utf8_bytes (utf8_buf, lexer_unchecked_hex_to_character (left_p + 2, 4)); - JERRY_ASSERT (utf8_len > 0); - count -= utf8_len; - offset = 0; - - do - { - if (utf8_buf[offset] != *right_p++) - { - return false; - } - offset++; - } - while (offset < utf8_len); - - left_p += 6; - } - while (count > 0); - - return true; -} /* lexer_compare_identifier_to_current */ + return lexer_compare_identifiers (context_p, left_ident_p, right_ident_p); +} /* lexer_current_is_literal */ /** - * Compares the current identifier to an expected identifier. + * Compares the current string token to "use strict". + * + * Note: + * Escape sequences are not allowed. + * + * @return true if "use strict" is found, false otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +lexer_string_is_use_strict (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_STRING_LITERAL); + + return (context_p->token.lit_location.length == 10 + && !context_p->token.lit_location.has_escape + && memcmp (context_p->token.lit_location.char_p, "use strict", 10) == 0); +} /* lexer_string_is_use_strict */ + +/** + * Checks whether the string before the current token is a directive or a string literal. + * + * @return true if the string is a directive, false otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +lexer_string_is_directive (parser_context_t *context_p) /**< context */ +{ + return (context_p->token.type == LEXER_SEMICOLON + || context_p->token.type == LEXER_RIGHT_BRACE + || ((context_p->token.flags & LEXER_WAS_NEWLINE) + && !LEXER_IS_BINARY_OP_TOKEN (context_p->token.type) + && context_p->token.type != LEXER_LEFT_PAREN + && context_p->token.type != LEXER_LEFT_SQUARE + && context_p->token.type != LEXER_DOT)); +} /* lexer_string_is_directive */ + +#if ENABLED (JERRY_ES2015) + +/** + * Compares the current token to an expected identifier. * * Note: * Escape sequences are not allowed. @@ -2622,16 +3397,53 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context * * @return true if they are the same, false otherwise */ inline bool JERRY_ATTR_ALWAYS_INLINE -lexer_compare_literal_to_identifier (parser_context_t *context_p, /**< context */ - const char *identifier_p, /**< identifier */ - size_t identifier_length) /**< identifier length */ +lexer_token_is_identifier (parser_context_t *context_p, /**< context */ + const char *identifier_p, /**< identifier */ + size_t identifier_length) /**< identifier length */ { /* Checking has_escape is unnecessary because memcmp will fail if escape sequences are present. */ return (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL && context_p->token.lit_location.length == identifier_length && memcmp (context_p->token.lit_location.char_p, identifier_p, identifier_length) == 0); -} /* lexer_compare_literal_to_identifier */ +} /* lexer_token_is_identifier */ + +/** + * Compares the current identifier token to "let". + * + * Note: + * Escape sequences are not allowed. + * + * @return true if "let" is found, false otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +lexer_token_is_let (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL); + + return (context_p->token.keyword_type == LEXER_KEYW_LET + && !context_p->token.lit_location.has_escape); +} /* lexer_token_is_let */ + +/** + * Compares the current identifier token to "async". + * + * Note: + * Escape sequences are not allowed. + * + * @return true if "async" is found, false otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +lexer_token_is_async (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + || context_p->token.type == LEXER_TEMPLATE_LITERAL); + + return (context_p->token.keyword_type == LEXER_KEYW_ASYNC + && !context_p->token.lit_location.has_escape); +} /* lexer_token_is_async */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Compares the current identifier or string to an expected string. @@ -2668,10 +3480,17 @@ lexer_convert_binary_lvalue_token_to_binary (uint8_t token) /**< binary lvalue t JERRY_ASSERT (LEXER_IS_BINARY_LVALUE_TOKEN (token)); JERRY_ASSERT (token != LEXER_ASSIGN); +#if ENABLED (JERRY_ES2015) + if (token <= LEXER_ASSIGN_EXPONENTIATION) + { + return (uint8_t) (LEXER_ADD + (token - LEXER_ASSIGN_ADD)); + } +#else /* !ENABLED (JERRY_ES2015) */ if (token <= LEXER_ASSIGN_MODULO) { return (uint8_t) (LEXER_ADD + (token - LEXER_ASSIGN_ADD)); } +#endif /* ENABLED (JERRY_ES2015) */ if (token <= LEXER_ASSIGN_UNS_RIGHT_SHIFT) { diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 79f76228..6fe14c3c 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -39,12 +39,10 @@ typedef enum LEXER_LIT_TRUE, /**< true (not a keyword!) */ LEXER_LIT_FALSE, /**< false (not a keyword!) */ LEXER_LIT_NULL, /**< null (not a keyword!) */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) LEXER_TEMPLATE_LITERAL, /**< multi segment template literal */ -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) LEXER_THREE_DOTS, /**< ... (rest or spread operator) */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Unary operators * IMPORTANT: update CBC_UNARY_OP_TOKEN_TO_OPCODE and @@ -60,6 +58,9 @@ typedef enum LEXER_BIT_NOT, /**< "~" */ LEXER_KEYW_VOID, /**< void */ LEXER_KEYW_TYPEOF, /**< typeof */ +#if ENABLED (JERRY_ES2015) + LEXER_KEYW_AWAIT, /**< await */ +#endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYW_DELETE, /**< delete */ LEXER_INCREASE, /**< "++" */ LEXER_DECREASE, /**< "--" */ @@ -68,10 +69,17 @@ typedef enum * IMPORTANT: update CBC_BINARY_OP_TOKEN_TO_OPCODE, * CBC_BINARY_LVALUE_OP_TOKEN_TO_OPCODE and * parser_binary_precedence_table after changes. */ +#if ENABLED (JERRY_ES2015) +#define LEXER_IS_BINARY_OP_TOKEN(token_type) \ + ((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_EXPONENTIATION) +#else /* !ENABLED (JERRY_ES2015) */ #define LEXER_IS_BINARY_OP_TOKEN(token_type) \ ((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_MODULO) +#endif /* ENABLED (JERRY_ES2015) */ + #define LEXER_IS_BINARY_LVALUE_TOKEN(token_type) \ ((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_ASSIGN_BIT_XOR) + #define LEXER_FIRST_BINARY_OP LEXER_ASSIGN LEXER_ASSIGN, /**< "=" (prec: 3) */ @@ -80,6 +88,9 @@ typedef enum LEXER_ASSIGN_MULTIPLY, /**< "*=" (prec: 3) */ LEXER_ASSIGN_DIVIDE, /**< "/=" (prec: 3) */ LEXER_ASSIGN_MODULO, /**< "%=" (prec: 3) */ +#if ENABLED (JERRY_ES2015) + LEXER_ASSIGN_EXPONENTIATION, /**< "**=" (prec: 3) */ +#endif /* ENABLED (JERRY_ES2015) */ LEXER_ASSIGN_LEFT_SHIFT, /**< "<<=" (prec: 3) */ LEXER_ASSIGN_RIGHT_SHIFT, /**< ">>=" (prec: 3) */ LEXER_ASSIGN_UNS_RIGHT_SHIFT, /**< ">>>=" (prec: 3) */ @@ -110,6 +121,9 @@ typedef enum LEXER_MULTIPLY, /**< "*" (prec: 14) */ LEXER_DIVIDE, /**< "/" (prec: 14) */ LEXER_MODULO, /**< "%" (prec: 14) */ +#if ENABLED (JERRY_ES2015) + LEXER_EXPONENTIATION, /**< "**" (prec: 15) */ +#endif /* ENABLED (JERRY_ES2015) */ LEXER_LEFT_BRACE, /**< "{" */ LEXER_LEFT_PAREN, /**< "(" */ @@ -121,9 +135,9 @@ typedef enum LEXER_SEMICOLON, /**< ";" */ LEXER_COLON, /**< ":" */ LEXER_COMMA, /**< "," */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) LEXER_ARROW, /**< "=>" */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYW_BREAK, /**< break */ LEXER_KEYW_DO, /**< do */ @@ -146,44 +160,42 @@ typedef enum LEXER_KEYW_THROW, /**< throw */ LEXER_KEYW_TRY, /**< try */ - /* These are virtual tokens. */ - LEXER_EXPRESSION_START, /**< expression start */ - LEXER_PROPERTY_GETTER, /**< property getter function */ - LEXER_PROPERTY_SETTER, /**< property setter function */ - LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */ - LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */ - LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */ -#if ENABLED (JERRY_ES2015_FOR_OF) - LEXER_FOR_IN_OF, /**< special value during for in/of statmenet scanning */ - LEXER_LITERAL_OF, /**< 'of' literal */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - -#if !ENABLED (JERRY_ES2015) - /* Future reserved words: these keywords - * must form a group after all other keywords. */ -#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_CLASS -#endif /* !ENABLED (JERRY_ES2015) */ LEXER_KEYW_CLASS, /**< class */ LEXER_KEYW_EXTENDS, /**< extends */ LEXER_KEYW_SUPER, /**< super */ LEXER_KEYW_CONST, /**< const */ LEXER_KEYW_EXPORT, /**< export */ LEXER_KEYW_IMPORT, /**< import */ -#if ENABLED (JERRY_ES2015) - /* Future reserved words: these keywords - * must form a group after all other keywords. - * Note: - * Tokens from LEXER_KEYW_CLASS to LEXER_KEYW_IMPORT - * are no longer future reserved words in ES2015. */ -#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_ENUM -#endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYW_ENUM, /**< enum */ + + /* These are virtual tokens. */ + LEXER_EXPRESSION_START, /**< expression start */ + LEXER_PROPERTY_GETTER, /**< property getter function */ + LEXER_PROPERTY_SETTER, /**< property setter function */ + LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */ #if ENABLED (JERRY_ES2015) - LEXER_KEYW_AWAIT, /**< await */ + LEXER_ASSIGN_GROUP_EXPR, /**< indetifier for the assignment is located in a group expression */ + LEXER_ASSIGN_CONST, /**< a const binding is reassigned */ + LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */ + LEXER_INVALID_PATTERN, /**< special value for invalid destructuring pattern */ #endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015) + /* Keywords which are not keyword tokens. */ +#define LEXER_FIRST_NON_RESERVED_KEYWORD LEXER_KEYW_ASYNC + LEXER_KEYW_ASYNC, /**< async */ +#else /* !ENABLED (JERRY_ES2015) */ + /* Keywords which are not keyword tokens. */ +#define LEXER_FIRST_NON_RESERVED_KEYWORD LEXER_KEYW_EVAL +#endif /* ENABLED (JERRY_ES2015) */ + + /* Keywords which cannot be assigned in strict mode. */ +#define LEXER_FIRST_NON_STRICT_ARGUMENTS LEXER_KEYW_EVAL + LEXER_KEYW_EVAL, /**< eval */ + LEXER_KEYW_ARGUMENTS, /**< arguments */ + /* Future strict reserved words: these keywords - * must form a group after future reserved words. */ + * must form a group after non-reserved keywords. */ #define LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD LEXER_KEYW_IMPLEMENTS LEXER_KEYW_IMPLEMENTS, /**< implements */ LEXER_KEYW_PRIVATE, /**< private */ @@ -192,31 +204,16 @@ typedef enum LEXER_KEYW_PACKAGE, /**< package */ LEXER_KEYW_PROTECTED, /**< protected */ -#if ENABLED (JERRY_ES2015) - /* Context dependent strict reserved words: - * See also: ECMA-262 v6, 11.6.2.1 */ -#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD LEXER_KEYW_STATIC - LEXER_KEYW_STATIC, /**< static */ -#else /* !ENABLED (JERRY_ES2015) */ - /* Context dependent strict reserved words: - * See also: ECMA-262 v6, 11.6.2.1 */ -#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD -#endif /* ENABLED (JERRY_ES2015) */ - /* Context dependent future strict reserved words: * See also: ECMA-262 v6, 11.6.2.1 */ -#define LEXER_FIRST_CONTEXT_DEPENDENT_FUTURE_RESERVED_WORD LEXER_KEYW_LET LEXER_KEYW_LET, /**< let */ LEXER_KEYW_YIELD, /**< yield */ -#if !ENABLED (JERRY_ES2015) LEXER_KEYW_STATIC, /**< static */ -#endif /* !ENABLED (JERRY_ES2015) */ } lexer_token_type_t; #define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2 #define LEXER_NEWLINE_LS_PS_BYTE_23(source) \ ((source)[1] == LIT_UTF8_2_BYTE_CODE_POINT_MIN && ((source)[2] | 0x1) == 0xa9) -#define LEXER_UTF8_4BYTE_START 0xf0 #define LEXER_IS_LEFT_BRACKET(type) \ ((type) == LEXER_LEFT_BRACE || (type) == LEXER_LEFT_PAREN || (type) == LEXER_LEFT_SQUARE) @@ -236,6 +233,11 @@ typedef enum #define LEXER_BINARY_LVALUE_OP_TOKEN_TO_OPCODE(token_type) \ ((cbc_opcode_t) ((((token_type) - LEXER_ASSIGN_ADD) * 2) + CBC_ASSIGN_ADD)) +/** + * Maximum local buffer size for identifiers which contains escape sequences. + */ +#define LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE 48 + /** * Lexer newline flags. */ @@ -253,31 +255,17 @@ typedef enum LEXER_OBJ_IDENT_NO_OPTS = (1u << 0), /**< no options */ LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 1), /**< only identifiers are accepted */ LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */ + LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */ } lexer_obj_ident_opts_t; /** - * Lexer scan identifier parse options. + * Lexer string options. */ typedef enum { - LEXER_SCAN_IDENT_NO_OPTS = (1u << 0), /**< no options */ - LEXER_SCAN_IDENT_PROPERTY = (1u << 1), /**< scan valid property names */ - LEXER_SCAN_IDENT_NO_KEYW = (1u << 2), /**< don't scan keywords (e.g. get/set) */ -#if ENABLED (JERRY_ES2015_CLASS) - LEXER_SCAN_CLASS_PROPERTY = (1u << 3), /**< scan valid class property names */ - LEXER_SCAN_CLASS_LEFT_PAREN = (1u << 4), /**< also parse left parenthesis */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -} lexer_scan_ident_opts_t; - -/** - * Lexer literal object types. - */ -typedef enum -{ - LEXER_LITERAL_OBJECT_ANY, /**< unspecified object type */ - LEXER_LITERAL_OBJECT_EVAL, /**< reference is equal to eval */ - LEXER_LITERAL_OBJECT_ARGUMENTS, /**< reference is equal to arguments */ -} lexer_literal_object_type_t; + LEXER_STRING_NO_OPTS = (1u << 0), /**< no options */ + LEXER_STRING_RAW = (1u << 1), /**< raw string ECMAScript v6, 11.8.6.1: TVR */ +} lexer_string_options_t; /** * Lexer number types. @@ -287,6 +275,7 @@ typedef enum LEXER_NUMBER_DECIMAL, /**< decimal number */ LEXER_NUMBER_HEXADECIMAL, /**< hexadecimal number */ LEXER_NUMBER_OCTAL, /**< octal number */ + LEXER_NUMBER_BINARY, /**< binary number */ } lexer_number_type_t; /** @@ -306,8 +295,7 @@ typedef struct typedef struct { uint8_t type; /**< token type */ - uint8_t literal_is_reserved; /**< future reserved keyword - * (when char_literal.type is LEXER_IDENT_LITERAL) */ + uint8_t keyword_type; /**< keyword type for identifiers */ uint8_t extra_value; /**< helper value for different purposes */ uint8_t flags; /**< flag bits for the current token */ parser_line_counter_t line; /**< token start line */ @@ -322,7 +310,6 @@ typedef struct { lexer_literal_t *literal_p; /**< pointer to the literal object */ uint16_t index; /**< literal index */ - uint8_t type; /**< literal object type */ } lexer_lit_object_t; /** diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 46b456df..108bf904 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -20,6 +20,7 @@ #include "ecma-helpers.h" #include "lit-char-helpers.h" +#include "js-parser-tagged-template-literal.h" /** \addtogroup parser Parser * @{ @@ -32,29 +33,53 @@ */ /** - * Maximum precedence for right-to-left binary operation evaluation + * Maximum precedence for right-to-left binary operation evaluation. */ #define PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE 6 /** - * Precende for ternary operation + * Precedence for ternary operation. */ #define PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE 4 +/** + * Precedence for exponentiation operation. + */ +#define PARSER_RIGHT_TO_LEFT_ORDER_EXPONENTIATION 15 + +/** + * Value of grouping level increase and decrease. + */ +#define PARSER_GROUPING_LEVEL_INCREASE 2 + /** * Precedence of the binary tokens. * * See also: * lexer_token_type_t */ -static const uint8_t parser_binary_precedence_table[36] = +static const uint8_t parser_binary_precedence_table[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +#if ENABLED (JERRY_ES2015) + 3, +#endif /* ENABLED (JERRY_ES2015) */ 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, - 13, 13, 14, 14, 14 + 13, 13, 14, 14, 14, +#if ENABLED (JERRY_ES2015) + 15, +#endif /* ENABLED (JERRY_ES2015) */ }; +#if ENABLED (JERRY_ES2015) +JERRY_STATIC_ASSERT (sizeof (parser_binary_precedence_table) == 38, + parser_binary_precedence_table_should_have_38_values_in_es2015); +#else /* !ENABLED (JERRY_ES2015) */ +JERRY_STATIC_ASSERT (sizeof (parser_binary_precedence_table) == 36, + parser_binary_precedence_table_should_have_36_values_in_es51); +#endif /* ENABLED (JERRY_ES2015) */ + /** * Generate byte code for operators with lvalue. */ @@ -94,25 +119,44 @@ parser_check_invalid_assign (parser_context_t *context_p) /**< context */ { JERRY_ASSERT (context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL); - if (JERRY_UNLIKELY ((context_p->status_flags & PARSER_IS_STRICT) - && context_p->last_cbc.literal_object_type != LEXER_LITERAL_OBJECT_ANY)) + if (JERRY_UNLIKELY (context_p->status_flags & PARSER_IS_STRICT)) { - parser_error_t error; - - if (context_p->last_cbc.literal_object_type == LEXER_LITERAL_OBJECT_EVAL) + if (context_p->last_cbc.literal_keyword_type == LEXER_KEYW_EVAL) { - error = PARSER_ERR_EVAL_CANNOT_ASSIGNED; + parser_raise_error (context_p, PARSER_ERR_EVAL_CANNOT_ASSIGNED); } - else + else if (context_p->last_cbc.literal_keyword_type == LEXER_KEYW_ARGUMENTS) { - JERRY_ASSERT (context_p->last_cbc.literal_object_type == LEXER_LITERAL_OBJECT_ARGUMENTS); - error = PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED; + parser_raise_error (context_p, PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED); } - - parser_raise_error (context_p, error); } } /* parser_check_invalid_assign */ +#if ENABLED (JERRY_ES2015) + +/** + * Check and throw an error if the "new.target" is invalid as a left-hand side expression. + */ +static void +parser_check_invalid_new_target (parser_context_t *context_p, /**< parser context */ + cbc_opcode_t opcode) /**< current opcode under parsing */ +{ + /* new.target is an invalid left-hand side target */ + if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NEW_TARGET)) + { + /* Make sure that the call side is a post/pre increment or an assignment expression. + * There should be no other ways the "new.target" expression should be here. */ + JERRY_ASSERT ((opcode >= CBC_PRE_INCR && opcode <= CBC_POST_DECR) + || (opcode == CBC_ASSIGN + && (context_p->token.type == LEXER_ASSIGN + || LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type)))); + + parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED); + } +} /* parser_check_invalid_new_target */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Emit identifier reference */ @@ -136,7 +180,7 @@ parser_emit_ident_reference (parser_context_t *context_p, /**< context */ else if (context_p->last_cbc_opcode == CBC_PUSH_THIS_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_THIS; - literal_index = context_p->lit_object.index; + literal_index = context_p->last_cbc.literal_index; } else { @@ -169,7 +213,6 @@ parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_DELETE_IDENT_NOT_ALLOWED); } - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; unary_opcode = CBC_DELETE_IDENT_PUSH_RESULT; } else @@ -179,6 +222,16 @@ parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */ } parser_emit_ident_reference (context_p, unary_opcode); + +#if ENABLED (JERRY_ES2015) + if (unary_opcode != CBC_DELETE_IDENT_PUSH_RESULT + && scanner_literal_is_const_reg (context_p, context_p->last_cbc.literal_index)) + { + /* The current value must be read, but it cannot be changed. */ + context_p->last_cbc_opcode = CBC_PUSH_LITERAL; + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_ASSIGN_CONST_ERROR); + } +#endif /* ENABLED (JERRY_ES2015) */ return; } @@ -196,8 +249,27 @@ parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */ else { /* Invalid LeftHandSide expression. */ - parser_emit_cbc_ext (context_p, (opcode == CBC_DELETE_PUSH_RESULT) ? CBC_EXT_PUSH_UNDEFINED_BASE - : CBC_EXT_THROW_REFERENCE_ERROR); + if (opcode == CBC_DELETE_PUSH_RESULT) + { +#if ENABLED (JERRY_ES2015) + if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL) + || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); + parser_emit_cbc (context_p, CBC_POP); + return; + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_emit_cbc (context_p, CBC_POP); + parser_emit_cbc (context_p, CBC_PUSH_TRUE); + return; + } + +#if ENABLED (JERRY_ES2015) + parser_check_invalid_new_target (context_p, opcode); +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); } parser_emit_cbc (context_p, (uint16_t) opcode); @@ -210,6 +282,7 @@ static void parser_parse_array_literal (parser_context_t *context_p) /**< context */ { uint32_t pushed_items = 0; + uint16_t opcode = (uint16_t) CBC_ARRAY_APPEND; JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE); @@ -222,7 +295,7 @@ parser_parse_array_literal (parser_context_t *context_p) /**< context */ { if (pushed_items > 0) { - parser_emit_cbc_call (context_p, CBC_ARRAY_APPEND, pushed_items); + parser_emit_cbc_call (context_p, opcode, pushed_items); } return; } @@ -236,8 +309,23 @@ parser_parse_array_literal (parser_context_t *context_p) /**< context */ } else { +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_THREE_DOTS) + { + opcode = (uint16_t) (PARSER_TO_EXT_OPCODE (CBC_EXT_SPREAD_ARRAY_APPEND)); + pushed_items++; + lexer_next_token (context_p); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT); + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + if (context_p->last_cbc_opcode == CBC_PUSH_THIS) + { + parser_flush_cbc (context_p); + } + if (context_p->token.type == LEXER_COMMA) { lexer_next_token (context_p); @@ -250,13 +338,16 @@ parser_parse_array_literal (parser_context_t *context_p) /**< context */ if (pushed_items >= 64) { - parser_emit_cbc_call (context_p, CBC_ARRAY_APPEND, pushed_items); + parser_emit_cbc_call (context_p, opcode, pushed_items); +#if ENABLED (JERRY_ES2015) + opcode = (uint16_t) CBC_ARRAY_APPEND; +#endif /* ENABLED (JERRY_ES2015) */ pushed_items = 0; } } } /* parser_parse_array_literal */ -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) /** * Object literal item types. */ @@ -353,13 +444,16 @@ parser_append_object_literal_item (parser_context_t *context_p, /**< context */ context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS; } } /* parser_append_object_literal_item */ -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) +/** Forward definition of parse array initializer. */ +static void +parser_parse_array_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) -#error "Class support requires ES2015 object literal support" -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +/** Forward definition of parse object initializer. */ +static void +parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); /** * Description of "get" literal string. @@ -378,20 +472,56 @@ static const lexer_lit_location_t lexer_set_literal = }; /** - * Parse class as an object literal. + * Class literal parsing options. + */ +typedef enum +{ + PARSER_CLASS_LITERAL_NO_OPTS = 0, /**< no options are provided */ + PARSER_CLASS_LITERAL_CTOR_PRESENT = (1 << 0), /**< class constructor is present */ + PARSER_CLASS_LITERAL_HERTIAGE_PRESENT = (1 << 1), /**< class heritage is present */ +} parser_class_literal_opts_t; + +/** + * Parse class literal. */ static void -parser_parse_class_literal (parser_context_t *context_p) /**< context */ +parser_parse_class_literal (parser_context_t *context_p, /**< context */ + parser_class_literal_opts_t opts) /**< class literal parsing options */ { JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); - bool super_called = false; - uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; - status_flags |= context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER); + uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER; + + lexer_literal_t *ctor_literal_p = NULL; + + if (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT) + { + if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) + { + parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); + } + + ctor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); + ctor_literal_p->type = LEXER_UNUSED_LITERAL; + ctor_literal_p->status_flags = 0; + parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, (uint16_t) (context_p->literal_count++)); + } + else if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT) + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR); + } + + parser_emit_cbc_ext (context_p, CBC_EXT_INIT_CLASS); + + bool is_static = false; while (true) { - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)) + if (!is_static) { lexer_skip_empty_statements (context_p); } @@ -410,8 +540,6 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ uint16_t literal_index, function_literal_index; bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER); - lexer_skip_empty_statements (context_p); - if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { lexer_construct_literal_object (context_p, @@ -421,7 +549,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ goto parse_class_method; } - uint32_t accessor_status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; + uint32_t accessor_status_flags = status_flags; accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER); lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); @@ -431,14 +559,13 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ { is_computed = true; } - else if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) + else if (!is_static && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type) && lexer_compare_literal_to_string (context_p, "constructor", 11)) { parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR); } - parser_flush_cbc (context_p); function_literal_index = lexer_construct_function_object (context_p, accessor_status_flags); parser_emit_cbc_literal (context_p, @@ -448,7 +575,6 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); cbc_ext_opcode_t opcode; - bool is_static = (status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0; if (is_computed) { @@ -478,66 +604,88 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ } context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); - status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION; + is_static = false; continue; } - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_CLASS_CONSTRUCTOR) + if (!is_static) { - if (super_called) + if (context_p->token.type == LEXER_KEYW_STATIC) { - /* 14.5.1 */ - parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS); - } - else - { - super_called = true; + is_static = true; + continue; } - parser_flush_cbc (context_p); - uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR; - - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) + if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR) { - constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED; - } + JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT); + JERRY_ASSERT (ctor_literal_p != NULL); - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } + if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL) + { + /* 14.5.1 */ + parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS); + } - uint16_t result_index = context_p->literal_count; - lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - literal_p->type = LEXER_UNUSED_LITERAL; - literal_p->status_flags = 0; - literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags); - literal_p->type = LEXER_FUNCTION_LITERAL; - parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index); - context_p->literal_count++; - continue; + uint32_t constructor_status_flags = (status_flags + | PARSER_CLASS_CONSTRUCTOR + | PARSER_LEXICAL_ENV_NEEDED); + + if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT) + { + constructor_status_flags |= PARSER_ALLOW_SUPER_CALL; + } + + parser_flush_cbc (context_p); + ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags); + ctor_literal_p->u.bytecode_p = compiled_code_p; + ctor_literal_p->type = LEXER_FUNCTION_LITERAL; + continue; + } } - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_KEYW_STATIC) + status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + + if (context_p->token.type == LEXER_KEYW_ASYNC) { - status_flags |= PARSER_CLASS_STATIC_FUNCTION; - continue; + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + + if (!lexer_consume_generator (context_p)) + { + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + } + } + + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } if (context_p->token.type == LEXER_RIGHT_SQUARE) { is_computed = true; } - else if ((status_flags & PARSER_CLASS_STATIC_FUNCTION) - && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type) - && lexer_compare_literal_to_string (context_p, "prototype", 9)) + else if (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)) { - parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE); + if (is_static) + { + if (lexer_compare_literal_to_string (context_p, "prototype", 9)) + { + parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE); + } + } + else if ((status_flags & PARSER_IS_GENERATOR_FUNCTION) + && lexer_compare_literal_to_string (context_p, "constructor", 11)) + { + parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR); + } } parse_class_method: - parser_flush_cbc (context_p); - + ; /* Empty statement to make compiler happy. */ uint16_t literal_index = context_p->lit_object.index; uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); @@ -549,11 +697,11 @@ parse_class_method: context_p->last_cbc.value = literal_index; - if ((status_flags & PARSER_CLASS_STATIC_FUNCTION)) + if (is_static) { context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (is_computed ? CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL : CBC_EXT_SET_STATIC_PROPERTY_LITERAL); - status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION; + is_static = false; } else { @@ -561,26 +709,8 @@ parse_class_method: : CBC_SET_LITERAL_PROPERTY); } } - - if (!super_called && (context_p->status_flags & PARSER_CLASS_HAS_SUPER)) - { - parser_emit_cbc_ext (context_p, CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL); - } - - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) - { - parser_emit_cbc_ext (context_p, CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR); - } } /* parser_parse_class_literal */ -/** - * Description of "prototype" literal string. - */ -static const lexer_lit_location_t lexer_prototype_literal = -{ - (const uint8_t *) "prototype", 9, LEXER_STRING_LITERAL, false -}; - /** * Parse class statement or expression. */ @@ -592,6 +722,15 @@ parser_parse_class (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS); uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; + uint16_t class_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; + parser_class_literal_opts_t opts = PARSER_CLASS_LITERAL_NO_OPTS; + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR); + scanner_release_next (context_p, sizeof (scanner_info_t)); + opts |= PARSER_CLASS_LITERAL_CTOR_PRESENT; + } if (is_statement) { @@ -600,15 +739,19 @@ parser_parse_class (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } class_ident_index = context_p->lit_object.index; - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + class_name_index = context_p->lit_object.index; #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->status_flags & PARSER_MODULE_STORE_IDENT) - { - context_p->module_identifier_lit_p = context_p->lit_object.literal_p; - context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); - } + parser_module_append_export_name (context_p); + context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ lexer_next_token (context_p); @@ -621,16 +764,36 @@ parser_parse_class (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { /* NOTE: If 'Function.name' will be supported, the current literal object must be set to 'name' property. */ + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + class_name_index = context_p->lit_object.index; lexer_next_token (context_p); } } - bool create_class_env = (context_p->token.type == LEXER_KEYW_EXTENDS - || (context_p->status_flags & PARSER_CLASS_HAS_SUPER)); - - if (create_class_env) + if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS) { - parser_parse_super_class_context_start (context_p); + parser_emit_cbc_ext_literal (context_p, CBC_EXT_PUSH_NAMED_CLASS_ENV, class_name_index); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_ANONYMOUS_CLASS_ENV); + } + + bool is_strict = (context_p->status_flags & PARSER_IS_STRICT) != 0; + + /* 14.5. A ClassBody is always strict code. */ + context_p->status_flags |= PARSER_IS_STRICT; + + if (context_p->token.type == LEXER_KEYW_EXTENDS) + { + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE); + opts |= PARSER_CLASS_LITERAL_HERTIAGE_PRESENT; + } + else + { + /* Elisions represents that the classHeritage is not present */ + parser_emit_cbc (context_p, CBC_PUSH_ELISION); } if (context_p->token.type != LEXER_LEFT_BRACE) @@ -638,33 +801,29 @@ parser_parse_class (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE); - - bool is_strict = context_p->status_flags & PARSER_IS_STRICT; - - /* 14.5. A ClassBody is always strict code. */ - context_p->status_flags |= PARSER_IS_STRICT; - /* ClassDeclaration is parsed. Continue with class body. */ - parser_parse_class_literal (context_p); + parser_parse_class_literal (context_p, opts); - JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE); - - lexer_construct_literal_object (context_p, - (lexer_lit_location_t *) &lexer_prototype_literal, - lexer_prototype_literal.type); - - parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, context_p->lit_object.index); + if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS) + { + parser_emit_cbc_ext_literal (context_p, CBC_EXT_FINALIZE_NAMED_CLASS, class_name_index); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_FINALIZE_ANONYMOUS_CLASS); + } if (is_statement) { - parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, class_ident_index); - } + cbc_opcode_t opcode = CBC_MOV_IDENT; - if (create_class_env) - { - parser_parse_super_class_context_end (context_p, is_statement); - context_p->status_flags &= (uint32_t) ~(PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER); + if (class_ident_index < PARSER_REGISTER_START) + { + opcode = (scanner_literal_is_created (context_p, class_ident_index) ? CBC_ASSIGN_LET_CONST + : CBC_INIT_LET); + } + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, class_ident_index); } parser_flush_cbc (context_p); @@ -674,12 +833,13 @@ parser_parse_class (parser_context_t *context_p, /**< context */ /* Restore flag */ context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; } + context_p->status_flags &= (uint32_t) ~PARSER_ALLOW_SUPER; lexer_next_token (context_p); } /* parser_parse_class */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) /** * Parse object initializer method definition. * @@ -688,12 +848,9 @@ parser_parse_class (parser_context_t *context_p, /**< context */ static void parser_parse_object_method (parser_context_t *context_p) /**< context */ { - parser_flush_cbc (context_p); - context_p->source_p--; context_p->column--; - uint16_t function_literal_index = lexer_construct_function_object (context_p, - PARSER_IS_FUNCTION | PARSER_IS_CLOSURE); + uint16_t function_literal_index = lexer_construct_function_object (context_p, PARSER_FUNCTION_CLOSURE); parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, @@ -701,7 +858,42 @@ parser_parse_object_method (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); } /* parser_parse_object_method */ -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + +/** + * Reparse the current literal as a common identifier. + */ +static void +parser_reparse_as_common_identifier (parser_context_t *context_p, /**< context */ + parser_line_counter_t start_line, /**< start line */ + parser_line_counter_t start_column) /**< start column */ +{ + /* context_p->token.lit_location.char_p is showing the character after the string start, + so it is not suitable for reparsing as identifier. + e.g.: { 'foo' } */ + if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + context_p->source_p = context_p->token.lit_location.char_p; + context_p->line = start_line; + context_p->column = start_column; + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + JERRY_ASSERT (context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + + lexer_construct_literal_object (context_p, + &context_p->token.lit_location, + LEXER_IDENT_LITERAL); + +} /* parser_reparse_as_common_identifier */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Parse object literal. @@ -713,9 +905,13 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ parser_emit_cbc (context_p, CBC_CREATE_OBJECT); -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) parser_stack_push_uint8 (context_p, PARSER_OBJECT_PROPERTY_START); -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) + bool proto_seen = false; +#endif /* ENABLED (JERRY_ES2015) */ while (true) { @@ -732,52 +928,50 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ { uint32_t status_flags; cbc_ext_opcode_t opcode; - uint16_t literal_index, function_literal_index; -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) parser_object_literal_item_types_t item_type; -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ if (context_p->token.type == LEXER_PROPERTY_GETTER) { - status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER; + status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_GETTER; opcode = CBC_EXT_SET_GETTER; -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) item_type = PARSER_OBJECT_PROPERTY_GETTER; -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ } else { - status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER; + status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_SETTER; opcode = CBC_EXT_SET_SETTER; -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) item_type = PARSER_OBJECT_PROPERTY_SETTER; -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ } lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); /* This assignment is a nop for computed getters/setters. */ - literal_index = context_p->lit_object.index; + uint16_t literal_index = context_p->lit_object.index; -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_RIGHT_SQUARE) { opcode = ((opcode == CBC_EXT_SET_GETTER) ? CBC_EXT_SET_COMPUTED_GETTER : CBC_EXT_SET_COMPUTED_SETTER); } -#else /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#else /* !ENABLED (JERRY_ES2015) */ parser_append_object_literal_item (context_p, literal_index, item_type); -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ - parser_flush_cbc (context_p); - function_literal_index = lexer_construct_function_object (context_p, status_flags); + uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) if (opcode >= CBC_EXT_SET_COMPUTED_GETTER) { literal_index = function_literal_index; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, @@ -790,7 +984,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); break; } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) case LEXER_RIGHT_SQUARE: { lexer_next_token (context_p); @@ -822,24 +1016,81 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ } break; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - default: + case LEXER_KEYW_ASYNC: + case LEXER_MULTIPLY: { + uint32_t status_flags = PARSER_FUNCTION_CLOSURE; + + if (context_p->token.type == LEXER_KEYW_ASYNC) + { + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + lexer_consume_generator (context_p); + } + + if (context_p->token.type == LEXER_MULTIPLY) + { + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } + + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + + uint16_t opcode = CBC_SET_LITERAL_PROPERTY; + /* This assignment is a nop for CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL. */ uint16_t literal_index = context_p->lit_object.index; -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + if (context_p->token.type == LEXER_RIGHT_SQUARE) + { + opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL); + } + + uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); + + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + function_literal_index); + + JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); + context_p->last_cbc_opcode = opcode; + context_p->last_cbc.value = literal_index; + + lexer_next_token (context_p); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + default: + { +#if ENABLED (JERRY_ES2015) + const lexer_lit_location_t *literal_p = (const lexer_lit_location_t *) context_p->lit_object.literal_p; + bool is_proto = ((context_p->token.lit_location.type == LEXER_IDENT_LITERAL + || context_p->token.lit_location.type == LEXER_STRING_LITERAL) + && lexer_compare_identifier_to_string (literal_p, (uint8_t *) "__proto__", 9) + && lexer_check_next_character (context_p, LIT_CHAR_COLON)); + if (is_proto) + { + if (proto_seen) + { + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_PROTO); + } + + proto_seen = true; + } +#endif /* ENABLED (JERRY_ES2015) */ + + uint16_t literal_index = context_p->lit_object.index; + +#if ENABLED (JERRY_ES2015) parser_line_counter_t start_line = context_p->token.line; parser_line_counter_t start_column = context_p->token.column; -#else /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#else /* !ENABLED (JERRY_ES2015) */ parser_append_object_literal_item (context_p, literal_index, PARSER_OBJECT_PROPERTY_VALUE); -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - if (context_p->token.type == LEXER_LEFT_PAREN) +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_LEFT_PAREN && !is_proto) { parser_parse_object_method (context_p); @@ -849,26 +1100,10 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ break; } - if (context_p->token.type == LEXER_RIGHT_BRACE - || context_p->token.type == LEXER_COMMA) + if ((context_p->token.type == LEXER_RIGHT_BRACE || context_p->token.type == LEXER_COMMA) + && !is_proto) { - /* Re-parse the literal as common identifier. */ - context_p->source_p = context_p->token.lit_location.char_p; - context_p->line = start_line; - context_p->column = start_column; - - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_LITERAL - || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); - } - - lexer_construct_literal_object (context_p, - &context_p->token.lit_location, - context_p->token.lit_location.type); - + parser_reparse_as_common_identifier (context_p, start_line, start_column); parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY; @@ -877,7 +1112,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); break; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_COLON) { @@ -887,6 +1122,14 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); +#if ENABLED (JERRY_ES2015) + if (is_proto) + { + parser_emit_cbc_ext (context_p, CBC_EXT_SET__PROTO__); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY; @@ -911,14 +1154,14 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ } } -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if !ENABLED (JERRY_ES2015) while (context_p->stack_top_uint8 != PARSER_OBJECT_PROPERTY_START) { parser_stack_pop (context_p, NULL, 3); } parser_stack_pop_uint8 (context_p); -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* !ENABLED (JERRY_ES2015) */ } /* parser_parse_object_literal */ /** @@ -934,13 +1177,41 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ uint16_t function_literal_index; int32_t function_name_index = -1; +#if !ENABLED (JERRY_ES2015) + JERRY_ASSERT (status_flags & PARSER_IS_FUNC_EXPRESSION); +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) if (status_flags & PARSER_IS_FUNC_EXPRESSION) { +#endif /* !ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) parser_line_counter_t debugger_line = context_p->token.line; parser_line_counter_t debugger_column = context_p->token.column; #endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015) + uint32_t parent_status_flags = context_p->status_flags; + + context_p->status_flags &= (uint32_t) ~(PARSER_IS_ASYNC_FUNCTION + | PARSER_IS_GENERATOR_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + + if (status_flags & PARSER_IS_ASYNC_FUNCTION) + { + /* The name of the function cannot be await. */ + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } + + if (lexer_consume_generator (context_p)) + { + /* The name of the function cannot be yield. */ + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { lexer_next_token (context_p); @@ -969,15 +1240,18 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ - if (context_p->token.literal_is_reserved - || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) + if (context_p->token.keyword_type >= LEXER_FIRST_NON_STRICT_ARGUMENTS) { status_flags |= PARSER_HAS_NON_STRICT_ARG; } function_name_index = context_p->lit_object.index; } + +#if ENABLED (JERRY_ES2015) + context_p->status_flags = parent_status_flags; } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { @@ -992,10 +1266,6 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ literal2 = context_p->last_cbc.value; context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; } - else - { - parser_flush_cbc (context_p); - } function_literal_index = lexer_construct_function_object (context_p, status_flags); @@ -1028,10 +1298,10 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ } context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL; - context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY; + context_p->last_cbc.literal_keyword_type = LEXER_EOS; } /* parser_parse_function_expression */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) /** * Parse template literal. @@ -1064,21 +1334,21 @@ parser_parse_template_literal (parser_context_t *context_p) /**< context */ { if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) { - context_p->last_cbc_opcode = CBC_ADD_TWO_LITERALS; + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS); } else if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { - context_p->last_cbc_opcode = CBC_ADD_RIGHT_LITERAL; + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL); } else { - parser_emit_cbc (context_p, CBC_ADD); + parser_emit_cbc_ext (context_p, CBC_EXT_STRING_CONCAT); } } context_p->source_p--; context_p->column--; - lexer_parse_string (context_p); + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); if (is_empty_head || context_p->token.lit_location.length > 0) { @@ -1088,20 +1358,21 @@ parser_parse_template_literal (parser_context_t *context_p) /**< context */ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { - context_p->last_cbc_opcode = CBC_ADD_TWO_LITERALS; + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS); context_p->last_cbc.value = context_p->lit_object.index; context_p->last_cbc.literal_type = context_p->token.lit_location.type; - context_p->last_cbc.literal_object_type = context_p->lit_object.type; + context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type; } else { - parser_emit_cbc_literal_from_token (context_p, CBC_ADD_RIGHT_LITERAL); + parser_emit_cbc_ext_literal_from_token (context_p, CBC_EXT_STRING_CONCAT_RIGHT_LITERAL); } } while (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) { lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_RIGHT_BRACE) @@ -1111,16 +1382,16 @@ parser_parse_template_literal (parser_context_t *context_p) /**< context */ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { - context_p->last_cbc_opcode = CBC_ADD_RIGHT_LITERAL; + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL); } else { - parser_emit_cbc (context_p, CBC_ADD); + parser_emit_cbc_ext (context_p, CBC_EXT_STRING_CONCAT); } context_p->source_p--; context_p->column--; - lexer_parse_string (context_p); + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); if (context_p->token.lit_location.length > 0) { @@ -1128,35 +1399,151 @@ parser_parse_template_literal (parser_context_t *context_p) /**< context */ &context_p->token.lit_location, context_p->token.lit_location.type); - parser_emit_cbc_literal_from_token (context_p, CBC_ADD_RIGHT_LITERAL); + parser_emit_cbc_ext_literal_from_token (context_p, CBC_EXT_STRING_CONCAT_RIGHT_LITERAL); + } + } +} /* parser_parse_template_literal */ + +/** + * Parse tagged template literal. + */ +static size_t +parser_parse_tagged_template_literal (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_TEMPLATE_LITERAL); + + uint32_t call_arguments = 0; + ecma_collection_t *collection_p; + + if (context_p->tagged_template_literal_cp == JMEM_CP_NULL) + { + collection_p = ecma_new_collection (); + ECMA_SET_INTERNAL_VALUE_POINTER (context_p->tagged_template_literal_cp, collection_p); + } + else + { + collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, context_p->tagged_template_literal_cp); + if (collection_p->item_count > CBC_MAXIMUM_BYTE_VALUE) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); } } - return; -} /* parser_parse_template_literal */ + const uint32_t tagged_id = collection_p->item_count; + uint32_t prop_idx = 0; + ecma_object_t *raw_strings_p; + ecma_object_t *template_obj_p = parser_new_tagged_template_literal (&raw_strings_p); + ecma_collection_push_back (collection_p, ecma_make_object_value (template_obj_p)); -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ + parser_tagged_template_literal_append_strings (context_p, template_obj_p, raw_strings_p, prop_idx++); + + call_arguments++; + parser_emit_cbc_ext_call (context_p, CBC_EXT_GET_TAGGED_TEMPLATE_LITERAL, tagged_id); + + while (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) + { + JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LEFT_BRACE); + lexer_next_token (context_p); + + if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); + } + + parser_parse_expression (context_p, PARSE_EXPR); + + if (context_p->token.type != LEXER_RIGHT_BRACE) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); + } + + context_p->source_p--; + context_p->column--; + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); + + parser_tagged_template_literal_append_strings (context_p, template_obj_p, raw_strings_p, prop_idx++); + } + + parser_tagged_template_literal_finalize (template_obj_p, raw_strings_p); + + return call_arguments; +} /* parser_parse_tagged_template_literal */ + +/** + * Checks wheteher the current expression can be an assignment expression. + * + * @return true if the current expression can be an assignment expression, false otherwise + */ +static inline bool JERRY_ATTR_ALWAYS_INLINE +parser_is_assignment_expr (parser_context_t *context_p) +{ + return (context_p->stack_top_uint8 == LEXER_EXPRESSION_START + || context_p->stack_top_uint8 == LEXER_LEFT_PAREN + || context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST + || LEXER_IS_BINARY_LVALUE_TOKEN (context_p->stack_top_uint8)); +} /* parser_is_assignment_expr */ + +/** + * Throws an error if the current expression is not an assignment expression. + */ +static inline void JERRY_ATTR_ALWAYS_INLINE +parser_check_assignment_expr (parser_context_t *context_p) +{ + if (!parser_is_assignment_expr (context_p)) + { + parser_raise_error (context_p, PARSER_ERR_ASSIGNMENT_EXPECTED); + } +} /* parser_check_assignment_expr */ + +/** + * Checks whether the next token is a valid continuation token after an AssignmentExpression. + */ +static inline bool JERRY_ATTR_ALWAYS_INLINE +parser_abort_parsing_after_assignment_expression (parser_context_t *context_p) +{ + return (context_p->token.type != LEXER_RIGHT_PAREN + && context_p->token.type != LEXER_COMMA); +} /* parser_abort_parsing_after_assignment_expression */ + +#endif /* ENABLED (JERRY_ES2015) */ /** * Parse and record unary operators, and parse the primary literal. + * + * @return true if parsing should be aborted, true otherwise */ -static void +static bool parser_parse_unary_expression (parser_context_t *context_p, /**< context */ size_t *grouping_level_p) /**< grouping level */ { - int new_was_seen = 0; + bool new_was_seen = false; /* Collect unary operators. */ while (true) { /* Convert plus and minus binary operators to unary operators. */ - if (context_p->token.type == LEXER_ADD) + switch (context_p->token.type) { - context_p->token.type = LEXER_PLUS; - } - else if (context_p->token.type == LEXER_SUBTRACT) - { - context_p->token.type = LEXER_NEGATE; + case LEXER_ADD: + { + context_p->token.type = LEXER_PLUS; + break; + } + case LEXER_SUBTRACT: + { + context_p->token.type = LEXER_NEGATE; + break; + } +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_AWAIT: + { + if (JERRY_UNLIKELY (context_p->token.lit_location.has_escape)) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } /* Bracketed expressions are primary expressions. At this @@ -1164,22 +1551,40 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ * they are processed when their closing paren is reached. */ if (context_p->token.type == LEXER_LEFT_PAREN) { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW); + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); break; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - (*grouping_level_p)++; - new_was_seen = 0; +#endif /* ENABLED (JERRY_ES2015) */ + (*grouping_level_p) += PARSER_GROUPING_LEVEL_INCREASE; + new_was_seen = false; } else if (context_p->token.type == LEXER_KEYW_NEW) { /* After 'new' unary operators are not allowed. */ - new_was_seen = 1; + new_was_seen = true; + +#if ENABLED (JERRY_ES2015) + /* Check if "new.target" is written here. */ + if (scanner_try_scan_new_target (context_p)) + { + if (!(context_p->status_flags & PARSER_ALLOW_NEW_TARGET)) + { + parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED); + } + + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_NEW_TARGET); + lexer_next_token (context_p); + /* Found "new.target" return here */ + return false; + } +#endif /* ENABLED (JERRY_ES2015) */ } - else if (new_was_seen || !LEXER_IS_UNARY_OP_TOKEN (context_p->token.type)) + else if (new_was_seen + || (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE) + || !LEXER_IS_UNARY_OP_TOKEN (context_p->token.type)) { break; } @@ -1191,7 +1596,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ /* Parse primary expression. */ switch (context_p->token.type) { -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) case LEXER_TEMPLATE_LITERAL: { if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) @@ -1203,49 +1608,83 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ /* The string is a normal string literal. */ /* FALLTHRU */ } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_LITERAL: { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (context_p->next_scanner_info_p->source_p == context_p->source_p) +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (context_p->next_scanner_info_p->source_p == context_p->source_p)) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW); - scanner_release_next (context_p, sizeof (scanner_info_t)); + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); - return; + uint32_t arrow_status_flags = (PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) + { + JERRY_ASSERT (lexer_token_is_async (context_p)); + JERRY_ASSERT (!(context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT)); + + uint32_t saved_status_flags = context_p->status_flags; + + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + lexer_next_token (context_p); + context_p->status_flags = saved_status_flags; + + if (context_p->token.type == LEXER_KEYW_FUNCTION) + { + uint32_t status_flags = (PARSER_FUNCTION_CLOSURE + | PARSER_IS_FUNC_EXPRESSION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + parser_parse_function_expression (context_p, status_flags); + break; + } + + arrow_status_flags = (PARSER_IS_FUNCTION + | PARSER_IS_ARROW_FUNCTION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + } + + parser_check_assignment_expr (context_p); + parser_parse_function_expression (context_p, arrow_status_flags); + return parser_abort_parsing_after_assignment_expression (context_p); } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ - if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL - || context_p->token.lit_location.type == LEXER_STRING_LITERAL) + uint8_t type = context_p->token.lit_location.type; + + if (type == LEXER_IDENT_LITERAL || type == LEXER_STRING_LITERAL) { lexer_construct_literal_object (context_p, &context_p->token.lit_location, context_p->token.lit_location.type); + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->status_flags & PARSER_MODULE_STORE_IDENT - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + if ((context_p->status_flags & PARSER_MODULE_STORE_IDENT) + && type == LEXER_IDENT_LITERAL) { - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; context_p->module_identifier_lit_p = context_p->lit_object.literal_p; context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ } - else if (context_p->token.lit_location.type == LEXER_NUMBER_LITERAL) + else if (type == LEXER_NUMBER_LITERAL) { bool is_negative_number = false; - while (context_p->stack_top_uint8 == LEXER_PLUS - || context_p->stack_top_uint8 == LEXER_NEGATE) + if ((context_p->stack_top_uint8 == LEXER_PLUS || context_p->stack_top_uint8 == LEXER_NEGATE) + && !lexer_check_post_primary_exp (context_p)) { - if (context_p->stack_top_uint8 == LEXER_NEGATE) + do { - is_negative_number = !is_negative_number; + if (context_p->stack_top_uint8 == LEXER_NEGATE) + { + is_negative_number = !is_negative_number; + } + parser_stack_pop_uint8 (context_p); } - parser_stack_pop_uint8 (context_p); + while (context_p->stack_top_uint8 == LEXER_PLUS + || context_p->stack_top_uint8 == LEXER_NEGATE); } if (lexer_construct_number_object (context_p, true, is_negative_number)) @@ -1259,14 +1698,14 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ cbc_opcode_t opcode = CBC_PUSH_LITERAL; - if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_EVAL) + if (context_p->token.keyword_type != LEXER_KEYW_EVAL) { if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; context_p->last_cbc.value = context_p->lit_object.index; context_p->last_cbc.literal_type = context_p->token.lit_location.type; - context_p->last_cbc.literal_object_type = context_p->lit_object.type; + context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type; break; } @@ -1275,7 +1714,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ context_p->last_cbc_opcode = CBC_PUSH_THREE_LITERALS; context_p->last_cbc.third_literal_index = context_p->lit_object.index; context_p->last_cbc.literal_type = context_p->token.lit_location.type; - context_p->last_cbc.literal_object_type = context_p->lit_object.type; + context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type; break; } @@ -1291,17 +1730,46 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_FUNC_EXPRESSION | PARSER_IS_CLOSURE); + parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION); break; } case LEXER_LEFT_BRACE: { +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + + if (parser_is_assignment_expr (context_p)) + { + parser_parse_object_initializer (context_p, PARSER_PATTERN_NO_OPTS); + return parser_abort_parsing_after_assignment_expression (context_p); + } + + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_parse_object_literal (context_p); break; } case LEXER_LEFT_SQUARE: { +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + + if (parser_is_assignment_expr (context_p)) + { + parser_parse_array_initializer (context_p, PARSER_PATTERN_NO_OPTS); + return parser_abort_parsing_after_assignment_expression (context_p); + } + + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_parse_array_literal (context_p); break; } @@ -1328,30 +1796,23 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } context_p->last_cbc.literal_type = LEXER_REGEXP_LITERAL; - context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY; + context_p->last_cbc.literal_keyword_type = LEXER_EOS; break; } case LEXER_KEYW_THIS: { -#if ENABLED (JERRY_ES2015_CLASS) - if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)) +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_ALLOW_SUPER_CALL) { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } + parser_emit_cbc_ext (context_p, CBC_EXT_RESOLVE_LEXICAL_THIS); } else { -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ parser_emit_cbc (context_p, CBC_PUSH_THIS); -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ break; } case LEXER_LIT_TRUE: @@ -1369,71 +1830,88 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ parser_emit_cbc (context_p, CBC_PUSH_NULL); break; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { parser_parse_class (context_p, false); - return; + return false; } case LEXER_KEYW_SUPER: { - if ((lexer_check_next_character (context_p, LIT_CHAR_DOT) - || lexer_check_next_character (context_p, LIT_CHAR_LEFT_SQUARE)) - && context_p->status_flags & (PARSER_CLASS_HAS_SUPER)) + if (context_p->status_flags & PARSER_ALLOW_SUPER) { - if (!LEXER_IS_BINARY_LVALUE_TOKEN (context_p->stack_top_uint8)) + if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE)) { - context_p->status_flags |= PARSER_CLASS_SUPER_PROP_REFERENCE; - } - - if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER); break; } - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) + if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN) + && (context_p->status_flags & PARSER_ALLOW_SUPER_CALL)) { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_STATIC_SUPER); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_CONSTRUCTOR); break; } - - bool is_static = (context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0; - parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER); - break; } - if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN) - && ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) - && !(context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)) - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER); - break; - } - - parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_REFERENCE); + parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_KEYWORD); } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) case LEXER_LEFT_PAREN: { JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p - && context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW); - scanner_release_next (context_p, sizeof (scanner_info_t)); + && context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); - lexer_next_token (context_p); - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS); - return; + parser_check_assignment_expr (context_p); + + parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + return parser_abort_parsing_after_assignment_expression (context_p); } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + case LEXER_KEYW_YIELD: + { + JERRY_ASSERT ((context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + && !(context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)); + + if (context_p->token.lit_location.has_escape) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + + parser_check_assignment_expr (context_p); + lexer_next_token (context_p); + + cbc_ext_opcode_t opcode = CBC_EXT_YIELD; + + if (!lexer_check_yield_no_arg (context_p)) + { + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_next_token (context_p); + opcode = CBC_EXT_YIELD_ITERATOR; + } + + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + } + else + { + parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); + } + + parser_emit_cbc_ext (context_p, opcode); + + return (context_p->token.type != LEXER_RIGHT_PAREN + && context_p->token.type != LEXER_COMMA); + } +#endif /* ENABLED (JERRY_ES2015) */ default: { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); + bool is_left_hand_side = (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE); + parser_raise_error (context_p, (is_left_hand_side ? PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED + : PARSER_ERR_PRIMARY_EXP_EXPECTED)); break; } } lexer_next_token (context_p); + return false; } /* parser_parse_unary_expression */ /** @@ -1441,33 +1919,12 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ * generate byte code for the whole expression. */ static void -parser_process_unary_expression (parser_context_t *context_p) /**< context */ +parser_process_unary_expression (parser_context_t *context_p, /**< context */ + size_t grouping_level) /**< grouping level */ { -#if ENABLED (JERRY_ES2015_CLASS) - /* Track to see if a property was accessed or not */ - bool property_accessed = false; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - /* Parse postfix part of a primary expression. */ while (true) { -#if ENABLED (JERRY_ES2015_CLASS) - if (context_p->token.type == LEXER_DOT || context_p->token.type == LEXER_LEFT_SQUARE) - { - if (property_accessed) - { - /** - * In the case of "super.prop1.prop2(...)" the second property access should not - * generate a super prop call thus the 'PARSER_CLASS_SUPER_PROP_REFERENCE' flags should be removed. - * - * Similar case: "super[propname].prop2(...)" - */ - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; - } - property_accessed = true; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - /* Since break would only break the switch, we use * continue to continue this loop. Without continue, * the code abandons the loop. */ @@ -1479,7 +1936,8 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ lexer_expect_identifier (context_p, LEXER_STRING_LITERAL); JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_STRING_LITERAL); + && context_p->lit_object.literal_p->type == LEXER_STRING_LITERAL); + context_p->token.lit_location.type = LEXER_STRING_LITERAL; if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { @@ -1493,6 +1951,13 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_THIS_LITERAL); } +#if ENABLED (JERRY_ES2015) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL); + context_p->last_cbc.literal_index = context_p->lit_object.index; + } +#endif /* ENABLED (JERRY_ES2015) */ else { parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_LITERAL); @@ -1505,6 +1970,15 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ { parser_push_result (context_p); +#if ENABLED (JERRY_ES2015) + uint16_t last_cbc_opcode = context_p->last_cbc_opcode; + + if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_RIGHT_SQUARE) @@ -1513,6 +1987,14 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_PROP); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (PARSER_IS_MUTABLE_PUSH_LITERAL (context_p->last_cbc_opcode)) { context_p->last_cbc_opcode = PARSER_PUSH_LITERAL_TO_PUSH_PROP_LITERAL (context_p->last_cbc_opcode); @@ -1524,6 +2006,9 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ continue; } +#if ENABLED (JERRY_ES2015) + case LEXER_TEMPLATE_LITERAL: +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_LEFT_PAREN: { size_t call_arguments = 0; @@ -1540,10 +2025,9 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ else { if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL - && context_p->last_cbc.literal_object_type == LEXER_LITERAL_OBJECT_EVAL + && context_p->last_cbc.literal_keyword_type == LEXER_KEYW_EVAL && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { - context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; is_eval = true; } @@ -1552,15 +2036,25 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ opcode = CBC_CALL_PROP; context_p->last_cbc_opcode = PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE (context_p->last_cbc_opcode); } -#if ENABLED (JERRY_ES2015_CLASS) - else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER)) +#if ENABLED (JERRY_ES2015) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR)) { opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL); } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - else if (JERRY_UNLIKELY ((context_p->status_flags & (PARSER_INSIDE_WITH | PARSER_RESOLVE_BASE_FOR_CALLS)) - && PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) - && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_REFERENCE); + opcode = CBC_CALL_PROP; + } + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_REFERENCE); + opcode = CBC_CALL_PROP; + } +#endif /* ENABLED (JERRY_ES2015) */ + else if (JERRY_UNLIKELY (context_p->status_flags & PARSER_INSIDE_WITH) + && PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode) + && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { opcode = CBC_CALL_PROP; parser_emit_ident_reference (context_p, CBC_PUSH_IDENT_REFERENCE); @@ -1568,6 +2062,49 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } } +#if ENABLED (JERRY_ES2015) + bool has_spread_element = false; + + if (context_p->token.type == LEXER_TEMPLATE_LITERAL) + { + call_arguments = parser_parse_tagged_template_literal (context_p); + } + else + { + lexer_next_token (context_p); + + while (context_p->token.type != LEXER_RIGHT_PAREN) + { + if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); + } + + if (context_p->token.type == LEXER_THREE_DOTS) + { + has_spread_element = true; + call_arguments++; + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT); + lexer_next_token (context_p); + } + + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + + if (context_p->token.type == LEXER_COMMA) + { + lexer_next_token (context_p); + continue; + } + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); + } + + break; + } + } +#else /* !ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); if (context_p->token.type != LEXER_RIGHT_PAREN) @@ -1593,34 +2130,70 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } } +#endif /* ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); if (is_eval) { -#if ENABLED (JERRY_ES2015_CLASS) - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) + context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + +#if ENABLED (JERRY_ES2015) + uint16_t eval_flags = PARSER_SAVE_STATUS_FLAGS (context_p->status_flags); + const uint32_t required_flags = PARSER_IS_FUNCTION | PARSER_LEXICAL_BLOCK_NEEDED; + + if (context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS) { - parser_flush_cbc (context_p); - context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CLASS_EVAL); - context_p->last_cbc.value = PARSER_GET_CLASS_ECMA_PARSE_OPTS (context_p->status_flags); + context_p->status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; + } + else if (((context_p->status_flags & (required_flags | PARSER_IS_STRICT)) == required_flags) + || ((context_p->global_status_flags & ECMA_PARSE_FUNCTION_CONTEXT) + && !(context_p->status_flags & PARSER_IS_FUNCTION))) + { + eval_flags |= PARSER_GET_EVAL_FLAG (ECMA_PARSE_FUNCTION_CONTEXT); + } + + if (eval_flags != 0) + { + parser_emit_cbc_ext_call (context_p, CBC_EXT_LOCAL_EVAL, eval_flags); } else { -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ parser_emit_cbc (context_p, CBC_EVAL); -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ } -#if ENABLED (JERRY_ES2015_CLASS) - if ((context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) && opcode == CBC_CALL_PROP) +#if ENABLED (JERRY_ES2015) + if (has_spread_element) { - parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_CALL); - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; + uint16_t spread_opcode; + + if (opcode == CBC_CALL) + { + spread_opcode = CBC_EXT_SPREAD_CALL; + } + else if (opcode == CBC_CALL_PROP) + { + spread_opcode = CBC_EXT_SPREAD_CALL_PROP; + } + else if (opcode == CBC_NEW) + { + spread_opcode = CBC_EXT_SPREAD_NEW; + } + else + { + /* opcode is unchanged */ + JERRY_ASSERT (opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL)); + spread_opcode = CBC_EXT_SPREAD_SUPER_CALL; + } + + parser_emit_cbc_ext_call (context_p, spread_opcode, call_arguments); + continue; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ if (call_arguments <= 1) { @@ -1674,7 +2247,8 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } if (!(context_p->token.flags & LEXER_WAS_NEWLINE) - && (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE)) + && (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE) + && grouping_level != PARSE_EXPR_LEFT_HAND_SIDE) { cbc_opcode_t opcode = (context_p->token.type == LEXER_INCREASE) ? CBC_POST_INCR : CBC_POST_DECR; parser_push_result (context_p); @@ -1687,15 +2261,31 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ break; } +#if ENABLED (JERRY_ES2015) + uint8_t last_unary_token = LEXER_INCREASE; +#endif /* ENABLED (JERRY_ES2015) */ + /* Generate byte code for the unary operators. */ while (true) { uint8_t token = context_p->stack_top_uint8; if (!LEXER_IS_UNARY_OP_TOKEN (token)) { +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_EXPONENTIATION + && last_unary_token != LEXER_INCREASE + && last_unary_token != LEXER_DECREASE) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_EXPONENTIATION); + } +#endif /* ENABLED (JERRY_ES2015) */ break; } +#if ENABLED (JERRY_ES2015) + last_unary_token = token; +#endif /* ENABLED (JERRY_ES2015) */ + parser_push_result (context_p); parser_stack_pop_uint8 (context_p); @@ -1711,13 +2301,19 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } parser_emit_unary_lvalue_opcode (context_p, (cbc_opcode_t) token); } +#if ENABLED (JERRY_ES2015) + else if (JERRY_UNLIKELY (token == LEXER_KEYW_AWAIT)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_AWAIT); + } +#endif /* ENABLED (JERRY_ES2015) */ else { token = (uint8_t) (LEXER_UNARY_OP_TOKEN_TO_OPCODE (token)); if (token == CBC_TYPEOF) { - if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) + if (PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { parser_emit_ident_reference (context_p, CBC_TYPEOF_IDENT); @@ -1745,6 +2341,158 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } } /* parser_process_unary_expression */ +/** + * Append a binary '=' token. + * + * @return - pushed assignment opcode onto the parser stack + */ +static uint8_t +parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */ + uint32_t pattern_flags) /**< pattern flags */ +{ + JERRY_UNUSED (pattern_flags); + + /* Unlike other tokens, the whole byte code is saved for binary + * assignment, since it has multiple forms depending on the + * previous instruction. */ + + uint8_t assign_opcode = CBC_ASSIGN; + + if (PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode) + && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) + { + parser_check_invalid_assign (context_p); + + uint16_t literal_index; + + switch (context_p->last_cbc_opcode) + { + case CBC_PUSH_LITERAL: + { + literal_index = context_p->last_cbc.literal_index; + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + break; + } + case CBC_PUSH_TWO_LITERALS: + { + literal_index = context_p->last_cbc.value; + context_p->last_cbc_opcode = CBC_PUSH_LITERAL; + break; + } + case CBC_PUSH_THIS_LITERAL: + { + literal_index = context_p->last_cbc.literal_index; + context_p->last_cbc_opcode = CBC_PUSH_THIS; + parser_flush_cbc (context_p); + break; + } + default: + { + JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); + literal_index = context_p->last_cbc.third_literal_index; + context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; + break; + } + } + + assign_opcode = CBC_ASSIGN_SET_IDENT; + +#if ENABLED (JERRY_ES2015) + if (!(pattern_flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL))) + { + if (scanner_literal_is_const_reg (context_p, literal_index)) + { + parser_stack_push_uint8 (context_p, LEXER_ASSIGN_CONST); + } + } + else if (literal_index < PARSER_REGISTER_START) + { + assign_opcode = CBC_INIT_LET; + + if (scanner_literal_is_created (context_p, literal_index)) + { + assign_opcode = CBC_ASSIGN_LET_CONST; + } + else if (pattern_flags & PARSER_PATTERN_CONST) + { + assign_opcode = CBC_INIT_CONST; + } + else if (pattern_flags & PARSER_PATTERN_LOCAL) + { + assign_opcode = CBC_INIT_ARG_OR_CATCH; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + parser_stack_push_uint16 (context_p, literal_index); + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, assign_opcode)); + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, CBC_ASSIGN)); + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL) + { + if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL, CBC_ASSIGN_PROP_LITERAL)); + parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); + assign_opcode = CBC_ASSIGN_PROP_LITERAL; + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else + { + context_p->last_cbc_opcode = CBC_PUSH_LITERAL; + } + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_PUSH_TWO_LITERALS)); + context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL) + { + if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_THIS_LITERAL, CBC_ASSIGN_PROP_THIS_LITERAL)); + parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); + assign_opcode = CBC_ASSIGN_PROP_THIS_LITERAL; + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else + { + context_p->last_cbc_opcode = CBC_PUSH_THIS_LITERAL; + } + } +#if ENABLED (JERRY_ES2015) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_ASSIGNMENT_REFERENCE); + assign_opcode = CBC_ASSIGN_SUPER; + } + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_ASSIGNMENT_REFERENCE); + assign_opcode = CBC_ASSIGN_SUPER; + } +#endif /* ENABLED (JERRY_ES2015) */ + else + { + /* Invalid LeftHandSide expression. */ +#if ENABLED (JERRY_ES2015) + parser_check_invalid_new_target (context_p, CBC_ASSIGN); +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); + } + + parser_stack_push_uint8 (context_p, assign_opcode); + parser_stack_push_uint8 (context_p, LEXER_ASSIGN); + + return assign_opcode; +} /* parser_append_binary_single_assignment_token */ + /** * Append a binary token. */ @@ -1757,105 +2505,25 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */ if (context_p->token.type == LEXER_ASSIGN) { - /* Unlike other tokens, the whole byte code is saved for binary - * assignment, since it has multiple forms depending on the - * previous instruction. */ - - if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) - && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, CBC_ASSIGN_SET_IDENT)); - - parser_check_invalid_assign (context_p); - - uint16_t literal_index; - - if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) - { - literal_index = context_p->last_cbc.literal_index; - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) - { - literal_index = context_p->last_cbc.value; - context_p->last_cbc_opcode = CBC_PUSH_LITERAL; - } - else - { - JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); - literal_index = context_p->last_cbc.third_literal_index; - context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; - } - - parser_stack_push_uint16 (context_p, literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_SET_IDENT); - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, CBC_ASSIGN)); - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL) - { - if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL, CBC_ASSIGN_PROP_LITERAL)); - parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; -#if ENABLED (JERRY_ES2015_CLASS) - if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) - { - parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN); - parser_flush_cbc (context_p); - } - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - } - else - { - context_p->last_cbc_opcode = CBC_PUSH_LITERAL; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_PUSH_TWO_LITERALS)); - context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL) - { - if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_THIS_LITERAL, CBC_ASSIGN_PROP_THIS_LITERAL)); - parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_THIS_LITERAL); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - else - { - context_p->last_cbc_opcode = CBC_PUSH_THIS_LITERAL; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - } - else - { - /* Invalid LeftHandSide expression. */ - parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } + parser_append_binary_single_assignment_token (context_p, 0); + return; } - else if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type)) + + if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type)) { - if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) + if (PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { parser_check_invalid_assign (context_p); parser_emit_ident_reference (context_p, CBC_PUSH_IDENT_REFERENCE); + +#if ENABLED (JERRY_ES2015) + if (scanner_literal_is_const_reg (context_p, context_p->last_cbc.literal_index)) + { + parser_stack_push_uint8 (context_p, LEXER_ASSIGN_CONST); + } +#endif /* ENABLED (JERRY_ES2015) */ } else if (PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode)) { @@ -1864,6 +2532,10 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */ else { /* Invalid LeftHandSide expression. */ +#if ENABLED (JERRY_ES2015) + parser_check_invalid_new_target (context_p, CBC_ASSIGN); +#endif /* ENABLED (JERRY_ES2015) */ + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); parser_emit_cbc (context_p, CBC_PUSH_PROP_REFERENCE); } @@ -1918,20 +2590,42 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */ opcode = (cbc_opcode_t) context_p->stack_top_uint8; parser_stack_pop_uint8 (context_p); - if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL - && opcode == CBC_ASSIGN_SET_IDENT) - { - JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT, - CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)); - context_p->last_cbc.value = parser_stack_pop_uint16 (context_p); - context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT; - continue; - } - + int32_t index = -1; if (cbc_flags[opcode] & CBC_HAS_LITERAL_ARG) { - uint16_t index = parser_stack_pop_uint16 (context_p); - parser_emit_cbc_literal (context_p, (uint16_t) opcode, index); + JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT + || opcode == CBC_ASSIGN_PROP_LITERAL + || opcode == CBC_ASSIGN_PROP_THIS_LITERAL + || opcode == CBC_ASSIGN_LET_CONST + || opcode == CBC_INIT_ARG_OR_CATCH + || opcode == CBC_INIT_LET + || opcode == CBC_INIT_CONST); + + index = parser_stack_pop_uint16 (context_p); + } + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (context_p->stack_top_uint8 == LEXER_ASSIGN_CONST)) + { + parser_stack_pop_uint8 (context_p); + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_ASSIGN_CONST_ERROR); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (index >= 0) + { + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL + && opcode == CBC_ASSIGN_SET_IDENT) + { + JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT, + CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)); + + context_p->last_cbc.value = (uint16_t) index; + context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT; + continue; + } + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, (uint16_t) index); if (opcode == CBC_ASSIGN_PROP_THIS_LITERAL && (context_p->stack_depth >= context_p->stack_limit)) @@ -1990,6 +2684,496 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */ } } /* parser_process_binary_opcodes */ +#if ENABLED (JERRY_ES2015) +/** + * End position marker of a pattern. + */ +typedef struct +{ + scanner_location_t location; /**< end position of the pattern */ + lexer_token_t token; /**< token at the end position */ +} parser_pattern_end_marker_t; + +/** + * Literal index should not be emitted while processing rhs target value + */ +#define PARSER_PATTERN_RHS_NO_LIT UINT16_MAX + +/** + * Process the target of an initializer pattern. + */ +static parser_pattern_end_marker_t +parser_pattern_get_target (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + parser_pattern_end_marker_t end_marker; + end_marker.token.type = LEXER_INVALID_PATTERN; + parser_branch_t skip_init; + + if (flags & PARSER_PATTERN_TARGET_DEFAULT) + { + JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK); + + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); + } + + if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK) + { + scanner_location_t start_location; + + if (context_p->next_scanner_info_p->source_p != context_p->source_p + || context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED + || (flags & PARSER_PATTERN_REST_ELEMENT)) + { + /* Found invalid pattern, push null value to fake the rhs target. */ + parser_emit_cbc (context_p, CBC_PUSH_NULL); + } + else + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + scanner_get_location (&start_location, context_p); + + scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location); + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + scanner_seek (context_p); + lexer_next_token (context_p); + + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + scanner_get_location (&(end_marker.location), context_p); + end_marker.token = context_p->token; + + scanner_set_location (context_p, &start_location); + scanner_seek (context_p); + parser_flush_cbc (context_p); + } + } + + if (flags & PARSER_PATTERN_TARGET_DEFAULT) + { + parser_set_branch_to_current_position (context_p, &skip_init); + } + + return end_marker; +} /* parser_pattern_get_target */ + +/** + * Finalize an assignment/binding pattern. + */ +static void +parser_pattern_finalize (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + parser_pattern_end_marker_t *end_marker_p) /**< pattern end position */ +{ + if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK) + { + if (end_marker_p->token.type == LEXER_INVALID_PATTERN) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); + } + + scanner_set_location (context_p, &(end_marker_p->location)); + context_p->token = end_marker_p->token; + } + else + { + JERRY_ASSERT (!(flags & PARSER_PATTERN_TARGET_DEFAULT)); + lexer_next_token (context_p); + } + + if ((flags & (PARSER_PATTERN_BINDING | PARSER_PATTERN_NESTED_PATTERN)) == PARSER_PATTERN_BINDING) + { + /* Pop the result of the expression. */ + parser_emit_cbc (context_p, CBC_POP); + } + + parser_flush_cbc (context_p); +} /* parser_pattern_finalize */ + +/** + * Emit right-hand-side target value. + */ +static void +parser_pattern_emit_rhs (parser_context_t *context_p, /**< context */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index) /**< literal index for object pattern */ +{ + if (literal_index != PARSER_PATTERN_RHS_NO_LIT) + { + parser_emit_cbc_ext_literal (context_p, rhs_opcode, literal_index); + } + else + { + parser_emit_cbc_ext (context_p, rhs_opcode); + } +} /* parser_pattern_emit_rhs */ + +/** + * Form an assignment from a pattern. + */ +static void +parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index, /**< literal index for object pattern */ + parser_line_counter_t ident_line_counter) /**< identifier line counter */ +{ + JERRY_UNUSED (ident_line_counter); + + parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); + uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, flags); + + if (flags & PARSER_PATTERN_ARRAY) + { + int32_t stack_adjustment = (CBC_STACK_ADJUST_BASE - (cbc_flags[assign_opcode] >> CBC_STACK_ADJUST_SHIFT)); + JERRY_ASSERT (stack_adjustment >= 1 && stack_adjustment <= 3); + + rhs_opcode = (uint16_t) (rhs_opcode + stack_adjustment - 1); + } + + parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index); + + if (context_p->token.type == LEXER_ASSIGN) + { + parser_branch_t skip_init; + lexer_next_token (context_p); + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); + + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + parser_set_branch_to_current_position (context_p, &skip_init); + } + + parser_process_binary_opcodes (context_p, 0); + + JERRY_ASSERT (context_p->stack_top_uint8 == LEXER_EXPRESSION_START); + parser_stack_pop_uint8 (context_p); + +#if ENABLED (JERRY_DEBUGGER) + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + && ident_line_counter != context_p->last_breakpoint_line) + { + parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED); + parser_flush_cbc (context_p); + + parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter); + + context_p->last_breakpoint_line = ident_line_counter; + } +#endif /* ENABLED (JERRY_DEBUGGER) */ + +#if ENABLED (JERRY_LINE_INFO) + if (ident_line_counter != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, ident_line_counter, false); + } +#endif /* ENABLED (JERRY_LINE_INFO) */ +} /* parser_pattern_form_assignment */ + +/** + * Parse pattern inside a pattern. + */ +static void +parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index) /**< literal index for object pattern */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE); + + parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN + | PARSER_PATTERN_TARGET_ON_STACK + | (flags & (PARSER_PATTERN_BINDING + | PARSER_PATTERN_LET + | PARSER_PATTERN_CONST + | PARSER_PATTERN_LOCAL + | PARSER_PATTERN_REST_ELEMENT + | PARSER_PATTERN_ARGUMENTS))); + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + options |= PARSER_PATTERN_TARGET_DEFAULT; + } + + parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index); + + if (context_p->token.type == LEXER_LEFT_BRACE) + { + parser_parse_object_initializer (context_p, options); + } + else + { + parser_parse_array_initializer (context_p, options); + } + + parser_emit_cbc (context_p, CBC_POP); +} /* parser_pattern_process_nested_pattern */ + +/** + * Process the current {Binding, Assignment}Property + */ +static void +parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index, /**< literal index for object pattern */ + lexer_token_type_t end_type) /**< end type token */ +{ + if (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_pattern_process_nested_pattern (context_p, flags, rhs_opcode, literal_index); + return; + } + + parser_line_counter_t ident_line_counter = context_p->token.line; + + if (flags & PARSER_PATTERN_BINDING) + { + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + if (flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST) + && context_p->token.keyword_type == LEXER_KEYW_LET) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING); + } + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + + if (flags & PARSER_PATTERN_ARGUMENTS) + { + if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + { + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; + } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + parser_module_append_export_name (context_p); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); + lexer_next_token (context_p); + + if (context_p->token.type != end_type + && context_p->token.type != LEXER_ASSIGN + && context_p->token.type != LEXER_COMMA) + { + parser_raise_error (context_p, PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION); + } + } + else + { + parser_flush_cbc (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE); + + if (!PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) && !PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode)) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); + } + } + + parser_pattern_form_assignment (context_p, flags, rhs_opcode, literal_index, ident_line_counter); +} /* parser_pattern_process_assignment */ + +/** + * Parse array initializer. + */ +static void +parser_parse_array_initializer (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags); + flags |= PARSER_PATTERN_ARRAY; + + lexer_next_token (context_p); + parser_emit_cbc_ext (context_p, CBC_EXT_GET_ITERATOR); + + while (context_p->token.type != LEXER_RIGHT_SQUARE) + { + uint16_t rhs_opcode = CBC_EXT_ITERATOR_STEP; + + if (context_p->token.type == LEXER_COMMA) + { + parser_emit_cbc_ext (context_p, rhs_opcode); + parser_emit_cbc (context_p, CBC_POP); + lexer_next_token (context_p); + continue; + } + + parser_pattern_flags_t options = flags; + + if (context_p->token.type == LEXER_THREE_DOTS) + { + lexer_next_token (context_p); + rhs_opcode = CBC_EXT_REST_INITIALIZER; + options |= PARSER_PATTERN_REST_ELEMENT; + } + + parser_pattern_process_assignment (context_p, options, rhs_opcode, PARSER_PATTERN_RHS_NO_LIT, LEXER_RIGHT_SQUARE); + + if (context_p->token.type == LEXER_COMMA && rhs_opcode != CBC_EXT_REST_INITIALIZER) + { + lexer_next_token (context_p); + } + else if (context_p->token.type != LEXER_RIGHT_SQUARE) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); + } + } + + /* close the iterator */ + parser_emit_cbc_ext (context_p, CBC_EXT_ITERATOR_CLOSE); + + parser_pattern_finalize (context_p, flags, &end_pos); +} /* parser_parse_array_initializer */ + +/** + * Parse object initializer. + */ +static void +parser_parse_object_initializer (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags); + + /* 12.14.5.2: ObjectAssignmentPattern : { } */ + if (lexer_check_next_character (context_p, LIT_CHAR_RIGHT_BRACE)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_REQUIRE_OBJECT_COERCIBLE); + lexer_consume_next_character (context_p); + parser_pattern_finalize (context_p, flags, &end_pos); + return; + } + + while (true) + { + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJECT_PATTERN); + + uint16_t prop_index = context_p->lit_object.index; + parser_line_counter_t start_line = context_p->token.line; + parser_line_counter_t start_column = context_p->token.column; + uint16_t push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP_LITERAL; + + if (context_p->token.type == LEXER_RIGHT_BRACE) + { + break; + } + else if (context_p->token.type == LEXER_RIGHT_SQUARE) + { + prop_index = PARSER_PATTERN_RHS_NO_LIT; + push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP; + } + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_COLON) + { + lexer_next_token (context_p); + parser_pattern_process_assignment (context_p, flags, push_prop_opcode, prop_index, LEXER_RIGHT_BRACE); + } + else + { + if (push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_PROP) + { + parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); + } + + if (context_p->token.type != LEXER_RIGHT_BRACE + && context_p->token.type != LEXER_ASSIGN + && context_p->token.type != LEXER_COMMA) + { + parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED); + } + + parser_reparse_as_common_identifier (context_p, start_line, start_column); + lexer_next_token (context_p); + + JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE + || context_p->token.type == LEXER_ASSIGN + || context_p->token.type == LEXER_COMMA); + + if (flags & PARSER_PATTERN_ARGUMENTS) + { + if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + { + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; + } + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + parser_module_append_export_name (context_p); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); + parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line); + } + + if (context_p->token.type == LEXER_RIGHT_BRACE) + { + break; + } + else if (context_p->token.type != LEXER_COMMA) + { + parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED); + } + } + + parser_pattern_finalize (context_p, flags, &end_pos); +} /* parser_parse_object_initializer */ + +/** + * Parse an initializer. + */ +void +parser_parse_initializer (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + if (context_p->token.type == LEXER_LEFT_BRACE) + { + parser_parse_object_initializer (context_p, flags); + } + else + { + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE); + parser_parse_array_initializer (context_p, flags); + } +} /* parser_parse_initializer */ + +/** + * Parse an initializer using the next character. + */ +void +parser_parse_initializer_by_next_char (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + JERRY_ASSERT (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)); + + if (lexer_consume_next_character (context_p) == LIT_CHAR_LEFT_BRACE) + { + parser_parse_object_initializer (context_p, flags); + } + else + { + parser_parse_array_initializer (context_p, flags); + } +} /* parser_parse_initializer_by_next_char */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Process ternary expression. */ @@ -2036,6 +3220,8 @@ parser_process_ternary_expression (parser_context_t *context_p) /**< context */ /* Last opcode rewrite is not allowed because * the result may come from the first branch. */ parser_flush_cbc (context_p); + + parser_process_binary_opcodes (context_p, 0); } /* parser_process_ternary_expression */ /** @@ -2069,8 +3255,8 @@ static void parser_process_group_expression (parser_context_t *context_p, /**< context */ size_t *grouping_level_p) /**< grouping level */ { - JERRY_ASSERT (*grouping_level_p > 0); - (*grouping_level_p)--; + JERRY_ASSERT (*grouping_level_p >= PARSER_GROUPING_LEVEL_INCREASE); + (*grouping_level_p) -= PARSER_GROUPING_LEVEL_INCREASE; if (context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST) { @@ -2080,6 +3266,19 @@ parser_process_group_expression (parser_context_t *context_p, /**< context */ parser_stack_pop_uint8 (context_p); lexer_next_token (context_p); + +#if ENABLED (JERRY_ES2015) + /* Lookahead for anonymous function declaration after '=' token when the assignment base is LHS expression + with a single indentifier in it. e.g.: (a) = function () {} */ + if (JERRY_UNLIKELY (context_p->token.type == LEXER_ASSIGN + && PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode) + && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL + && parser_is_assignment_expr (context_p))) + { + parser_stack_push_uint8 (context_p, LEXER_ASSIGN_GROUP_EXPR); + } +#endif /* ENABLED (JERRY_ES2015) */ + } /* parser_process_group_expression */ /** @@ -2118,6 +3317,9 @@ parser_parse_expression_statement (parser_context_t *context_p, /**< context */ } } /* parser_parse_expression_statement */ +JERRY_STATIC_ASSERT (PARSE_EXPR_LEFT_HAND_SIDE == 0x1, + value_of_parse_expr_left_hand_side_must_be_1); + /** * Parse expression. */ @@ -2125,20 +3327,10 @@ void parser_parse_expression (parser_context_t *context_p, /**< context */ int options) /**< option flags */ { - size_t grouping_level = 0; + size_t grouping_level = (options & PARSE_EXPR_LEFT_HAND_SIDE); parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); -#if ENABLED (JERRY_ES2015_CLASS) - /* Parsing a new expression: - * So save, remove, and at the end restore the super prop reference indicator. - * - * If this is not done, it is possible to carry the flag over to the next expression. - */ - bool has_super_ref = (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE); - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; -#endif - if (options & PARSE_EXPR_HAS_LITERAL) { JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); @@ -2147,29 +3339,47 @@ parser_parse_expression (parser_context_t *context_p, /**< context */ while (true) { - parser_parse_unary_expression (context_p, &grouping_level); + if (parser_parse_unary_expression (context_p, &grouping_level)) + { + parser_process_binary_opcodes (context_p, 0); + break; + } while (true) { process_unary_expression: - parser_process_unary_expression (context_p); + parser_process_unary_expression (context_p, grouping_level); - uint8_t min_prec_treshold = 0; - - if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) + if (JERRY_LIKELY (grouping_level != PARSE_EXPR_LEFT_HAND_SIDE)) { - min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP]; + uint8_t min_prec_treshold = 0; - /* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND */ - if (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE - && min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE) + if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) { - /* Right-to-left evaluation order. */ - min_prec_treshold++; - } - } + min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP]; - parser_process_binary_opcodes (context_p, min_prec_treshold); +#if ENABLED (JERRY_ES2015) + /* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND + LEXER_EXPONENTIATION */ + if ((min_prec_treshold == PARSER_RIGHT_TO_LEFT_ORDER_EXPONENTIATION) + || (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE + && min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE)) + { + /* Right-to-left evaluation order. */ + min_prec_treshold++; + } +#else /* !ENABLED (JERRY_ES2015) */ + /* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND */ + if (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE + && min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE) + { + /* Right-to-left evaluation order. */ + min_prec_treshold++; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + parser_process_binary_opcodes (context_p, min_prec_treshold); + } if (context_p->token.type == LEXER_RIGHT_PAREN && (context_p->stack_top_uint8 == LEXER_LEFT_PAREN @@ -2179,31 +3389,41 @@ process_unary_expression: continue; } - if (context_p->token.type == LEXER_QUESTION_MARK) - { - parser_process_ternary_expression (context_p); - continue; - } break; } - if (JERRY_UNLIKELY (context_p->token.type == LEXER_COMMA) - && (!(options & PARSE_EXPR_NO_COMMA) || grouping_level > 0)) + if (grouping_level == PARSE_EXPR_LEFT_HAND_SIDE) { - parser_process_expression_sequence (context_p); - continue; + break; } - if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) + if (JERRY_UNLIKELY (context_p->token.type == LEXER_QUESTION_MARK)) + { + parser_process_ternary_expression (context_p); + + if (context_p->token.type == LEXER_RIGHT_PAREN) + { + goto process_unary_expression; + } + } + else if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) { parser_append_binary_token (context_p); lexer_next_token (context_p); continue; } + + if (JERRY_UNLIKELY (context_p->token.type == LEXER_COMMA) + && (!(options & PARSE_EXPR_NO_COMMA) || grouping_level >= PARSER_GROUPING_LEVEL_INCREASE)) + { + parser_process_expression_sequence (context_p); + continue; + } + break; } - if (grouping_level != 0) + if (grouping_level >= PARSER_GROUPING_LEVEL_INCREASE) { parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } @@ -2215,14 +3435,6 @@ process_unary_expression: { parser_push_result (context_p); } - -#if ENABLED (JERRY_ES2015_CLASS) - /* Restore the super prop ref flag. */ - if (has_super_ref) - { - context_p->status_flags |= (uint32_t) PARSER_CLASS_SUPER_PROP_REFERENCE; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ } /* parser_parse_expression */ /** diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d756f6da..87085732 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -48,46 +48,42 @@ typedef enum PARSER_IS_FUNC_EXPRESSION = (1u << 3), /**< a function expression is parsed */ PARSER_IS_PROPERTY_GETTER = (1u << 4), /**< a property getter function is parsed */ PARSER_IS_PROPERTY_SETTER = (1u << 5), /**< a property setter function is parsed */ -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - PARSER_FUNCTION_HAS_REST_PARAM = (1u << 6), /**< function has rest parameter */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - PARSER_HAS_NON_STRICT_ARG = (1u << 7), /**< the function has arguments which + PARSER_HAS_NON_STRICT_ARG = (1u << 6), /**< the function has arguments which * are not supported in strict mode */ - PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */ - PARSER_ARGUMENTS_NOT_NEEDED = (1u << 9), /**< arguments object must NOT be created */ - PARSER_LEXICAL_ENV_NEEDED = (1u << 10), /**< lexical environment object must be created */ - PARSER_NO_REG_STORE = (1u << 11), /**< all local variables must be stored - * in the lexical environment object */ - PARSER_INSIDE_WITH = (1u << 12), /**< code block is inside a with statement */ - PARSER_RESOLVE_BASE_FOR_CALLS = (1u << 13), /**< the this object must be resolved when - * a function without a base object is called */ - PARSER_HAS_INITIALIZED_VARS = (1u << 14), /**< a CBC_INITIALIZE_VARS instruction must be emitted */ - PARSER_HAS_LATE_LIT_INIT = (1u << 15), /**< allocate memory for this string after - * the local parser data is freed */ - PARSER_NO_END_LABEL = (1u << 16), /**< return instruction must be inserted + PARSER_ARGUMENTS_NEEDED = (1u << 7), /**< arguments object must be created */ + PARSER_LEXICAL_ENV_NEEDED = (1u << 8), /**< lexical environment object must be created */ + PARSER_INSIDE_WITH = (1u << 9), /**< code block is inside a with statement */ + PARSER_NO_END_LABEL = (1u << 10), /**< return instruction must be inserted * after the last byte code */ - PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 17), /**< pending (unsent) breakpoint + PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 11), /**< pending (unsent) breakpoint * info is available */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - PARSER_IS_ARROW_FUNCTION = (1u << 18), /**< an arrow function is parsed */ - PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) - /* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ - PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in - * in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */ - PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */ - PARSER_CLASS_IMPLICIT_SUPER = (1u << 22), /**< class has implicit parent class */ - PARSER_CLASS_STATIC_FUNCTION = (1u << 23), /**< this function is a static class method */ - PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 24), /**< super property call or assignment */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) + PARSER_LEXICAL_BLOCK_NEEDED = (1u << 12), /**< global script: needs a lexical environment for let and const + * function: needs a lexical environment for arguments */ + PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */ + PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */ + PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */ + PARSER_DISALLOW_AWAIT_YIELD = (1u << 16), /**< throw SyntaxError for await / yield keywords */ + PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 17), /**< set when parsing function arguments */ + PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 18), /**< function has a non simple parameter */ + PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */ + PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed + * Note: PARSER_ALLOW_SUPER must be present */ + /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ + PARSER_ALLOW_SUPER = (1u << 21), /**< allow super property access */ + PARSER_ALLOW_SUPER_CALL = (1u << 22), /**< allow super constructor call + * Note: PARSER_CLASS_CONSTRUCTOR must be present */ + PARSER_ALLOW_NEW_TARGET = (1u << 23), /**< allow new.target parsing in the current context */ + +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 25), /**< parsing a function or class default export */ - PARSER_MODULE_STORE_IDENT = (1u << 26), /**< store identifier of the current export statement */ - PARSER_IS_EVAL = (1u << 27), /**< eval code */ + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 24), /**< parsing a function or class default export */ + PARSER_MODULE_STORE_IDENT = (1u << 25), /**< store identifier of the current export statement */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction + * is postponed after the local parser data is freed */ #ifndef JERRY_NDEBUG - PARSER_SCANNING_SUCCESSFUL = (1u << 30), /**< scanning process was successful */ + PARSER_SCANNING_SUCCESSFUL = PARSER_HAS_LATE_LIT_INIT, /**< scanning process was successful */ #endif /* !JERRY_NDEBUG */ } parser_general_flags_t; @@ -97,64 +93,133 @@ typedef enum typedef enum { PARSE_EXPR = 0, /**< parse an expression without any special flags */ - PARSE_EXPR_NO_PUSH_RESULT = (1u << 0), /**< do not push the result of the expression onto the stack */ - PARSE_EXPR_NO_COMMA = (1u << 1), /**< do not parse comma operator */ - PARSE_EXPR_HAS_LITERAL = (1u << 2), /**< a primary literal is provided by a + PARSE_EXPR_LEFT_HAND_SIDE = (1u << 0), /**< parse a left-hand-side expression */ + PARSE_EXPR_NO_PUSH_RESULT = (1u << 1), /**< do not push the result of the expression onto the stack */ + PARSE_EXPR_NO_COMMA = (1u << 2), /**< do not parse comma operator */ + PARSE_EXPR_HAS_LITERAL = (1u << 3), /**< a primary literal is provided by a * CBC_PUSH_LITERAL instruction */ } parser_expression_flags_t; +/** + * Pattern parsing flags. + */ +typedef enum +{ + PARSER_PATTERN_NO_OPTS = 0, /**< parse the expression after '=' */ + PARSER_PATTERN_BINDING = (1u << 0), /**< parse BindingPattern */ + PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */ + PARSER_PATTERN_TARGET_DEFAULT = (1u << 2), /**< perform default value comparison for assignment target */ + PARSER_PATTERN_NESTED_PATTERN = (1u << 3), /**< parse patter inside a pattern */ + PARSER_PATTERN_LET = (1u << 4), /**< pattern is a let declaration */ + PARSER_PATTERN_CONST = (1u << 5), /**< pattern is a const declaration */ + PARSER_PATTERN_LOCAL = (1u << 6), /**< pattern is a local (catch parameter) declaration */ + PARSER_PATTERN_REST_ELEMENT = (1u << 7), /**< parse rest array initializer */ + PARSER_PATTERN_ARGUMENTS = (1u << 8), /**< parse arguments binding */ + PARSER_PATTERN_ARRAY = (1u << 9), /**< array pattern is being parsed */ +} parser_pattern_flags_t; + +/** + * Check type for scanner_is_context_needed function. + */ +typedef enum +{ + PARSER_CHECK_BLOCK_CONTEXT, /**< check block context */ +#if ENABLED (JERRY_ES2015) + PARSER_CHECK_GLOBAL_CONTEXT, /**< check global context */ + PARSER_CHECK_FUNCTION_CONTEXT, /**< check function context */ +#endif /* ENABLED (JERRY_ES2015) */ +} parser_check_context_type_t; + /** * Mask for strict mode code */ #define PARSER_STRICT_MODE_MASK 0x1 -#if ENABLED (JERRY_ES2015_CLASS) /** - * Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR + * Shorthand for function closure definition */ -#define PARSER_CLASS_PARSE_OPTS_OFFSET \ - (JERRY_LOG2 (PARSER_CLASS_CONSTRUCTOR) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) +#define PARSER_FUNCTION_CLOSURE (PARSER_IS_FUNCTION | PARSER_IS_CLOSURE) + +#if PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX +/** + * Maximum number of bytes for branch target. + */ +#define PARSER_MAX_BRANCH_LENGTH 2 +#else /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */ +/** + * Maximum number of bytes for branch target. + */ +#define PARSER_MAX_BRANCH_LENGTH 3 +#endif /* PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX */ + +#if ENABLED (JERRY_ES2015) +/** + * Offset of PARSER_ALLOW_SUPER + */ +#define PARSER_SAVED_FLAGS_OFFSET \ + JERRY_LOG2 (PARSER_ALLOW_SUPER) /** - * Count of ecma_parse_opts_t class parsing options related bits + * Mask of saved flags */ -#define PARSER_CLASS_PARSE_OPTS_COUNT \ - (JERRY_LOG2 (ECMA_PARSE_HAS_STATIC_SUPER) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) - -/** - * Mask for get class option bits from ecma_parse_opts_t - */ -#define PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK \ - (((1 << PARSER_CLASS_PARSE_OPTS_COUNT) - 1) << JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) - -/** - * Get class option bits from ecma_parse_opts_t - */ -#define PARSER_GET_CLASS_PARSER_OPTS(opts) \ - (((opts) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK) << PARSER_CLASS_PARSE_OPTS_OFFSET) +#define PARSER_SAVED_FLAGS_MASK \ + ((1 << (JERRY_LOG2 (PARSER_ALLOW_NEW_TARGET) - JERRY_LOG2 (PARSER_ALLOW_SUPER) + 1)) - 1) /** * Get class option bits from parser_general_flags_t */ -#define PARSER_GET_CLASS_ECMA_PARSE_OPTS(opts) \ - ((uint16_t) (((opts) >> PARSER_CLASS_PARSE_OPTS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK)) +#define PARSER_SAVE_STATUS_FLAGS(opts) \ + ((uint16_t) (((opts) >> PARSER_SAVED_FLAGS_OFFSET) & PARSER_SAVED_FLAGS_MASK)) /** - * Class constructor with heritage context representing bits + * Mask for get class option bits from ecma_parse_opts_t */ -#define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER) +#define PARSER_RESTORE_STATUS_FLAGS_MASK \ + (((ECMA_PARSE_ALLOW_NEW_TARGET << 1) - 1) - (ECMA_PARSE_ALLOW_SUPER - 1)) /** - * Check the scope is a class constructor with heritage context + * Shift for get class option bits from ecma_parse_opts_t */ -#define PARSER_IS_CLASS_CONSTRUCTOR_SUPER(flag) \ - (((flag) & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#define PARSER_RESTORE_STATUS_FLAGS_SHIFT \ + (JERRY_LOG2 (PARSER_ALLOW_SUPER) - JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER)) + +/** + * Get class option bits from ecma_parse_opts_t + */ +#define PARSER_RESTORE_STATUS_FLAGS(opts) \ + (((opts) & PARSER_RESTORE_STATUS_FLAGS_MASK) << PARSER_RESTORE_STATUS_FLAGS_SHIFT) + +/** + * All flags that affect exotic arguments object creation. + */ +#define PARSER_ARGUMENTS_RELATED_FLAGS \ + (PARSER_ARGUMENTS_NEEDED | PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM | PARSER_IS_STRICT) + +/** + * Get the corresponding eval flag for a ecma_parse_opts_t flag + */ +#define PARSER_GET_EVAL_FLAG(type) \ + ((type) >> JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER)) + +#else /* !ENABLED (JERRY_ES2015) */ + +/** + * All flags that affect exotic arguments object creation. + */ +#define PARSER_ARGUMENTS_RELATED_FLAGS \ + (PARSER_ARGUMENTS_NEEDED | PARSER_IS_STRICT) + +#endif /* ENABLED (JERRY_ES2015) */ + +/* Checks whether unmapped arguments are needed. */ +#define PARSER_NEEDS_MAPPED_ARGUMENTS(status_flags) \ + (((status_flags) & PARSER_ARGUMENTS_RELATED_FLAGS) == PARSER_ARGUMENTS_NEEDED) /* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */ #define PARSER_CBC_STREAM_PAGE_SIZE \ ((uint32_t) (64 - sizeof (void *))) +/* Defines the size of the max page. */ #define PARSER_STACK_PAGE_SIZE \ ((uint32_t) (((sizeof (void *) > 4) ? 128 : 64) - sizeof (void *))) @@ -172,7 +237,7 @@ typedef struct uint16_t value; /**< other argument (second literal or byte). */ uint16_t third_literal_index; /**< literal index argument */ uint8_t literal_type; /**< last literal type */ - uint8_t literal_object_type; /**< last literal object type */ + uint8_t literal_keyword_type; /**< last literal keyword type */ } cbc_argument_t; /* Useful parser macros. */ @@ -313,6 +378,59 @@ typedef struct parser_branch_node_t parser_branch_t branch; /**< branch */ } parser_branch_node_t; +/** + * Items of scope stack. + */ +typedef struct +{ + uint16_t map_from; /**< original literal index */ + uint16_t map_to; /**< encoded register or literal index and flags */ +} parser_scope_stack_t; + +/** + * This item represents a function literal in the scope stack. + * + * When map_from == PARSER_SCOPE_STACK_FUNC: + * map_to represents the literal reserved for a function literal + * Note: the name of the function is the previous value in the scope stack + * Note: map_to is not encoded in this case + */ +#define PARSER_SCOPE_STACK_FUNC 0xffff + +#if ENABLED (JERRY_ES2015) + +/** + * Mask for decoding the register index of map_to + */ +#define PARSER_SCOPE_STACK_REGISTER_MASK 0x3fff + +/** + * Function statements with the name specified + * in map_from should not be copied to global scope. + */ +#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x8000 + +/** + * The scope stack item represents a const binding stored in register + */ +#define PARSER_SCOPE_STACK_IS_CONST_REG 0x4000 + +/** + * The scope stack item represents a binding which has already created with ECMA_VALUE_UNINITIALIZED + */ +#define PARSER_SCOPE_STACK_IS_LOCAL_CREATED (PARSER_SCOPE_STACK_IS_CONST_REG) + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Starting literal index for registers. + */ +#define PARSER_REGISTER_START 0x8000 + +/* Forward definitions for js-scanner-internal.h. */ +struct scanner_context_t; +typedef struct scanner_context_t scanner_context_t; + #if ENABLED (JERRY_DEBUGGER) /** * Extra information for each breakpoint. @@ -352,6 +470,14 @@ typedef struct parser_saved_context_t parser_mem_data_t byte_code; /**< byte code buffer */ uint32_t byte_code_size; /**< byte code size for branches */ parser_mem_data_t literal_pool_data; /**< literal list */ + parser_scope_stack_t *scope_stack_p; /**< scope stack */ + uint16_t scope_stack_size; /**< size of scope stack */ + uint16_t scope_stack_top; /**< preserved top of scope stack */ + uint16_t scope_stack_reg_top; /**< preserved top register of scope stack */ +#if ENABLED (JERRY_ES2015) + uint16_t scope_stack_global_end; /**< end of global declarations of a function */ + ecma_value_t tagged_template_literal_cp; /**< compessed pointer to the tagged template literal collection */ +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG uint16_t context_stack_depth; /**< current context stack depth */ @@ -365,12 +491,18 @@ typedef struct { PARSER_TRY_CONTEXT (try_buffer); /**< try_buffer */ parser_error_t error; /**< error code */ - void *allocated_buffer_p; /**< dinamically allocated buffer + /** Union for rarely used members. */ + union + { + void *allocated_buffer_p; /**< dinamically allocated buffer * which needs to be freed on error */ + scanner_context_t *scanner_context_p; /**< scanner context for the pre-scanner */ + } u; uint32_t allocated_buffer_size; /**< size of the dinamically allocated buffer */ /* Parser members. */ uint32_t status_flags; /**< status flags */ + uint32_t global_status_flags; /**< global status flags */ uint16_t stack_depth; /**< current stack depth */ uint16_t stack_limit; /**< maximum stack depth */ parser_saved_context_t *last_context_p; /**< last saved context */ @@ -409,7 +541,15 @@ typedef struct uint32_t byte_code_size; /**< current byte code size for branches */ parser_list_t literal_pool; /**< literal list */ parser_mem_data_t stack; /**< storage space */ + parser_scope_stack_t *scope_stack_p; /**< scope stack */ parser_mem_page_t *free_page_p; /**< space for fast allocation */ + uint16_t scope_stack_size; /**< size of scope stack */ + uint16_t scope_stack_top; /**< current top of scope stack */ + uint16_t scope_stack_reg_top; /**< current top register of scope stack */ +#if ENABLED (JERRY_ES2015) + uint16_t scope_stack_global_end; /**< end of global declarations of a function */ + ecma_value_t tagged_template_literal_cp; /**< compessed pointer to the tagged template literal collection */ +#endif /* ENABLED (JERRY_ES2015) */ uint8_t stack_top_uint8; /**< top byte stored on the stack */ #ifndef JERRY_NDEBUG @@ -451,6 +591,7 @@ void *parser_malloc (parser_context_t *context_p, size_t size); void parser_free (void *ptr, size_t size); void *parser_malloc_local (parser_context_t *context_p, size_t size); void parser_free_local (void *ptr, size_t size); +void parser_free_allocated_buffer (parser_context_t *context_p); /* Parser byte stream. */ @@ -502,6 +643,8 @@ void parser_stack_iterator_write (parser_stack_iterator_t *iterator, const void void parser_flush_cbc (parser_context_t *context_p); void parser_emit_cbc (parser_context_t *context_p, uint16_t opcode); void parser_emit_cbc_literal (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index); +void parser_emit_cbc_literal_value (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index, + uint16_t value); void parser_emit_cbc_literal_from_token (parser_context_t *context_p, uint16_t opcode); void parser_emit_cbc_call (parser_context_t *context_p, uint16_t opcode, size_t call_arguments); void parser_emit_cbc_push_number (parser_context_t *context_p, bool is_negative_number); @@ -518,6 +661,10 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars parser_emit_cbc ((context_p), PARSER_TO_EXT_OPCODE (opcode)) #define parser_emit_cbc_ext_literal(context_p, opcode, literal_index) \ parser_emit_cbc_literal ((context_p), PARSER_TO_EXT_OPCODE (opcode), (literal_index)) +#define parser_emit_cbc_ext_literal_from_token(context_p, opcode) \ + parser_emit_cbc_literal_from_token ((context_p), PARSER_TO_EXT_OPCODE (opcode)) +#define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \ + parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments)) #define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \ parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments)) #define parser_emit_cbc_ext_forward_branch(context_p, opcode, branch_p) \ @@ -536,26 +683,45 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars void lexer_next_token (parser_context_t *context_p); bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t character); -#if ENABLED (JERRY_ES2015_CLASS) +bool lexer_check_next_characters (parser_context_t *context_p, lit_utf8_byte_t character1, + lit_utf8_byte_t character2); +uint8_t lexer_consume_next_character (parser_context_t *context_p); +bool lexer_check_post_primary_exp (parser_context_t *context_p); +#if ENABLED (JERRY_ES2015) void lexer_skip_empty_statements (parser_context_t *context_p); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) bool lexer_check_arrow (parser_context_t *context_p); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -void lexer_parse_string (parser_context_t *context_p); +bool lexer_check_arrow_param (parser_context_t *context_p); +bool lexer_check_yield_no_arg (parser_context_t *context_p); +bool lexer_consume_generator (parser_context_t *context_p); +void lexer_update_await_yield (parser_context_t *context_p, uint32_t status_flags); +#endif /* ENABLED (JERRY_ES2015) */ +void lexer_parse_string (parser_context_t *context_p, lexer_string_options_t opts); void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type); -void lexer_scan_identifier (parser_context_t *context_p, uint32_t ident_opts); -ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *source_p, int length); +bool lexer_scan_identifier (parser_context_t *context_p); +void lexer_check_property_modifier (parser_context_t *context_p); +void lexer_convert_ident_to_cesu8 (uint8_t *destination_p, const uint8_t *source_p, prop_length_t length); + +const uint8_t *lexer_convert_literal_to_chars (parser_context_t *context_p, const lexer_lit_location_t *literal_p, + uint8_t *local_byte_array_p, lexer_string_options_t opts); void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts); -void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p, +void lexer_construct_literal_object (parser_context_t *context_p, const lexer_lit_location_t *lit_location_p, uint8_t literal_type); bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number); void lexer_convert_push_number_to_push_literal (parser_context_t *context_p); uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags); void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only); -bool lexer_compare_identifier_to_current (parser_context_t *context_p, const lexer_lit_location_t *right_ident_p); -bool lexer_compare_literal_to_identifier (parser_context_t *context_p, const char *identifier_p, - size_t identifier_length); +bool lexer_compare_identifier_to_string (const lexer_lit_location_t *left_p, const uint8_t *right_p, size_t size); +bool lexer_compare_identifiers (parser_context_t *context_p, const lexer_lit_location_t *left_p, + const lexer_lit_location_t *right_p); +bool lexer_current_is_literal (parser_context_t *context_p, const lexer_lit_location_t *right_ident_p); +bool lexer_string_is_use_strict (parser_context_t *context_p); +bool lexer_string_is_directive (parser_context_t *context_p); +#if ENABLED (JERRY_ES2015) +bool lexer_token_is_identifier (parser_context_t *context_p, const char *identifier_p, + size_t identifier_length); +bool lexer_token_is_let (parser_context_t *context_p); +bool lexer_token_is_async (parser_context_t *context_p); +#endif /* ENABLED (JERRY_ES2015) */ bool lexer_compare_literal_to_string (parser_context_t *context_p, const char *string_p, size_t string_length); uint8_t lexer_convert_binary_lvalue_token_to_binary (uint8_t token); @@ -571,11 +737,11 @@ uint8_t lexer_convert_binary_lvalue_token_to_binary (uint8_t token); void parser_parse_block_expression (parser_context_t *context_p, int options); void parser_parse_expression_statement (parser_context_t *context_p, int options); void parser_parse_expression (parser_context_t *context_p, int options); -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) void parser_parse_class (parser_context_t *context_p, bool is_statement); -void parser_parse_super_class_context_start (parser_context_t *context_p); -void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_statement); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +void parser_parse_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); +void parser_parse_initializer_by_next_char (parser_context_t *context_p, parser_pattern_flags_t flags); +#endif /* ENABLED (JERRY_ES2015) */ /** * @} @@ -584,21 +750,30 @@ void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_ * @{ */ -void scanner_raise_error (parser_context_t *context_p); -void *scanner_malloc (parser_context_t *context_p, size_t size); -void scanner_free (void *ptr, size_t size); - -scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, size_t size); void scanner_release_next (parser_context_t *context_p, size_t size); void scanner_set_active (parser_context_t *context_p); +void scanner_revert_active (parser_context_t *context_p); void scanner_release_active (parser_context_t *context_p, size_t size); void scanner_release_switch_cases (scanner_case_info_t *case_p); void scanner_seek (parser_context_t *context_p); void scanner_reverse_info_list (parser_context_t *context_p); void scanner_cleanup (parser_context_t *context_p); +bool scanner_is_context_needed (parser_context_t *context_p, parser_check_context_type_t check_type); +#if ENABLED (JERRY_ES2015) +bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p); +bool scanner_try_scan_new_target (parser_context_t *context_p); +void scanner_check_variables (parser_context_t *context_p); +#endif /* ENABLED (JERRY_ES2015) */ +void scanner_create_variables (parser_context_t *context_p, uint32_t option_flags); + void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p); void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p); +uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p); +#if ENABLED (JERRY_ES2015) +bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index); +bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index); +#endif /* ENABLED (JERRY_ES2015) */ void scanner_scan_all (parser_context_t *context_p, const uint8_t *arg_list_p, const uint8_t *arg_list_end_p, const uint8_t *source_p, const uint8_t *source_end_p); @@ -634,6 +809,7 @@ void parser_module_set_default (parser_context_t *context_p); ecma_module_node_t *parser_module_create_module_node (parser_context_t *context_p); bool parser_module_check_duplicate_import (parser_context_t *context_p, ecma_string_t *local_name_p); bool parser_module_check_duplicate_export (parser_context_t *context_p, ecma_string_t *export_name_p); +void parser_module_append_export_name (parser_context_t *context_p); void parser_module_add_names_to_node (parser_context_t *context_p, ecma_string_t *imex_name_p, ecma_string_t *local_name_p); @@ -648,9 +824,9 @@ void parser_module_add_names_to_node (parser_context_t *context_p, */ ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32_t status_flags); -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ /* Error management. */ diff --git a/jerry-core/parser/js/js-parser-limits.h b/jerry-core/parser/js/js-parser-limits.h index 89ed2673..b150b2e8 100644 --- a/jerry-core/parser/js/js-parser-limits.h +++ b/jerry-core/parser/js/js-parser-limits.h @@ -52,22 +52,30 @@ #define PARSER_MAXIMUM_STRING_LENGTH PARSER_MAXIMUM_STRING_LIMIT #endif /* !PARSER_MAXIMUM_STRING_LENGTH */ -/** - * Maximum number of literals. - * Limit: 32767. Recommended: 510, 32767 - */ -#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS -#define PARSER_MAXIMUM_NUMBER_OF_LITERALS 32767 -#endif /* !PARSER_MAXIMUM_NUMBER_OF_LITERALS */ - /** * Maximum number of registers. - * Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS + * Limit: min: 256, max: min(PARSER_MAXIMUM_NUMBER_OF_LITERALS / 2, 16383) */ #ifndef PARSER_MAXIMUM_NUMBER_OF_REGISTERS #define PARSER_MAXIMUM_NUMBER_OF_REGISTERS 256 #endif /* !PARSER_MAXIMUM_NUMBER_OF_REGISTERS */ +/** + * Maximum number of literals. + * Limit: 32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS. Recommended: 32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS. + */ +#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS +#define PARSER_MAXIMUM_NUMBER_OF_LITERALS (32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS) +#endif /* !PARSER_MAXIMUM_NUMBER_OF_LITERALS */ + +/** + * Maximum depth of scope stack. + * Limit: 32767. Recommended: 32767 + */ +#ifndef PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK +#define PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK 32767 +#endif /* !PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK */ + /** * Maximum code size. * Limit: 16777215. Recommended: 65535, 16777215. @@ -95,13 +103,19 @@ #error "Maximum identifier length is not within range." #endif /* (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH) */ -#if (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767) +#if ((PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) \ + || (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_OF_REGISTERS > 32767)) #error "Maximum number of literals is not within range." -#endif /* (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767) */ +#endif /* ((PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) \ + || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767)) */ -#if (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS) +#if (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK < 1) || (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK > 32767) +#error "Maximum depth of scope stack is not within range." +#endif /* (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK < 1) || (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK > 32767) */ + +#if ((PARSER_MAXIMUM_NUMBER_OF_REGISTERS * 2) > PARSER_MAXIMUM_NUMBER_OF_LITERALS) #error "Maximum number of registers is not within range." -#endif /* (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */ +#endif /* ((PARSER_MAXIMUM_NUMBER_OF_REGISTERS * 2) > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */ #if (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215) #error "Maximum code size is not within range." diff --git a/jerry-core/parser/js/js-parser-mem.c b/jerry-core/parser/js/js-parser-mem.c index d3fafb6a..4dc87252 100644 --- a/jerry-core/parser/js/js-parser-mem.c +++ b/jerry-core/parser/js/js-parser-mem.c @@ -82,12 +82,27 @@ parser_malloc_local (parser_context_t *context_p, /**< context */ /** * Free memory allocated by parser_malloc_local. */ -void parser_free_local (void *ptr, /**< pointer to free */ - size_t size) /**< size of the memory */ +void +parser_free_local (void *ptr, /**< pointer to free */ + size_t size) /**< size of the memory */ { jmem_heap_free_block (ptr, size); } /* parser_free_local */ +/** + * Free the dynamically allocated buffer stored in the context + */ +inline void JERRY_ATTR_ALWAYS_INLINE +parser_free_allocated_buffer (parser_context_t *context_p) /**< context */ +{ + if (context_p->u.allocated_buffer_p != NULL) + { + parser_free_local (context_p->u.allocated_buffer_p, + context_p->allocated_buffer_size); + context_p->u.allocated_buffer_p = NULL; + } +} /* parser_free_allocated_buffer */ + /**********************************************************************/ /* Parser data management functions */ /**********************************************************************/ diff --git a/jerry-core/parser/js/js-parser-module.c b/jerry-core/parser/js/js-parser-module.c index 0878931e..79cf6196 100644 --- a/jerry-core/parser/js/js-parser-module.c +++ b/jerry-core/parser/js/js-parser-module.c @@ -76,6 +76,34 @@ parser_module_check_duplicate_import (parser_context_t *context_p, /**< parser c return false; } /* parser_module_check_duplicate_import */ +/** + * Append an identifier to the exported bindings. + */ +void +parser_module_append_export_name (parser_context_t *context_p) /**< parser context */ +{ + if (!(context_p->status_flags & PARSER_MODULE_STORE_IDENT)) + { + return; + } + + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; + + ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + if (parser_module_check_duplicate_export (context_p, name_p)) + { + ecma_deref_ecma_string (name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); + } + + parser_module_add_names_to_node (context_p, + name_p, + name_p); + ecma_deref_ecma_string (name_p); +} /* parser_module_append_export_name */ + /** * Check for duplicated exported bindings. * @return - true - if the exported name is a duplicate @@ -297,8 +325,8 @@ parser_module_context_init (void) ecma_module_t *module_p = ecma_module_find_or_create_module (path_p); module_p->state = ECMA_MODULE_STATE_EVALUATED; - module_p->scope_p = ecma_get_global_environment (); - ecma_ref_object (module_p->scope_p); + /* The lexical scope of the root module does not exist yet. */ + module_p->scope_p = NULL; module_p->context_p = module_context_p; module_context_p->module_p = module_p; @@ -339,7 +367,7 @@ parser_module_parse_export_clause (parser_context_t *context_p) /**< parser cont /* 15.2.3.1 The referenced binding cannot be a reserved word. */ if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL - || context_p->token.literal_is_reserved) + || context_p->token.keyword_type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD) { parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } @@ -347,13 +375,13 @@ parser_module_parse_export_clause (parser_context_t *context_p) /**< parser cont ecma_string_t *export_name_p = NULL; ecma_string_t *local_name_p = NULL; - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL); uint16_t local_name_index = context_p->lit_object.index; uint16_t export_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; lexer_next_token (context_p); - if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (lexer_token_is_identifier (context_p, "as", 2)) { lexer_next_token (context_p); @@ -363,7 +391,7 @@ parser_module_parse_export_clause (parser_context_t *context_p) /**< parser cont parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL); export_name_index = context_p->lit_object.index; @@ -405,7 +433,7 @@ parser_module_parse_export_clause (parser_context_t *context_p) /**< parser cont lexer_next_token (context_p); } - if (lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (lexer_token_is_identifier (context_p, "from", 4)) { parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); } @@ -435,16 +463,24 @@ parser_module_parse_import_clause (parser_context_t *context_p) /**< parser cont parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_string_t *import_name_p = NULL; ecma_string_t *local_name_p = NULL; - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL); uint16_t import_name_index = context_p->lit_object.index; uint16_t local_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; lexer_next_token (context_p); - if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (lexer_token_is_identifier (context_p, "as", 2)) { lexer_next_token (context_p); @@ -454,7 +490,15 @@ parser_module_parse_import_clause (parser_context_t *context_p) /**< parser cont parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL); local_name_index = context_p->lit_object.index; @@ -496,7 +540,7 @@ parser_module_parse_import_clause (parser_context_t *context_p) /**< parser cont lexer_next_token (context_p); } - if (lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (lexer_token_is_identifier (context_p, "from", 4)) { parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); } @@ -511,7 +555,8 @@ parser_module_check_request_place (parser_context_t *context_p) /**< parser cont { if (context_p->last_context_p != NULL || context_p->stack_top_uint8 != 0 - || (context_p->status_flags & (PARSER_IS_EVAL | PARSER_IS_FUNCTION)) != 0) + || (context_p->status_flags & PARSER_IS_FUNCTION) + || (context_p->global_status_flags & ECMA_PARSE_EVAL)) { parser_raise_error (context_p, PARSER_ERR_MODULE_UNEXPECTED); } diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index d919548b..9a4264c2 100755 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -21,13 +21,6 @@ #include "ecma-helpers.h" #include "lit-char-helpers.h" -#if ENABLED (JERRY_ES2015_FOR_OF) -#if !ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) -#error "For of support requires ES2015 iterator support" -#endif /* !ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - - /** \addtogroup parser Parser * @{ * @@ -38,53 +31,121 @@ * @{ */ -/** - * @{ - * Strict mode string literal in directive prologues - */ -#define PARSER_USE_STRICT_LITERAL "use strict" -#define PARSER_USE_STRICT_LENGTH 10 -/** @} */ - /** * Parser statement types. * * When a new statement is added, the following - * functions may need to be updated as well: - * - * - parser_statement_length() - * - parser_parse_break_statement() - * - parser_parse_continue_statement() - * - parser_free_jumps() - * - 'case LEXER_RIGHT_BRACE:' in parser_parse_statements() - * - 'if (context_p->token.type == LEXER_RIGHT_BRACE)' in parser_parse_statements() - * - 'switch (context_p->stack_top_uint8)' in parser_parse_statements() + * arrays must be updated as well: + * - statement_lengths[] + * - parser_statement_flags[] */ typedef enum { PARSER_STATEMENT_START, PARSER_STATEMENT_BLOCK, +#if ENABLED (JERRY_ES2015) + PARSER_STATEMENT_BLOCK_SCOPE, + PARSER_STATEMENT_PRIVATE_SCOPE, + PARSER_STATEMENT_BLOCK_CONTEXT, + PARSER_STATEMENT_PRIVATE_CONTEXT, +#endif /* ENABLED (JERRY_ES2015) */ PARSER_STATEMENT_LABEL, PARSER_STATEMENT_IF, PARSER_STATEMENT_ELSE, - /* From switch -> for-in : break target statements */ PARSER_STATEMENT_SWITCH, PARSER_STATEMENT_SWITCH_NO_DEFAULT, - /* From do-while -> for->in : continue target statements */ PARSER_STATEMENT_DO_WHILE, PARSER_STATEMENT_WHILE, PARSER_STATEMENT_FOR, - /* From for->in -> try : instructions with context - * Break and continue uses another instruction form - * when crosses their borders. */ PARSER_STATEMENT_FOR_IN, -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) PARSER_STATEMENT_FOR_OF, -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ PARSER_STATEMENT_WITH, PARSER_STATEMENT_TRY, } parser_statement_type_t; +/** + * Parser statement type flags. + */ +typedef enum +{ + PARSER_STATM_NO_OPTS = 0, /**< no options */ + PARSER_STATM_SINGLE_STATM = (1 << 0), /**< statment can form single statement context */ + PARSER_STATM_HAS_BLOCK = (1 << 1), /**< statement always has a code block */ + PARSER_STATM_BREAK_TARGET = (1 << 2), /**< break target statement */ + PARSER_STATM_CONTINUE_TARGET = (1 << 3), /**< continue target statement */ + PARSER_STATM_CONTEXT_BREAK = (1 << 4), /**< uses another instruction form when crosses their borders */ +} parser_statement_flags_t; + +/** + * Parser statement attributes. + * Note: the order of the attributes must be keep in sync with parser_statement_type_t + */ +static const uint8_t parser_statement_flags[] = +{ + /* PARSER_STATEMENT_START */ + PARSER_STATM_HAS_BLOCK, + /* PARSER_STATEMENT_BLOCK, */ + PARSER_STATM_HAS_BLOCK, +#if ENABLED (JERRY_ES2015) + /* PARSER_STATEMENT_BLOCK_SCOPE, */ + PARSER_STATM_HAS_BLOCK, + /* PARSER_STATEMENT_PRIVATE_SCOPE, */ + PARSER_STATM_NO_OPTS, + /* PARSER_STATEMENT_BLOCK_CONTEXT, */ + PARSER_STATM_HAS_BLOCK | PARSER_STATM_CONTEXT_BREAK, + /* PARSER_STATEMENT_PRIVATE_CONTEXT, */ + PARSER_STATM_CONTEXT_BREAK, +#endif /* ENABLED (JERRY_ES2015) */ + /* PARSER_STATEMENT_LABEL */ + PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_IF */ + PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_ELSE */ + PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_SWITCH */ + PARSER_STATM_HAS_BLOCK | PARSER_STATM_BREAK_TARGET, + /* PARSER_STATEMENT_SWITCH_NO_DEFAULT */ + PARSER_STATM_HAS_BLOCK | PARSER_STATM_BREAK_TARGET, + /* PARSER_STATEMENT_DO_WHILE */ + PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_WHILE */ + PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_FOR */ + PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_FOR_IN */ + PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM | PARSER_STATM_CONTEXT_BREAK, +#if ENABLED (JERRY_ES2015) + /* PARSER_STATEMENT_FOR_OF */ + PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM | PARSER_STATM_CONTEXT_BREAK, +#endif /* ENABLED (JERRY_ES2015) */ + /* PARSER_STATEMENT_WITH */ + PARSER_STATM_CONTEXT_BREAK | PARSER_STATM_SINGLE_STATM, + /* PARSER_STATEMENT_TRY */ + PARSER_STATM_HAS_BLOCK | PARSER_STATM_CONTEXT_BREAK +}; + +#if ENABLED (JERRY_ES2015) +/** + * Block statement. + */ +typedef struct +{ + uint16_t scope_stack_top; /**< preserved top of scope stack */ + uint16_t scope_stack_reg_top; /**< preserved top register of scope stack */ +} parser_block_statement_t; + +/** + * Context of block statement. + */ +typedef struct +{ + parser_branch_t branch; /**< branch to the end */ +} parser_block_context_t; + +#endif /* !ENABLED (JERRY_ES2015) */ + /** * Loop statement. */ @@ -181,6 +242,8 @@ typedef enum typedef struct { parser_try_block_type_t type; /**< current block type */ + uint16_t scope_stack_top; /**< current top of scope stack */ + uint16_t scope_stack_reg_top; /**< current top register of scope stack */ parser_branch_t branch; /**< branch to the end of the current block */ } parser_try_statement_t; @@ -197,6 +260,16 @@ parser_statement_length (uint8_t type) /**< type of statement */ { /* PARSER_STATEMENT_BLOCK */ 1, +#if ENABLED (JERRY_ES2015) + /* PARSER_STATEMENT_BLOCK_SCOPE */ + (uint8_t) (sizeof (parser_block_statement_t) + 1), + /* PARSER_STATEMENT_PRIVATE_SCOPE */ + (uint8_t) (sizeof (parser_block_statement_t) + 1), + /* PARSER_STATEMENT_BLOCK_CONTEXT */ + (uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1), + /* PARSER_STATEMENT_PRIVATE_CONTEXT */ + (uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1), +#endif /* ENABLED (JERRY_ES2015) */ /* PARSER_STATEMENT_LABEL */ (uint8_t) (sizeof (parser_label_statement_t) + 1), /* PARSER_STATEMENT_IF */ @@ -215,12 +288,12 @@ parser_statement_length (uint8_t type) /**< type of statement */ (uint8_t) (sizeof (parser_for_statement_t) + sizeof (parser_loop_statement_t) + 1), /* PARSER_STATEMENT_FOR_IN */ (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1), -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) /* PARSER_STATEMENT_FOR_OF */ (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1), -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ /* PARSER_STATEMENT_WITH */ - (uint8_t) (sizeof (parser_with_statement_t) + 1), + (uint8_t) (sizeof (parser_with_statement_t) + 1 + 1), /* PARSER_STATEMENT_TRY */ (uint8_t) (sizeof (parser_try_statement_t) + 1), }; @@ -292,67 +365,262 @@ parser_parse_enclosed_expr (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); } /* parser_parse_enclosed_expr */ +#if ENABLED (JERRY_ES2015) + +/** + * Create a block context. + * + * @return true - when a context is created, false - otherwise + */ +static bool +parser_push_block_context (parser_context_t *context_p, /**< context */ + bool is_private) /**< is private (bound to a statement) context */ +{ + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); + + parser_block_statement_t block_statement; + block_statement.scope_stack_top = context_p->scope_stack_top; + block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top; + + bool is_context_needed = false; + + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) + { + parser_block_context_t block_context; + +#ifndef JERRY_NDEBUG + PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#endif /* !JERRY_NDEBUG */ + + parser_emit_cbc_forward_branch (context_p, + CBC_BLOCK_CREATE_CONTEXT, + &block_context.branch); + parser_stack_push (context_p, &block_context, sizeof (parser_block_context_t)); + is_context_needed = true; + } + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); + parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t)); + + uint8_t statement_type; + + if (is_private) + { + statement_type = (is_context_needed ? PARSER_STATEMENT_PRIVATE_CONTEXT : PARSER_STATEMENT_PRIVATE_SCOPE); + } + else + { + statement_type = (is_context_needed ? PARSER_STATEMENT_BLOCK_CONTEXT : PARSER_STATEMENT_BLOCK_SCOPE); + } + + parser_stack_push_uint8 (context_p, statement_type); + + return is_context_needed; +} /* parser_push_block_context */ + +/** + * Pop block context. + */ +static void +parser_pop_block_context (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT); + + uint8_t type = context_p->stack_top_uint8; + + parser_block_statement_t block_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t)); + + context_p->scope_stack_top = block_statement.scope_stack_top; + context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top; + + if (type == PARSER_STATEMENT_BLOCK_CONTEXT || type == PARSER_STATEMENT_PRIVATE_CONTEXT) + { + PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#ifndef JERRY_NDEBUG + PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#endif /* !JERRY_NDEBUG */ + + parser_block_context_t block_context; + parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t)); + + parser_emit_cbc (context_p, CBC_CONTEXT_END); + parser_set_branch_to_current_position (context_p, &block_context.branch); + } + + parser_stack_iterator_init (context_p, &context_p->last_statement); +} /* parser_pop_block_context */ + +/** + * Validate lexical context for a declaration. + */ +static void +parser_validate_lexical_context (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_LET + || context_p->token.type == LEXER_KEYW_CONST + || context_p->token.type == LEXER_KEYW_CLASS); + + if (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } +} /* parser_validate_lexical_context */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * Parse var statement. */ static void parser_parse_var_statement (parser_context_t *context_p) /**< context */ { - JERRY_ASSERT (context_p->token.type == LEXER_KEYW_VAR); + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_VAR + || context_p->token.type == LEXER_KEYW_LET + || context_p->token.type == LEXER_KEYW_CONST); + +#if ENABLED (JERRY_ES2015) + uint8_t declaration_type = context_p->token.type; + + if (declaration_type != LEXER_KEYW_VAR) + { + parser_validate_lexical_context (context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ while (true) { - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); +#if ENABLED (JERRY_ES2015) + if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) + { + parser_pattern_flags_t flags = PARSER_PATTERN_BINDING; + + if (declaration_type == LEXER_KEYW_LET) + { + flags |= PARSER_PATTERN_LET; + } + else if (declaration_type == LEXER_KEYW_CONST) + { + flags |= PARSER_PATTERN_CONST; + } + + parser_parse_initializer_by_next_char (context_p, flags); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); #if ENABLED (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) - parser_line_counter_t ident_line_counter = context_p->token.line; + parser_line_counter_t ident_line_counter = context_p->token.line; #endif /* ENABLED (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) */ - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; - #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->status_flags & PARSER_MODULE_STORE_IDENT) - { - context_p->module_identifier_lit_p = context_p->lit_object.literal_p; - context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); - } + parser_module_append_export_name (context_p); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_ASSIGN) - { -#if ENABLED (JERRY_DEBUGGER) - if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && ident_line_counter != context_p->last_breakpoint_line) +#if ENABLED (JERRY_ES2015) + if (declaration_type != LEXER_KEYW_VAR + && context_p->token.keyword_type == LEXER_KEYW_LET) { - parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED); - parser_flush_cbc (context_p); - - parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter); - - context_p->last_breakpoint_line = ident_line_counter; + parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING); } + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_ASSIGN) + { +#if ENABLED (JERRY_DEBUGGER) + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + && ident_line_counter != context_p->last_breakpoint_line) + { + parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED); + parser_flush_cbc (context_p); + + parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter); + + context_p->last_breakpoint_line = ident_line_counter; + } #endif /* ENABLED (JERRY_DEBUGGER) */ #if ENABLED (JERRY_LINE_INFO) - if (ident_line_counter != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, ident_line_counter, false); - } + if (ident_line_counter != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, ident_line_counter, false); + } #endif /* ENABLED (JERRY_LINE_INFO) */ - parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); - parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); + uint16_t index = context_p->lit_object.index; + + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + + cbc_opcode_t opcode = CBC_ASSIGN_SET_IDENT; + +#if ENABLED (JERRY_ES2015) + if (declaration_type != LEXER_KEYW_VAR + && (index < PARSER_REGISTER_START)) + { + opcode = CBC_INIT_LET; + + if (scanner_literal_is_created (context_p, index)) + { + opcode = CBC_ASSIGN_LET_CONST; + } + else if (declaration_type == LEXER_KEYW_CONST) + { + opcode = CBC_INIT_CONST; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, index); + } +#if ENABLED (JERRY_ES2015) + else if (declaration_type == LEXER_KEYW_LET) + { + parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); + + uint16_t index = context_p->lit_object.index; + cbc_opcode_t opcode = CBC_MOV_IDENT; + + if (index < PARSER_REGISTER_START) + { + opcode = (scanner_literal_is_created (context_p, index) ? CBC_ASSIGN_LET_CONST + : CBC_INIT_LET); + } + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, index); + } + else if (declaration_type == LEXER_KEYW_CONST) + { + parser_raise_error (context_p, PARSER_ERR_MISSING_ASSIGN_AFTER_CONST); + } } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_COMMA) { break; } } + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ } /* parser_parse_var_statement */ /** @@ -361,48 +629,110 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ static void parser_parse_function_statement (parser_context_t *context_p) /**< context */ { - uint32_t status_flags; - lexer_literal_t *name_p; - lexer_literal_t *literal_p; - uint8_t no_reg_store; - JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION); +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM)) + { + if (context_p->status_flags & PARSER_IS_STRICT) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } + + if (context_p->stack_top_uint8 == PARSER_STATEMENT_IF + || context_p->stack_top_uint8 == PARSER_STATEMENT_ELSE) + { + /* There must be a parser error later if this check fails. */ + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + parser_push_block_context (context_p, true); + } + } + else if (context_p->stack_top_uint8 == PARSER_STATEMENT_LABEL) + { + parser_stack_iterator_t iterator; + parser_stack_iterator_init (context_p, &iterator); + parser_stack_iterator_skip (&iterator, sizeof (parser_label_statement_t) + 1); + + while (true) + { + uint8_t type = parser_stack_iterator_read_uint8 (&iterator); + + if (type == PARSER_STATEMENT_LABEL) + { + parser_stack_iterator_skip (&iterator, sizeof (parser_label_statement_t) + 1); + continue; + } + + if (parser_statement_flags[type] & PARSER_STATM_HAS_BLOCK) + { + break; + } + + parser_raise_error (context_p, PARSER_ERR_LABELLED_FUNC_NOT_IN_BLOCK); + } + } + else + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } + } +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) parser_line_counter_t debugger_line = context_p->token.line; parser_line_counter_t debugger_column = context_p->token.column; #endif /* ENABLED (JERRY_DEBUGGER) */ - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); +#if ENABLED (JERRY_ES2015) + bool is_generator_function = false; + + if (lexer_consume_generator (context_p)) + { + is_generator_function = true; + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_expect_identifier (context_p, LEXER_NEW_IDENT_LITERAL); JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); - if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS) +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED) { - context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED; + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); } - - name_p = context_p->lit_object.literal_p; +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->status_flags & PARSER_MODULE_STORE_IDENT) - { - context_p->module_identifier_lit_p = context_p->lit_object.literal_p; - context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); - } + parser_module_append_export_name (context_p); + context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; - if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) + uint32_t status_flags = PARSER_FUNCTION_CLOSURE; + + if (context_p->token.keyword_type >= LEXER_FIRST_NON_STRICT_ARGUMENTS) { - JERRY_ASSERT (context_p->lit_object.type == LEXER_LITERAL_OBJECT_EVAL - || context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS); status_flags |= PARSER_HAS_NON_STRICT_ARG; } +#if ENABLED (JERRY_ES2015) + if (is_generator_function) + { + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) + { + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { + lexer_literal_t *name_p = context_p->lit_object.literal_p; jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME, JERRY_DEBUGGER_NO_SUBTYPE, name_p->u.char_p, @@ -414,55 +744,88 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ - if (name_p->status_flags & LEXER_FLAG_INITIALIZED) + JERRY_ASSERT (context_p->scope_stack_top >= 2); + parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top - 2; + + uint16_t literal_index = context_p->lit_object.index; + + while (literal_index != scope_stack_p->map_from) { - if (!(name_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) + scope_stack_p--; + + JERRY_ASSERT (scope_stack_p >= context_p->scope_stack_p); + } + + JERRY_ASSERT (scope_stack_p[1].map_from == PARSER_SCOPE_STACK_FUNC); + +#if ENABLED (JERRY_ES2015) + if (!(context_p->status_flags & PARSER_IS_STRICT) + && (scope_stack_p >= context_p->scope_stack_p + context_p->scope_stack_global_end)) + { + bool copy_value = true; + + parser_scope_stack_t *stack_p = context_p->scope_stack_p; + + while (stack_p < scope_stack_p) { - /* Overwrite the previous initialization. */ - ecma_compiled_code_t *compiled_code_p; + if (literal_index == stack_p->map_from + && (stack_p->map_to & PARSER_SCOPE_STACK_NO_FUNCTION_COPY)) + { + copy_value = false; + break; + } + stack_p++; + } - literal_p = PARSER_GET_LITERAL ((size_t) (context_p->lit_object.index + 1)); + if (copy_value) + { + stack_p = context_p->scope_stack_p; - JERRY_ASSERT (literal_p->type == LEXER_FUNCTION_LITERAL - && literal_p->status_flags == 0); + while (stack_p < scope_stack_p) + { + if (literal_index == stack_p->map_from) + { + JERRY_ASSERT (!(stack_p->map_to & PARSER_SCOPE_STACK_NO_FUNCTION_COPY)); - compiled_code_p = parser_parse_function (context_p, status_flags); - util_free_literal (literal_p); + uint16_t map_to = scanner_decode_map_to (stack_p); + uint16_t opcode = ((map_to >= PARSER_REGISTER_START) ? CBC_ASSIGN_LITERAL_SET_IDENT + : CBC_COPY_TO_GLOBAL); - literal_p->u.bytecode_p = compiled_code_p; - lexer_next_token (context_p); - return; + parser_emit_cbc_literal_value (context_p, + opcode, + scanner_decode_map_to (scope_stack_p), + map_to); + break; + } + stack_p++; + } + + parser_flush_cbc (context_p); + } + + if (JERRY_UNLIKELY (context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT)) + { + parser_pop_block_context (context_p); } } - else if (context_p->lit_object.index + 1 == context_p->literal_count) +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_literal_t *literal_p = PARSER_GET_LITERAL ((size_t) scope_stack_p[1].map_to); + + JERRY_ASSERT ((literal_p->type == LEXER_UNUSED_LITERAL || literal_p->type == LEXER_FUNCTION_LITERAL) + && literal_p->status_flags == 0); + + ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, status_flags); + + if (literal_p->type == LEXER_FUNCTION_LITERAL) { - /* The most common case: the literal is the last literal. */ - name_p->status_flags |= LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED; - lexer_construct_function_object (context_p, status_flags); - lexer_next_token (context_p); - return; + ecma_bytecode_deref (literal_p->u.bytecode_p); } - /* Clone the literal at the end. */ - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } + literal_p->u.bytecode_p = compiled_code_p; + literal_p->type = LEXER_FUNCTION_LITERAL; - literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - *literal_p = *name_p; - no_reg_store = name_p->status_flags & (LEXER_FLAG_NO_REG_STORE | LEXER_FLAG_SOURCE_PTR); - literal_p->status_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | no_reg_store; - - name_p->type = LEXER_UNUSED_LITERAL; - name_p->status_flags &= LEXER_FLAG_FUNCTION_ARGUMENT | LEXER_FLAG_SOURCE_PTR; - /* Byte code references to this literal are - * redirected to the newly allocated literal. */ - name_p->prop.index = context_p->literal_count; - - context_p->literal_count++; - - lexer_construct_function_object (context_p, status_flags); lexer_next_token (context_p); } /* parser_parse_function_statement */ @@ -547,12 +910,15 @@ parser_parse_with_statement_start (parser_context_t *context_p) /**< context */ PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION); #endif /* !JERRY_NDEBUG */ - context_p->status_flags |= PARSER_INSIDE_WITH | PARSER_LEXICAL_ENV_NEEDED; + uint8_t inside_with = (context_p->status_flags & PARSER_INSIDE_WITH) != 0; + + context_p->status_flags |= PARSER_INSIDE_WITH; parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_WITH_CREATE_CONTEXT, &with_statement.branch); parser_stack_push (context_p, &with_statement, sizeof (parser_with_statement_t)); + parser_stack_push_uint8 (context_p, inside_with); parser_stack_push_uint8 (context_p, PARSER_STATEMENT_WITH); parser_stack_iterator_init (context_p, &context_p->last_statement); } /* parser_parse_with_statement_start */ @@ -564,10 +930,16 @@ static void parser_parse_with_statement_end (parser_context_t *context_p) /**< context */ { parser_with_statement_t with_statement; - parser_stack_iterator_t iterator; JERRY_ASSERT (context_p->status_flags & PARSER_INSIDE_WITH); + parser_stack_pop_uint8 (context_p); + + if (!context_p->stack_top_uint8) + { + context_p->status_flags &= (uint32_t) ~PARSER_INSIDE_WITH; + } + parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, &with_statement, sizeof (parser_with_statement_t)); parser_stack_iterator_init (context_p, &context_p->last_statement); @@ -580,99 +952,8 @@ parser_parse_with_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc (context_p, CBC_CONTEXT_END); parser_set_branch_to_current_position (context_p, &with_statement.branch); - - parser_stack_iterator_init (context_p, &iterator); - - while (true) - { - uint8_t type = parser_stack_iterator_read_uint8 (&iterator); - - if (type == PARSER_STATEMENT_START) - { - context_p->status_flags &= (uint32_t) ~PARSER_INSIDE_WITH; - return; - } - - if (type == PARSER_STATEMENT_WITH) - { - return; - } - - parser_stack_iterator_skip (&iterator, parser_statement_length (type)); - } } /* parser_parse_with_statement_end */ -#if ENABLED (JERRY_ES2015_CLASS) -/** - * Parse super class context like a with statement (starting part). - */ -void -parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */ -{ - JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS - || (context_p->status_flags & PARSER_CLASS_HAS_SUPER)); - parser_with_statement_t with_statement; - - if (context_p->token.type == LEXER_KEYW_EXTENDS) - { - lexer_next_token (context_p); - - /* NOTE: Currently there is no proper way to check whether the currently parsed expression - is a valid lefthand-side expression or not, so we do not throw syntax error and parse - the class extending value as an expression. */ - parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA); - } - else - { - JERRY_ASSERT (context_p->status_flags & PARSER_CLASS_HAS_SUPER); - parser_emit_cbc (context_p, CBC_PUSH_NULL); - context_p->status_flags |= PARSER_CLASS_IMPLICIT_SUPER; - } - -#ifndef JERRY_NDEBUG - PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - context_p->status_flags |= PARSER_CLASS_HAS_SUPER; - parser_emit_cbc_ext_forward_branch (context_p, - CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, - &with_statement.branch); - - parser_stack_push (context_p, &with_statement, sizeof (parser_with_statement_t)); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_WITH); -} /* parser_parse_super_class_context_start */ - -/** - * Parse super class context like a with statement (ending part). - */ -void -parser_parse_super_class_context_end (parser_context_t *context_p, /**< context */ - bool is_statement) /**< true - if class is parsed as a statement - * false - otherwise (as an expression) */ -{ - parser_with_statement_t with_statement; - parser_stack_pop_uint8 (context_p); - parser_stack_pop (context_p, &with_statement, sizeof (parser_with_statement_t)); - - parser_flush_cbc (context_p); - PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#ifndef JERRY_NDEBUG - PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - if (is_statement) - { - parser_emit_cbc (context_p, CBC_CONTEXT_END); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_CLASS_EXPR_CONTEXT_END); - } - - parser_set_branch_to_current_position (context_p, &with_statement.branch); -} /* parser_parse_super_class_context_end */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - /** * Parse do-while statement (ending part). */ @@ -910,23 +1191,71 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ parser_for_in_of_statement_t for_in_of_statement; scanner_location_t start_location, end_location; -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF); bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN); -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ + end_location = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location; + + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + + scanner_get_location (&start_location, context_p); + lexer_next_token (context_p); + + uint8_t token_type = LEXER_EOS; + bool has_context = false; + + if (context_p->token.type == LEXER_KEYW_VAR + || context_p->token.type == LEXER_KEYW_LET + || context_p->token.type == LEXER_KEYW_CONST) + { + token_type = context_p->token.type; + has_context = context_p->next_scanner_info_p->source_p == context_p->source_p; + JERRY_ASSERT (!has_context || context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); + scanner_get_location (&start_location, context_p); + + /* TODO: remove this after the pre-scanner supports strict mode detection. */ + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION) + { + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + } + else if (context_p->token.type == LEXER_LITERAL && lexer_token_is_let (context_p)) + { + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION) + { + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + else + { + token_type = LEXER_KEYW_LET; + has_context = (context_p->next_scanner_info_p->source_p == context_p->source_p); + scanner_get_location (&start_location, context_p); + } + } + + if (has_context) + { + has_context = parser_push_block_context (context_p, true); + } + + scanner_set_location (context_p, &end_location); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN); bool is_for_in = true; -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - scanner_get_location (&start_location, context_p); + scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location); + scanner_release_next (context_p, sizeof (scanner_location_info_t)); +#endif /* ENABLED (JERRY_ES2015) */ + /* The length of both 'in' and 'of' is two. */ const uint8_t *source_end_p = context_p->source_p - 2; - scanner_release_next (context_p, sizeof (scanner_location_info_t)); scanner_seek (context_p); lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); @@ -950,6 +1279,13 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); for_in_of_statement.start_offset = context_p->byte_code_size; +#if ENABLED (JERRY_ES2015) + if (has_context) + { + parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_CONTEXT); + } +#endif /* ENABLED (JERRY_ES2015) */ + /* The expression parser must not read the 'in' or 'of' tokens. */ scanner_get_location (&end_location, context_p); scanner_set_location (context_p, &start_location); @@ -957,65 +1293,128 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ const uint8_t *original_source_end_p = context_p->source_end_p; context_p->source_end_p = source_end_p; scanner_seek (context_p); + +#if ENABLED (JERRY_ES2015) + if (token_type == LEXER_EOS) + { + lexer_next_token (context_p); + } +#else /* !ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); - if (context_p->token.type == LEXER_KEYW_VAR) + uint8_t token_type = context_p->token.type; +#endif /* ENABLED (JERRY_ES2015) */ + + switch (token_type) { - uint16_t literal_index; - - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); - - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; - - literal_index = context_p->lit_object.index; - - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_ASSIGN) +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: +#endif /* ENABLED (JERRY_ES2015) */ + case LEXER_KEYW_VAR: { - parser_branch_t branch; +#if ENABLED (JERRY_ES2015) + if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) + { + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); - /* Initialiser is never executed. */ - parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch); + if (context_p->next_scanner_info_p->source_p == (context_p->source_p + 1)) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } + + parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK); + + if (token_type == LEXER_KEYW_LET) + { + flags |= PARSER_PATTERN_LET; + } + else if (token_type == LEXER_KEYW_CONST) + { + flags |= PARSER_PATTERN_CONST; + } + + parser_parse_initializer_by_next_char (context_p, flags); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + + uint16_t literal_index = context_p->lit_object.index; lexer_next_token (context_p); - parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA); - parser_set_branch_to_current_position (context_p, &branch); + + if (context_p->token.type == LEXER_ASSIGN) + { +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_STRICT) + { + parser_raise_error (context_p, PARSER_ERR_FOR_IN_OF_DECLARATION); + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_branch_t branch; + + /* Initialiser is never executed. */ + parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch); + lexer_next_token (context_p); + parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA); + parser_set_branch_to_current_position (context_p, &branch); + } + + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); +#if ENABLED (JERRY_ES2015) +#ifndef JERRY_NDEBUG + if (literal_index < PARSER_REGISTER_START + && has_context + && !scanner_literal_is_created (context_p, literal_index)) + { + context_p->global_status_flags |= ECMA_PARSE_INTERNAL_FOR_IN_OFF_CONTEXT_ERROR; + } +#endif /* !JERRY_NDEBUG */ + + uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT); + parser_emit_cbc_literal (context_p, opcode, literal_index); +#else /* !ENABLED (JERRY_ES2015) */ + parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); +#endif /* ENABLED (JERRY_ES2015) */ + break; } + default: + { + uint16_t opcode; - parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT - : CBC_EXT_FOR_OF_GET_NEXT); - parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); - } - else - { - uint16_t opcode; + parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE); - parser_parse_expression (context_p, PARSE_EXPR); + opcode = context_p->last_cbc_opcode; - opcode = context_p->last_cbc_opcode; + /* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */ + JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS + && opcode != CBC_PUSH_THREE_LITERALS); - /* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */ - JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS - && opcode != CBC_PUSH_THREE_LITERALS); + opcode = parser_check_left_hand_side_expression (context_p, opcode); - opcode = parser_check_left_hand_side_expression (context_p, opcode); + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); + parser_flush_cbc (context_p); - parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT - : CBC_EXT_FOR_OF_GET_NEXT); - parser_flush_cbc (context_p); - - context_p->last_cbc_opcode = opcode; + context_p->last_cbc_opcode = opcode; + break; + } } if (context_p->token.type != LEXER_EOS) { -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) parser_raise_error (context_p, is_for_in ? PARSER_ERR_IN_EXPECTED : PARSER_ERR_OF_EXPECTED); -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ +#else /* !ENABLED (JERRY_ES2015) */ parser_raise_error (context_p, PARSER_ERR_IN_EXPECTED); -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ } parser_flush_cbc (context_p); @@ -1027,12 +1426,12 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t)); parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t)); -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) parser_stack_push_uint8 (context_p, is_for_in ? PARSER_STATEMENT_FOR_IN : PARSER_STATEMENT_FOR_OF); -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ +#else /* !ENABLED (JERRY_ES2015) */ parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN); -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ parser_stack_iterator_init (context_p, &context_p->last_statement); return; } @@ -1041,13 +1440,56 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ if (context_p->token.type != LEXER_SEMICOLON) { - if (context_p->token.type == LEXER_KEYW_VAR) +#if ENABLED (JERRY_ES2015) + const uint8_t *source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + + switch (context_p->token.type) { - parser_parse_var_statement (context_p); - } - else - { - parser_parse_expression_statement (context_p, PARSE_EXPR); +#if ENABLED (JERRY_ES2015) + case LEXER_LITERAL: + { + if (!lexer_token_is_let (context_p)) + { + parser_parse_expression_statement (context_p, PARSE_EXPR); + break; + } + + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type != SCANNER_TYPE_BLOCK) + { + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION) + { + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + + parser_parse_expression_statement (context_p, PARSE_EXPR); + break; + } + + context_p->token.type = LEXER_KEYW_LET; + /* FALLTHRU */ + } + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: + { + if (context_p->next_scanner_info_p->source_p == source_p) + { + parser_push_block_context (context_p, true); + } + /* FALLTHRU */ + } +#endif /* ENABLED (JERRY_ES2015) */ + case LEXER_KEYW_VAR: + { + parser_parse_var_statement (context_p); + break; + } + default: + { + parser_parse_expression_statement (context_p, PARSE_EXPR); + break; + } } if (context_p->token.type != LEXER_SEMICOLON) @@ -1131,6 +1573,19 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t)); parser_stack_iterator_read (&iterator, &for_statement, sizeof (parser_for_statement_t)); +#if ENABLED (JERRY_ES2015) + bool has_block_context = false; + uint8_t next_statement_type; + + parser_stack_iterator_skip (&iterator, sizeof (parser_for_statement_t)); + parser_stack_iterator_read (&iterator, &next_statement_type, 1); + + if (next_statement_type == PARSER_STATEMENT_PRIVATE_CONTEXT) + { + has_block_context = true; + } +#endif + scanner_get_location (&location, context_p); current_token = context_p->token; @@ -1140,6 +1595,13 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_set_continues_to_current_position (context_p, loop.branch_list_p); +#if ENABLED (JERRY_ES2015) + if (has_block_context) + { + parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_FULL_CONTEXT); + } +#endif + if (context_p->token.type != LEXER_RIGHT_PAREN) { parser_parse_expression_statement (context_p, PARSE_EXPR); @@ -1188,6 +1650,14 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset); parser_set_breaks_to_current_position (context_p, loop.branch_list_p); +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT) + { + parser_pop_block_context (context_p); + } +#endif + /* Calling scanner_seek is unnecessary because all * info blocks inside the for statement should be processed. */ scanner_set_location (context_p, &location); @@ -1217,6 +1687,13 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p - 1) + { + parser_push_block_context (context_p, true); + } +#endif /* ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p && context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH); @@ -1233,6 +1710,7 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * parser_emit_cbc (context_p, CBC_POP); parser_flush_cbc (context_p); + parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK); parser_stack_iterator_init (context_p, &context_p->last_statement); return; @@ -1381,6 +1859,11 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, 1); parser_stack_iterator_read (&iterator, &try_statement, sizeof (parser_try_statement_t)); +#if ENABLED (JERRY_ES2015) + context_p->scope_stack_top = try_statement.scope_stack_top; + context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top; +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); if (try_statement.type == parser_finally_block) @@ -1400,6 +1883,11 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ if (try_statement.type == parser_catch_block) { +#if !ENABLED (JERRY_ES2015) + context_p->scope_stack_top = try_statement.scope_stack_top; + context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top; +#endif /* !ENABLED (JERRY_ES2015) */ + if (context_p->token.type != LEXER_KEYW_FINALLY) { parser_flush_cbc (context_p); @@ -1410,6 +1898,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc (context_p, CBC_CONTEXT_END); parser_flush_cbc (context_p); + try_statement.type = parser_finally_block; } } @@ -1430,8 +1919,6 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ if (context_p->token.type == LEXER_KEYW_CATCH) { - uint16_t literal_index; - lexer_next_token (context_p); if (context_p->token.type != LEXER_LEFT_PAREN) @@ -1439,16 +1926,66 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED); } - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + try_statement.type = parser_catch_block; + parser_emit_cbc_ext_forward_branch (context_p, + CBC_EXT_CATCH, + &try_statement.branch); - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + try_statement.scope_stack_top = context_p->scope_stack_top; + try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top; - literal_index = context_p->lit_object.index; +#ifndef JERRY_NDEBUG + bool block_found = false; +#endif /* !JERRY_NDEBUG */ - lexer_next_token (context_p); + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); +#ifndef JERRY_NDEBUG + block_found = true; +#endif /* !JERRY_NDEBUG */ + + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); + } + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); + } + +#if ENABLED (JERRY_ES2015) + if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) + { + parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING + | PARSER_PATTERN_TARGET_ON_STACK + | PARSER_PATTERN_LET); + + parser_parse_initializer_by_next_char (context_p, flags); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + +#if ENABLED (JERRY_ES2015) + uint16_t literal_index = context_p->lit_object.index; + parser_emit_cbc_literal (context_p, + (literal_index >= PARSER_REGISTER_START) ? CBC_ASSIGN_SET_IDENT : CBC_ASSIGN_LET_CONST, + literal_index); +#else /* !ENABLED (JERRY_ES2015) */ + parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, context_p->lit_object.index); +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_next_token (context_p); + +#ifndef JERRY_NDEBUG + JERRY_ASSERT (block_found); +#endif /* !JERRY_NDEBUG */ +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_RIGHT_PAREN) { @@ -1462,12 +1999,6 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - try_statement.type = parser_catch_block; - parser_emit_cbc_ext_forward_branch (context_p, - CBC_EXT_CATCH, - &try_statement.branch); - - parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); parser_flush_cbc (context_p); } else @@ -1485,6 +2016,20 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_FINALLY, &try_statement.branch); + +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); + + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); + } + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); + } +#endif /* ENABLED (JERRY_ES2015) */ } lexer_next_token (context_p); @@ -1591,12 +2136,7 @@ parser_parse_break_statement (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_INVALID_BREAK_LABEL); } - if (type == PARSER_STATEMENT_FOR_IN -#if ENABLED (JERRY_ES2015_FOR_OF) - || type == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || type == PARSER_STATEMENT_WITH - || type == PARSER_STATEMENT_TRY) + if (parser_statement_flags[type] & PARSER_STATM_CONTEXT_BREAK) { opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT; } @@ -1608,7 +2148,7 @@ parser_parse_break_statement (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, 1); parser_stack_iterator_read (&iterator, &label_statement, sizeof (parser_label_statement_t)); - if (lexer_compare_identifier_to_current (context_p, &label_statement.label_ident)) + if (lexer_current_is_literal (context_p, &label_statement.label_ident)) { label_statement.break_list_p = parser_emit_cbc_forward_branch_item (context_p, (uint16_t) opcode, @@ -1635,25 +2175,12 @@ parser_parse_break_statement (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_INVALID_BREAK); } - if (type == PARSER_STATEMENT_FOR_IN -#if ENABLED (JERRY_ES2015_FOR_OF) - || type == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || type == PARSER_STATEMENT_WITH - || type == PARSER_STATEMENT_TRY) + if (parser_statement_flags[type] & PARSER_STATM_CONTEXT_BREAK) { opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT; } - if (type == PARSER_STATEMENT_SWITCH - || type == PARSER_STATEMENT_SWITCH_NO_DEFAULT - || type == PARSER_STATEMENT_DO_WHILE - || type == PARSER_STATEMENT_WHILE - || type == PARSER_STATEMENT_FOR -#if ENABLED (JERRY_ES2015_FOR_OF) - || type == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || type == PARSER_STATEMENT_FOR_IN) + if (parser_statement_flags[type] & PARSER_STATM_BREAK_TARGET) { parser_loop_statement_t loop; @@ -1687,7 +2214,6 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { parser_stack_iterator_t loop_iterator; - bool for_in_of_was_seen = false; loop_iterator.current_p = NULL; @@ -1709,7 +2235,7 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, 1); parser_stack_iterator_read (&iterator, &label_statement, sizeof (parser_label_statement_t)); - if (lexer_compare_identifier_to_current (context_p, &label_statement.label_ident)) + if (lexer_current_is_literal (context_p, &label_statement.label_ident)) { parser_loop_statement_t loop; @@ -1727,30 +2253,12 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ continue; } -#if ENABLED (JERRY_ES2015_FOR_OF) - bool is_for_in_of_statement = (type == PARSER_STATEMENT_FOR_IN) || (type == PARSER_STATEMENT_FOR_OF); -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ - bool is_for_in_of_statement = (type == PARSER_STATEMENT_FOR_IN); -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - - if (type == PARSER_STATEMENT_WITH - || type == PARSER_STATEMENT_TRY - || for_in_of_was_seen) + if (parser_statement_flags[type] & PARSER_STATM_CONTEXT_BREAK) { opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT; } - else if (is_for_in_of_statement) - { - for_in_of_was_seen = true; - } - if (type == PARSER_STATEMENT_DO_WHILE - || type == PARSER_STATEMENT_WHILE - || type == PARSER_STATEMENT_FOR -#if ENABLED (JERRY_ES2015_FOR_OF) - || type == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || type == PARSER_STATEMENT_FOR_IN) + if (parser_statement_flags[type] & PARSER_STATM_CONTINUE_TARGET) { loop_iterator = iterator; } @@ -1772,13 +2280,7 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_INVALID_CONTINUE); } - if (type == PARSER_STATEMENT_DO_WHILE - || type == PARSER_STATEMENT_WHILE - || type == PARSER_STATEMENT_FOR -#if ENABLED (JERRY_ES2015_FOR_OF) - || type == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || type == PARSER_STATEMENT_FOR_IN) + if (parser_statement_flags[type] & PARSER_STATM_CONTINUE_TARGET) { parser_loop_statement_t loop; @@ -1792,8 +2294,7 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ return; } - if (type == PARSER_STATEMENT_WITH - || type == PARSER_STATEMENT_TRY) + if (parser_statement_flags[type] & PARSER_STATM_CONTEXT_BREAK) { opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT; } @@ -1861,7 +2362,7 @@ parser_parse_import_statement (parser_context_t *context_p) /**< parser context parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_MULTIPLY_EXPECTED); } } - else if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + else if (!lexer_token_is_identifier (context_p, "from", 4)) { parser_raise_error (context_p, PARSER_ERR_FROM_COMMA_EXPECTED); } @@ -1871,7 +2372,7 @@ parser_parse_import_statement (parser_context_t *context_p) /**< parser context { /* NameSpaceImport*/ lexer_next_token (context_p); - if (!lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (!lexer_token_is_identifier (context_p, "as", 2)) { parser_raise_error (context_p, PARSER_ERR_AS_EXPECTED); } @@ -1907,7 +2408,7 @@ parser_parse_import_statement (parser_context_t *context_p) /**< parser context parser_module_parse_import_clause (context_p); } - if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (!lexer_token_is_identifier (context_p, "from", 4)) { parser_raise_error (context_p, PARSER_ERR_FROM_EXPECTED); } @@ -1960,10 +2461,7 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ scanner_set_location (context_p, &location); /* 15.2.3.5 Use the synthetic name '*default*' as the identifier. */ - lexer_construct_literal_object (context_p, - (lexer_lit_location_t *) &lexer_default_literal, - lexer_default_literal.type); - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; + lexer_construct_literal_object (context_p, &lexer_default_literal, lexer_default_literal.type); context_p->token.lit_location.type = LEXER_IDENT_LITERAL; parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); @@ -1997,7 +2495,7 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ case LEXER_MULTIPLY: { lexer_next_token (context_p); - if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (!lexer_token_is_identifier (context_p, "from", 4)) { parser_raise_error (context_p, PARSER_ERR_FROM_EXPECTED); } @@ -2007,67 +2505,30 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ break; } case LEXER_KEYW_VAR: + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: { context_p->status_flags |= PARSER_MODULE_STORE_IDENT; parser_parse_var_statement (context_p); - ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, - context_p->module_identifier_lit_p->prop.length); - - if (parser_module_check_duplicate_export (context_p, name_p)) - { - ecma_deref_ecma_string (name_p); - parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); - } - - parser_module_add_names_to_node (context_p, - name_p, - name_p); - ecma_deref_ecma_string (name_p); break; } case LEXER_KEYW_CLASS: { context_p->status_flags |= PARSER_MODULE_STORE_IDENT; parser_parse_class (context_p, true); - ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, - context_p->module_identifier_lit_p->prop.length); - - if (parser_module_check_duplicate_export (context_p, name_p)) - { - ecma_deref_ecma_string (name_p); - parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); - } - - parser_module_add_names_to_node (context_p, - name_p, - name_p); - ecma_deref_ecma_string (name_p); break; } case LEXER_KEYW_FUNCTION: { context_p->status_flags |= PARSER_MODULE_STORE_IDENT; parser_parse_function_statement (context_p); - ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, - context_p->module_identifier_lit_p->prop.length); - - if (parser_module_check_duplicate_export (context_p, name_p)) - { - ecma_deref_ecma_string (name_p); - parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); - } - - parser_module_add_names_to_node (context_p, - name_p, - name_p); - ecma_deref_ecma_string (name_p); break; } case LEXER_LEFT_BRACE: { parser_module_parse_export_clause (context_p); - if (lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (lexer_token_is_identifier (context_p, "from", 4)) { lexer_next_token (context_p); parser_module_handle_module_specifier (context_p); @@ -2112,7 +2573,7 @@ parser_parse_label (parser_context_t *context_p) /**< context */ parser_stack_iterator_read (&iterator, &label_statement, sizeof (parser_label_statement_t)); parser_stack_iterator_skip (&iterator, sizeof (parser_label_statement_t)); - if (lexer_compare_identifier_to_current (context_p, &label_statement.label_ident)) + if (lexer_current_is_literal (context_p, &label_statement.label_ident)) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_LABEL); } @@ -2130,6 +2591,16 @@ parser_parse_label (parser_context_t *context_p) /**< context */ parser_stack_iterator_init (context_p, &context_p->last_statement); } /* parser_parse_label */ +/** + * Strict mode types for statement parsing. + */ +typedef enum +{ + PARSER_USE_STRICT_NOT_FOUND = 0, /**< 'use strict' directive is not found */ + PARSER_USE_STRICT_FOUND = 1, /**< 'use strict' directive is found but strict mode has already been enabled */ + PARSER_USE_STRICT_SET = 2, /**< strict mode is enabled after 'use strict' directive is found */ +} parser_strict_mode_type_t; + /** * Parse statements. */ @@ -2150,12 +2621,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) { parser_emit_cbc_ext (context_p, CBC_EXT_RESOURCE_NAME); parser_flush_cbc (context_p); } +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) context_p->last_line_info_line = 0; #endif /* ENABLED (JERRY_LINE_INFO) */ @@ -2163,31 +2636,35 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ && context_p->token.lit_location.type == LEXER_STRING_LITERAL) { lexer_lit_location_t lit_location; - uint32_t status_flags = context_p->status_flags; + parser_strict_mode_type_t strict_mode = PARSER_USE_STRICT_NOT_FOUND; - JERRY_ASSERT (context_p->stack_depth == 0); + JERRY_ASSERT (context_p->stack_depth <= 1); +#ifndef JERRY_NDEBUG + JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth); +#endif /* !JERRY_NDEBUG */ - lit_location = context_p->token.lit_location; - - if (lit_location.length == PARSER_USE_STRICT_LENGTH - && !lit_location.has_escape - && memcmp (PARSER_USE_STRICT_LITERAL, lit_location.char_p, PARSER_USE_STRICT_LENGTH) == 0) + if (lexer_string_is_use_strict (context_p)) { - context_p->status_flags |= PARSER_IS_STRICT; + strict_mode = PARSER_USE_STRICT_FOUND; + + if (!(context_p->status_flags & PARSER_IS_STRICT)) + { + /* The next token should be parsed in strict mode. */ + context_p->status_flags |= PARSER_IS_STRICT; + strict_mode = PARSER_USE_STRICT_SET; + } } + lit_location = context_p->token.lit_location; lexer_next_token (context_p); - if (context_p->token.type != LEXER_SEMICOLON - && context_p->token.type != LEXER_RIGHT_BRACE - && (!(context_p->token.flags & LEXER_WAS_NEWLINE) - || LEXER_IS_BINARY_OP_TOKEN (context_p->token.type) - || context_p->token.type == LEXER_LEFT_PAREN - || context_p->token.type == LEXER_LEFT_SQUARE - || context_p->token.type == LEXER_DOT)) + if (!lexer_string_is_directive (context_p)) { /* The string is part of an expression statement. */ - context_p->status_flags = status_flags; + if (strict_mode == PARSER_USE_STRICT_SET) + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; + } #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) @@ -2215,14 +2692,20 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - if (context_p->is_show_opcodes - && !(status_flags & PARSER_IS_STRICT) - && (context_p->status_flags & PARSER_IS_STRICT)) + if (strict_mode == PARSER_USE_STRICT_SET && context_p->is_show_opcodes) { JERRY_DEBUG_MSG (" Note: switch to strict mode\n\n"); } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ +#if ENABLED (JERRY_ES2015) + if (strict_mode != PARSER_USE_STRICT_NOT_FOUND + && (context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM)) + { + parser_raise_error (context_p, PARSER_ERR_USE_STRICT_NOT_ALLOWED); + } +#endif /* ENABLED (JERRY_ES2015) */ + if (context_p->token.type == LEXER_SEMICOLON) { lexer_next_token (context_p); @@ -2237,6 +2720,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); parser_emit_cbc (context_p, CBC_POP_BLOCK); parser_flush_cbc (context_p); + break; } } @@ -2255,6 +2739,11 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->stack_depth == context_p->context_stack_depth); #endif /* !JERRY_NDEBUG */ +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (context_p->stack_top_uint8 != PARSER_STATEMENT_PRIVATE_SCOPE + && context_p->stack_top_uint8 != PARSER_STATEMENT_PRIVATE_CONTEXT); +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED && context_p->token.line != context_p->last_breakpoint_line @@ -2262,6 +2751,8 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ && context_p->token.type != LEXER_LEFT_BRACE && context_p->token.type != LEXER_RIGHT_BRACE && context_p->token.type != LEXER_KEYW_VAR + && context_p->token.type != LEXER_KEYW_LET + && context_p->token.type != LEXER_KEYW_CONST && context_p->token.type != LEXER_KEYW_FUNCTION && context_p->token.type != LEXER_KEYW_CASE && context_p->token.type != LEXER_KEYW_DEFAULT) @@ -2281,6 +2772,8 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ && context_p->token.type != LEXER_LEFT_BRACE && context_p->token.type != LEXER_RIGHT_BRACE && context_p->token.type != LEXER_KEYW_VAR + && context_p->token.type != LEXER_KEYW_LET + && context_p->token.type != LEXER_KEYW_CONST && context_p->token.type != LEXER_KEYW_FUNCTION && context_p->token.type != LEXER_KEYW_CASE && context_p->token.type != LEXER_KEYW_DEFAULT) @@ -2298,17 +2791,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ case LEXER_RIGHT_BRACE: { - if (context_p->stack_top_uint8 == PARSER_STATEMENT_LABEL - || context_p->stack_top_uint8 == PARSER_STATEMENT_IF - || context_p->stack_top_uint8 == PARSER_STATEMENT_ELSE - || context_p->stack_top_uint8 == PARSER_STATEMENT_DO_WHILE - || context_p->stack_top_uint8 == PARSER_STATEMENT_WHILE - || context_p->stack_top_uint8 == PARSER_STATEMENT_FOR - || context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_IN -#if ENABLED (JERRY_ES2015_FOR_OF) - || context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_OF -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - || context_p->stack_top_uint8 == PARSER_STATEMENT_WITH) + if (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) { parser_raise_error (context_p, PARSER_ERR_STATEMENT_EXPECTED); } @@ -2317,25 +2800,42 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ case LEXER_LEFT_BRACE: { +#if ENABLED (JERRY_ES2015) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + parser_push_block_context (context_p, false); + } + else + { + parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK); + } +#else /* !ENABLED (JERRY_ES2015) */ parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK); +#endif /* ENABLED (JERRY_ES2015) */ + parser_stack_iterator_init (context_p, &context_p->last_statement); lexer_next_token (context_p); continue; } case LEXER_KEYW_VAR: +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: +#endif /* ENABLED (JERRY_ES2015) */ { parser_parse_var_statement (context_p); break; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { + parser_validate_lexical_context (context_p); parser_parse_class (context_p, true); goto consume_last_statement; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) case LEXER_KEYW_IMPORT: @@ -2425,6 +2925,23 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ CBC_EXT_TRY_CREATE_CONTEXT, &try_statement.branch); +#if ENABLED (JERRY_ES2015) + try_statement.scope_stack_top = context_p->scope_stack_top; + try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top; + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); + + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); + } + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); + } +#endif /* ENABLED (JERRY_ES2015) */ + parser_stack_push (context_p, &try_statement, sizeof (parser_try_statement_t)); parser_stack_push_uint8 (context_p, PARSER_STATEMENT_TRY); parser_stack_iterator_init (context_p, &context_p->last_statement); @@ -2479,57 +2996,38 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ if ((context_p->token.flags & LEXER_WAS_NEWLINE) || context_p->token.type == LEXER_SEMICOLON + || context_p->token.type == LEXER_EOS || context_p->token.type == LEXER_RIGHT_BRACE) { -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } - parser_emit_cbc (context_p, CBC_RETURN); + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE_UNDEFINED); + break; } - else - { -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK); -#if ENABLED (JERRY_ES2015_CLASS) - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK); break; } parser_parse_expression (context_p, PARSE_EXPR); - bool return_with_literal = (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); -#if ENABLED (JERRY_ES2015_CLASS) - return_with_literal = return_with_literal && !PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ - if (return_with_literal) + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + break; } - else - { -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN); - } - else - { -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - parser_emit_cbc (context_p, CBC_RETURN); -#if ENABLED (JERRY_ES2015_CLASS) - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - } + + parser_emit_cbc (context_p, CBC_RETURN); break; } @@ -2546,16 +3044,74 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ lexer_next_token (context_p); break; } + case LEXER_LITERAL: { - if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL - && lexer_check_next_character (context_p, LIT_CHAR_COLON)) + if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { - parser_parse_label (context_p); - lexer_next_token (context_p); - JERRY_ASSERT (context_p->token.type == LEXER_COLON); - lexer_next_token (context_p); - continue; + if (JERRY_UNLIKELY (lexer_check_next_character (context_p, LIT_CHAR_COLON))) + { + parser_parse_label (context_p); + lexer_consume_next_character (context_p); + lexer_next_token (context_p); + continue; + } +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (lexer_token_is_let (context_p))) + { + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION) + { + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + + if (context_p->status_flags & PARSER_IS_FUNCTION) + { + parser_parse_expression_statement (context_p, PARSE_EXPR); + break; + } + + parser_parse_block_expression (context_p, PARSE_EXPR); + break; + } + + context_p->token.type = LEXER_KEYW_LET; + parser_parse_var_statement (context_p); + break; + } + + if (JERRY_UNLIKELY (lexer_token_is_async (context_p)) + && context_p->next_scanner_info_p->source_p == context_p->source_p) + { + bool is_statement = true; + + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION) + { + is_statement = (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT) != 0; + + JERRY_ASSERT (!is_statement || (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC)); + } + else + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION); + + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + + if (is_statement) + { + if (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } + + lexer_next_token (context_p); + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION); + continue; + } + } +#endif /* ENABLED (JERRY_ES2015) */ } /* FALLTHRU */ } @@ -2594,6 +3150,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_stack_iterator_init (context_p, &context_p->last_statement); lexer_next_token (context_p); } +#if ENABLED (JERRY_ES2015) + else if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT) + { + parser_pop_block_context (context_p); + lexer_next_token (context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ else if (context_p->stack_top_uint8 == PARSER_STATEMENT_SWITCH || context_p->stack_top_uint8 == PARSER_STATEMENT_SWITCH_NO_DEFAULT) { @@ -2615,6 +3179,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_set_breaks_to_current_position (context_p, loop.branch_list_p); lexer_next_token (context_p); + +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT) + { + parser_pop_block_context (context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ } else if (context_p->stack_top_uint8 == PARSER_STATEMENT_TRY) { @@ -2626,28 +3198,8 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ { parser_stack_pop_uint8 (context_p); context_p->last_statement.current_p = NULL; - JERRY_ASSERT (context_p->stack_depth == 0); -#ifndef JERRY_NDEBUG - JERRY_ASSERT (context_p->context_stack_depth == 0); -#endif /* !JERRY_NDEBUG */ /* There is no lexer_next_token here, since the * next token belongs to the parent context. */ - -#if ENABLED (JERRY_ES2015_CLASS) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } - parser_emit_cbc (context_p, CBC_RETURN); - parser_flush_cbc (context_p); - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ return; } parser_raise_error (context_p, PARSER_ERR_INVALID_RIGHT_SQUARE); @@ -2724,18 +3276,18 @@ consume_last_statement: } case PARSER_STATEMENT_FOR_IN: -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case PARSER_STATEMENT_FOR_OF: -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ { parser_for_in_of_statement_t for_in_of_statement; parser_loop_statement_t loop; -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) bool is_for_in = (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_IN); #else bool is_for_in = true; -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, &loop, sizeof (parser_loop_statement_t)); @@ -2760,6 +3312,14 @@ consume_last_statement: parser_set_breaks_to_current_position (context_p, loop.branch_list_p); parser_set_branch_to_current_position (context_p, &for_in_of_statement.branch); + +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE + || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT) + { + parser_pop_block_context (context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ continue; } @@ -2778,11 +3338,6 @@ consume_last_statement: } } - JERRY_ASSERT (context_p->stack_depth == 0); -#ifndef JERRY_NDEBUG - JERRY_ASSERT (context_p->context_stack_depth == 0); -#endif /* !JERRY_NDEBUG */ - parser_stack_pop_uint8 (context_p); context_p->last_statement.current_p = NULL; @@ -2848,9 +3403,9 @@ parser_free_jumps (parser_stack_iterator_t iterator) /**< iterator position */ case PARSER_STATEMENT_WHILE: case PARSER_STATEMENT_FOR: case PARSER_STATEMENT_FOR_IN: -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case PARSER_STATEMENT_FOR_OF: -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ { parser_loop_statement_t loop; diff --git a/jerry-core/parser/js/js-parser-tagged-template-literal.c b/jerry-core/parser/js/js-parser-tagged-template-literal.c new file mode 100644 index 00000000..3ed96751 --- /dev/null +++ b/jerry-core/parser/js/js-parser-tagged-template-literal.c @@ -0,0 +1,152 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "js-parser-tagged-template-literal.h" +#include "js-lexer.h" +#include "ecma-array-object.h" +#include "ecma-builtin-helpers.h" +#include "ecma-gc.h" +#include "ecma-helpers.h" +#include "ecma-objects.h" + +/* \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_tagged_template_literal Tagged template literal + * @{ + */ + +#if ENABLED (JERRY_ES2015) +/** + * Append the cooked and raw string to the corresponding array + */ +void +parser_tagged_template_literal_append_strings (parser_context_t *context_p, /**< parser context */ + ecma_object_t *template_obj_p, /**< template object */ + ecma_object_t *raw_strings_p, /**< raw strings object */ + uint32_t prop_idx) /**< property index to set the values */ +{ + lexer_lit_location_t *lit_loc_p = &context_p->token.lit_location; + + if (lit_loc_p->length == 0 && !lit_loc_p->has_escape) + { + ecma_builtin_helper_def_prop_by_index (template_obj_p, + prop_idx, + ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY), + ECMA_PROPERTY_FLAG_ENUMERABLE); + + ecma_builtin_helper_def_prop_by_index (raw_strings_p, + prop_idx, + ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY), + ECMA_PROPERTY_FLAG_ENUMERABLE); + return; + } + + uint8_t local_byte_array[LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE]; + const uint8_t *source_p = lexer_convert_literal_to_chars (context_p, + &context_p->token.lit_location, + local_byte_array, + LEXER_STRING_NO_OPTS); + + ecma_string_t *raw_str_p; + ecma_string_t *cooked_str_p = ecma_new_ecma_string_from_utf8 (source_p, lit_loc_p->length); + parser_free_allocated_buffer (context_p); + + if (lit_loc_p->has_escape) + { + context_p->source_p = context_p->token.lit_location.char_p - 1; + lexer_parse_string (context_p, LEXER_STRING_RAW); + source_p = lexer_convert_literal_to_chars (context_p, + &context_p->token.lit_location, + local_byte_array, + LEXER_STRING_RAW); + + raw_str_p = ecma_new_ecma_string_from_utf8 (source_p, lit_loc_p->length); + parser_free_allocated_buffer (context_p); + } + else + { + ecma_ref_ecma_string (cooked_str_p); + raw_str_p = cooked_str_p; + } + + ecma_builtin_helper_def_prop_by_index (template_obj_p, + prop_idx, + ecma_make_string_value (cooked_str_p), + ECMA_PROPERTY_FLAG_ENUMERABLE); + + ecma_builtin_helper_def_prop_by_index (raw_strings_p, + prop_idx, + ecma_make_string_value (raw_str_p), + ECMA_PROPERTY_FLAG_ENUMERABLE); + + ecma_deref_ecma_string (cooked_str_p); + ecma_deref_ecma_string (raw_str_p); +} /* parser_tagged_template_literal_append_strings */ + +/** + * Create new tagged template literal object + * + * @return pointer to the allocated object + */ +ecma_object_t * +parser_new_tagged_template_literal (ecma_object_t **raw_strings_p) /**< [out] raw strings object */ +{ + ecma_object_t *template_obj_p = ecma_op_new_array_object (0); + *raw_strings_p = ecma_op_new_array_object (0); + + ecma_builtin_helper_def_prop (template_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_RAW), + ecma_make_object_value (*raw_strings_p), + ECMA_PROPERTY_FIXED); + ecma_deref_object (*raw_strings_p); + + return template_obj_p; +} /* parser_new_tagged_template_literal */ + +/** + * Set integrity level of the given template array object to "frozen" + */ +static void +parser_tagged_template_literal_freeze_array (ecma_object_t *obj_p) +{ + JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); + + ecma_op_ordinary_object_prevent_extensions (obj_p); + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + uint8_t new_prop_value = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); + ext_obj_p->u.array.u.length_prop = new_prop_value; +} /* parser_tagged_template_literal_freeze_array */ + +/** + * Finalize the tagged template object + */ +void +parser_tagged_template_literal_finalize (ecma_object_t *template_obj_p, /**< template object */ + ecma_object_t *raw_strings_p) /**< raw strings object */ +{ + parser_tagged_template_literal_freeze_array (template_obj_p); + parser_tagged_template_literal_freeze_array (raw_strings_p); +} /* parser_tagged_template_literal_finalize */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * @} + * @} + * @} + */ diff --git a/jerry-core/parser/js/js-parser-tagged-template-literal.h b/jerry-core/parser/js/js-parser-tagged-template-literal.h new file mode 100644 index 00000000..b4fe9a59 --- /dev/null +++ b/jerry-core/parser/js/js-parser-tagged-template-literal.h @@ -0,0 +1,51 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_TAGGED_TEMPLATE_LITERAL_H +#define ECMA_TAGGED_TEMPLATE_LITERAL_H + +/* \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_tagged_template_literal Tagged template literal + * @{ + */ + +#include "common.h" +#include "ecma-globals.h" +#include "js-parser-internal.h" + +#if ENABLED (JERRY_ES2015) +ecma_object_t * +parser_new_tagged_template_literal (ecma_object_t **raw_strings_p); + +void +parser_tagged_template_literal_append_strings (parser_context_t *context_p, ecma_object_t *template_obj_p, + ecma_object_t *raw_strings_p, uint32_t prop_index); + +void +parser_tagged_template_literal_finalize (ecma_object_t *template_obj_p, ecma_object_t *raw_strings_p); +#endif /* ENABLED (JERRY_ES2015) */ + +#endif /* ECMA_TAGGED_TEMPLATE_LITERAL_H */ + +/** + * @} + * @} + * @} + */ diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index 3c7a7174..3bcf9b07 100755 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -85,6 +85,60 @@ parser_emit_two_bytes (parser_context_t *context_p, /**< context */ } \ (context_p)->byte_code.last_p->bytes[(context_p)->byte_code.last_position++] = (uint8_t) (byte) +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + +/** + * Print literal corresponding to the current index + */ +static void +parser_print_literal (parser_context_t *context_p, /**< context */ + uint16_t literal_index) /**< index of literal */ +{ + parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p; + parser_scope_stack_t *scope_stack_end_p = scope_stack_p + context_p->scope_stack_top; + bool in_scope_literal = false; + + while (scope_stack_p < scope_stack_end_p) + { + scope_stack_end_p--; + + if (scope_stack_end_p->map_from == PARSER_SCOPE_STACK_FUNC) + { + if (literal_index == scope_stack_end_p->map_to) + { + in_scope_literal = true; + break; + } + } + else if (literal_index == scanner_decode_map_to (scope_stack_end_p)) + { + in_scope_literal = true; + break; + } + } + + if (literal_index < PARSER_REGISTER_START) + { + JERRY_DEBUG_MSG (in_scope_literal ? " IDX:%d->" : " idx:%d->", literal_index); + lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index); + util_print_literal (literal_p); + return; + } + + if (!in_scope_literal) + { + JERRY_DEBUG_MSG (" reg:%d", (int) (literal_index - PARSER_REGISTER_START)); + return; + } + + JERRY_DEBUG_MSG (" REG:%d->", (int) (literal_index - PARSER_REGISTER_START)); + + lexer_literal_t *literal_p = PARSER_GET_LITERAL (scope_stack_end_p->map_from); + util_print_literal (literal_p); +} /* parser_print_literal */ + +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + /** * Append the current byte code to the stream */ @@ -99,6 +153,8 @@ parser_flush_cbc (parser_context_t *context_p) /**< context */ return; } + JERRY_ASSERT (last_opcode != PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)); + context_p->status_flags |= PARSER_NO_END_LABEL; if (PARSER_IS_BASIC_OPCODE (last_opcode)) @@ -181,26 +237,16 @@ parser_flush_cbc (parser_context_t *context_p) /**< context */ if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) { - uint16_t literal_index = context_p->last_cbc.literal_index; - lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index); - JERRY_DEBUG_MSG (" idx:%d->", literal_index); - util_print_literal (literal_p); + parser_print_literal (context_p, context_p->last_cbc.literal_index); } if (flags & CBC_HAS_LITERAL_ARG2) { - uint16_t literal_index = context_p->last_cbc.value; - lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index); - JERRY_DEBUG_MSG (" idx:%d->", literal_index); - util_print_literal (literal_p); + parser_print_literal (context_p, context_p->last_cbc.value); if (!(flags & CBC_HAS_LITERAL_ARG)) { - literal_index = context_p->last_cbc.third_literal_index; - - literal_p = PARSER_GET_LITERAL (literal_index); - JERRY_DEBUG_MSG (" idx:%d->", literal_index); - util_print_literal (literal_p); + parser_print_literal (context_p, context_p->last_cbc.third_literal_index); } } @@ -273,9 +319,32 @@ parser_emit_cbc_literal (parser_context_t *context_p, /**< context */ context_p->last_cbc_opcode = opcode; context_p->last_cbc.literal_index = literal_index; context_p->last_cbc.literal_type = LEXER_UNUSED_LITERAL; - context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY; + context_p->last_cbc.literal_keyword_type = LEXER_EOS; } /* parser_emit_cbc_literal */ +/** + * Append a byte code with a literal and value argument + */ +void +parser_emit_cbc_literal_value (parser_context_t *context_p, /**< context */ + uint16_t opcode, /**< opcode */ + uint16_t literal_index, /**< literal index */ + uint16_t value) /**< value */ +{ + JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)); + + if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE) + { + parser_flush_cbc (context_p); + } + + context_p->last_cbc_opcode = opcode; + context_p->last_cbc.literal_index = literal_index; + context_p->last_cbc.literal_type = LEXER_UNUSED_LITERAL; + context_p->last_cbc.literal_keyword_type = LEXER_EOS; + context_p->last_cbc.value = value; +} /* parser_emit_cbc_literal_value */ + /** * Append a byte code with the current literal argument */ @@ -293,7 +362,7 @@ parser_emit_cbc_literal_from_token (parser_context_t *context_p, /**< context */ context_p->last_cbc_opcode = opcode; context_p->last_cbc.literal_index = context_p->lit_object.index; context_p->last_cbc.literal_type = context_p->token.lit_location.type; - context_p->last_cbc.literal_object_type = context_p->lit_object.type; + context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type; } /* parser_emit_cbc_literal_from_token */ /** @@ -497,11 +566,7 @@ parser_emit_cbc_forward_branch (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 - opcode++; -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ - PARSER_PLUS_EQUAL_U16 (opcode, 2); -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ + PARSER_PLUS_EQUAL_U16 (opcode, PARSER_MAX_BRANCH_LENGTH - 1); parser_emit_two_bytes (context_p, (uint8_t) opcode, 0); branch_p->page_p = context_p->byte_code.last_p; @@ -509,13 +574,13 @@ parser_emit_cbc_forward_branch (parser_context_t *context_p, /**< context */ context_p->byte_code_size += extra_byte_code_increase; -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 +#if PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX PARSER_APPEND_TO_BYTE_CODE (context_p, 0); - context_p->byte_code_size += 3; -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ +#else /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */ parser_emit_two_bytes (context_p, 0, 0); - context_p->byte_code_size += 4; -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ +#endif /* PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX */ + + context_p->byte_code_size += PARSER_MAX_BRANCH_LENGTH + 1; if (context_p->stack_depth > context_p->stack_limit) { @@ -612,35 +677,30 @@ parser_emit_cbc_backward_branch (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ context_p->byte_code_size += 2; -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 - if (offset > 255) +#if PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX + if (offset > UINT16_MAX) { opcode++; context_p->byte_code_size++; } -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ - if (offset > 65535) - { - PARSER_PLUS_EQUAL_U16 (opcode, 2); - context_p->byte_code_size += 2; - } - else if (offset > 255) +#endif /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */ + + if (offset > UINT8_MAX) { opcode++; context_p->byte_code_size++; } -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ PARSER_APPEND_TO_BYTE_CODE (context_p, (uint8_t) opcode); -#if PARSER_MAXIMUM_CODE_SIZE > 65535 - if (offset > 65535) +#if PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX + if (offset > UINT16_MAX) { PARSER_APPEND_TO_BYTE_CODE (context_p, offset >> 16); } -#endif /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ +#endif /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */ - if (offset > 255) + if (offset > UINT8_MAX) { PARSER_APPEND_TO_BYTE_CODE (context_p, (offset >> 8) & 0xff); } @@ -676,14 +736,14 @@ parser_set_branch_to_current_position (parser_context_t *context_p, /**< context JERRY_ASSERT (delta <= PARSER_MAXIMUM_CODE_SIZE); -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 +#if PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX page_p->bytes[offset++] = (uint8_t) (delta >> 8); if (offset >= PARSER_CBC_STREAM_PAGE_SIZE) { page_p = page_p->next_p; offset = 0; } -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ +#else /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */ page_p->bytes[offset++] = (uint8_t) (delta >> 16); if (offset >= PARSER_CBC_STREAM_PAGE_SIZE) { @@ -696,8 +756,8 @@ parser_set_branch_to_current_position (parser_context_t *context_p, /**< context page_p = page_p->next_p; offset = 0; } -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ - page_p->bytes[offset++] = delta & 0xff; +#endif /* PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX */ + page_p->bytes[offset] = delta & 0xff; } /* parser_set_branch_to_current_position */ /** @@ -754,6 +814,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Maximum number of literals reached."; } + case PARSER_ERR_SCOPE_STACK_LIMIT_REACHED: + { + return "Maximum depth of scope stack reached."; + } case PARSER_ERR_ARGUMENT_LIMIT_REACHED: { return "Maximum number of function arguments reached."; @@ -766,18 +830,24 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Maximum JERRY_STACK_LIMIT stack limit reached."; } - case PARSER_ERR_REGISTER_LIMIT_REACHED: - { - return "Maximum number of registers is reached."; - } case PARSER_ERR_INVALID_CHARACTER: { return "Invalid (unexpected) character."; } + case PARSER_ERR_INVALID_OCTAL_DIGIT: + { + return "Invalid octal digit."; + } case PARSER_ERR_INVALID_HEX_DIGIT: { return "Invalid hexadecimal digit."; } +#if ENABLED (JERRY_ES2015) + case PARSER_ERR_INVALID_BIN_DIGIT: + { + return "Invalid binary digit."; + } +#endif /* ENABLED (JERRY_ES2015) */ case PARSER_ERR_INVALID_ESCAPE_SEQUENCE: { return "Invalid escape sequence."; @@ -794,6 +864,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Character cannot be part of an identifier."; } + case PARSER_ERR_INVALID_KEYWORD: + { + return "Escape sequences are not allowed in keywords."; + } case PARSER_ERR_INVALID_NUMBER: { return "Invalid number."; @@ -874,6 +948,28 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Arguments is not allowed to be used here in strict mode."; } +#if ENABLED (JERRY_ES2015) + case PARSER_ERR_USE_STRICT_NOT_ALLOWED: + { + return "The 'use strict' directive is not allowed for functions with non-simple arguments."; + } + case PARSER_ERR_YIELD_NOT_ALLOWED: + { + return "Yield expression is not allowed here."; + } + case PARSER_ERR_AWAIT_NOT_ALLOWED: + { + return "Await expression is not allowed here."; + } + case PARSER_ERR_FOR_IN_OF_DECLARATION: + { + return "for in-of loop variable declaration may not have an initializer."; + } + case PARSER_ERR_DUPLICATED_PROTO: + { + return "Duplicate __proto__ fields are not allowed in object literals."; + } +#endif /* ENABLED (JERRY_ES2015) */ case PARSER_ERR_DELETE_IDENT_NOT_ALLOWED: { return "Deleting identifier is not allowed in strict mode."; @@ -902,24 +998,6 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Case statement must be in a switch block."; } -#if ENABLED (JERRY_ES2015_CLASS) - case PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS: - { - return "Multiple constructors are not allowed."; - } - case PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR: - { - return "Class constructor may not be an accessor."; - } - case PARSER_ERR_CLASS_STATIC_PROTOTYPE: - { - return "Classes may not have a static property called 'prototype'."; - } - case PARSER_ERR_UNEXPECTED_SUPER_REFERENCE: - { - return "Super is not allowed to be used here."; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ case PARSER_ERR_LEFT_PAREN_EXPECTED: { return "Expected '(' token."; @@ -936,12 +1014,6 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Expected ']' token."; } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - case PARSER_ERR_RIGHT_BRACE_EXPECTED: - { - return "Expected '}' token."; - } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ case PARSER_ERR_COLON_EXPECTED: { return "Expected ':' token."; @@ -958,12 +1030,6 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Expected 'in' token."; } -#if ENABLED (JERRY_ES2015_FOR_OF) - case PARSER_ERR_OF_EXPECTED: - { - return "Expected 'of' token."; - } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ case PARSER_ERR_WHILE_EXPECTED: { return "While expected for do-while loop."; @@ -992,6 +1058,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Primary expression expected."; } + case PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED: + { + return "Left-hand-side expression expected."; + } case PARSER_ERR_STATEMENT_EXPECTED: { return "Statement expected."; @@ -1048,24 +1118,6 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Duplicated label."; } -#if ((ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)) \ - || (ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER))) - case PARSER_ERR_DUPLICATED_ARGUMENT_NAMES: - { - return "Duplicated function argument names are not allowed here."; - } -#endif /* ((ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)) - || (ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER))) */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - case PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER: - { - return "Rest parameter must be the last formal parameter."; - } - case PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER: - { - return "Rest parameter may not have a default initializer."; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ case PARSER_ERR_OBJECT_PROPERTY_REDEFINED: { return "Property of object literal redefined."; @@ -1074,7 +1126,96 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Non-strict argument definition."; } - +#if ENABLED (JERRY_ES2015) + case PARSER_ERR_VARIABLE_REDECLARED: + { + return "Local variable is redeclared."; + } + case PARSER_ERR_LEXICAL_SINGLE_STATEMENT: + { + return "Lexical declaration cannot appear in a single-statement context."; + } + case PARSER_ERR_LABELLED_FUNC_NOT_IN_BLOCK: + { + return "Labelled functions are only allowed inside blocks."; + } + case PARSER_ERR_LEXICAL_LET_BINDING: + { + return "Let binding cannot appear in let/const declarations."; + } + case PARSER_ERR_MISSING_ASSIGN_AFTER_CONST: + { + return "Value assignment is expected after a const declaration."; + } + case PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS: + { + return "Multiple constructors are not allowed."; + } + case PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR: + { + return "Class constructor may not be an accessor."; + } + case PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR: + { + return "Class constructor may not be a generator."; + } + case PARSER_ERR_CLASS_STATIC_PROTOTYPE: + { + return "Classes may not have a static property called 'prototype'."; + } + case PARSER_ERR_UNEXPECTED_SUPER_KEYWORD: + { + return "Super is not allowed to be used here."; + } + case PARSER_ERR_RIGHT_BRACE_EXPECTED: + { + return "Expected '}' token."; + } + case PARSER_ERR_OF_EXPECTED: + { + return "Expected 'of' token."; + } + case PARSER_ERR_ASSIGNMENT_EXPECTED: + { + return "Unexpected arrow function or yield expression (parentheses around the expression may help)."; + } + case PARSER_ERR_DUPLICATED_ARGUMENT_NAMES: + { + return "Duplicated function argument names are not allowed here."; + } + case PARSER_ERR_INVALID_DESTRUCTURING_PATTERN: + { + return "Invalid destructuring assignment target."; + } + case PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION: + { + return "Illegal property in declaration context."; + } + case PARSER_ERR_INVALID_EXPONENTIATION: + { + return "Left operand of ** operator cannot be unary expression."; + } + case PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER: + { + return "Rest parameter must be the last formal parameter."; + } + case PARSER_ERR_SETTER_REST_PARAMETER: + { + return "Setter function argument must not be a rest parameter."; + } + case PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER: + { + return "Rest parameter may not have a default initializer."; + } + case PARSER_ERR_NEW_TARGET_EXPECTED: + { + return "Expected new.target expression."; + } + case PARSER_ERR_NEW_TARGET_NOT_ALLOWED: + { + return "new.target expression is not allowed here."; + } +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) case PARSER_ERR_FILE_NOT_FOUND: { diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index cb4770ba..47ff69e7 100755 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -26,10 +26,15 @@ JERRY_STATIC_ASSERT ((int) ECMA_PARSE_STRICT_MODE == (int) PARSER_IS_STRICT, ecma_parse_strict_mode_must_be_equal_to_parser_is_strict); -#if ENABLED (JERRY_ES2015_CLASS) -JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OFFSET) == PARSER_CLASS_CONSTRUCTOR, - ecma_class_parse_options_must_be_able_to_be_shifted_to_ecma_general_flags); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) +JERRY_STATIC_ASSERT (PARSER_SAVE_STATUS_FLAGS (PARSER_ALLOW_SUPER) == 0x1, + incorrect_saving_of_ecma_parse_allow_super); +JERRY_STATIC_ASSERT (PARSER_RESTORE_STATUS_FLAGS (ECMA_PARSE_ALLOW_SUPER) == PARSER_ALLOW_SUPER, + incorrect_restoring_of_ecma_parse_allow_super); + +JERRY_STATIC_ASSERT (PARSER_RESTORE_STATUS_FLAGS (ECMA_PARSE_FUNCTION_CONTEXT) == 0, + ecma_parse_function_context_must_not_be_transformed); +#endif /* ENABLED (JERRY_ES2015) */ /** \addtogroup parser Parser * @{ @@ -41,608 +46,197 @@ JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OF * @{ */ -/** - * Copy identifiers if needed. - */ -static void -parser_copy_identifiers (parser_context_t *context_p) /**< context */ -{ - parser_saved_context_t *parent_p = context_p->last_context_p; - - if (parent_p == NULL || !(parent_p->status_flags & PARSER_IS_FUNCTION)) - { - /* Return if this function is not a nested function. */ - return; - } - - if (context_p->status_flags & PARSER_NO_REG_STORE) - { - /* This flag must affect all parent functions. */ - parent_p->status_flags |= PARSER_NO_REG_STORE; - return; - } - - parser_list_iterator_t literal_iterator; - lexer_literal_t *literal_p; - - parser_list_t parent_literal_pool; - - /* Accessing the parent literal pool requires all data. */ - parent_literal_pool.data = parent_p->literal_pool_data; - parent_literal_pool.page_size = context_p->literal_pool.page_size; - parent_literal_pool.item_size = context_p->literal_pool.item_size; - parent_literal_pool.item_count = context_p->literal_pool.item_count; - - parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); - while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) - { - if (literal_p->type != LEXER_IDENT_LITERAL || (literal_p->status_flags & LEXER_FLAG_VAR)) - { - continue; - } - - parser_list_iterator_t parent_literal_iterator; - parser_list_iterator_init (&parent_literal_pool, &parent_literal_iterator); - - lexer_literal_t *parent_literal_p; - const uint8_t *char_p = literal_p->u.char_p; - size_t length = literal_p->prop.length; - - while ((parent_literal_p = (lexer_literal_t *) parser_list_iterator_next (&parent_literal_iterator)) != NULL) - { - if (parent_literal_p->type == LEXER_IDENT_LITERAL - && parent_literal_p->prop.length == length - && memcmp (parent_literal_p->u.char_p, char_p, length) == 0) - { - /* This literal is known by the parent. */ - parent_literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - break; - } - } - - if (parent_literal_p != NULL) - { - continue; - } - - if (parent_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } - - parent_literal_p = (lexer_literal_t *) parser_list_append (context_p, &parent_literal_pool); - - /* The literal data is updated at every iteration to handle out-of memory. */ - parent_p->literal_pool_data = parent_literal_pool.data; - - parent_literal_p->prop.length = (prop_length_t) length; - parent_literal_p->type = LEXER_IDENT_LITERAL; - parent_literal_p->status_flags = (uint8_t) (literal_p->status_flags & LEXER_FLAG_SOURCE_PTR); - parent_literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE | LEXER_FLAG_UNUSED_IDENT; - parent_literal_p->u.char_p = char_p; - - /* The buffer ownership is passed to the parent by - * setting this flag which prevents freeing the buffer. */ - literal_p->status_flags |= LEXER_FLAG_SOURCE_PTR; - - parent_p->literal_count++; - } -} /* parser_copy_identifiers */ - /** * Compute real literal indicies. * * @return length of the prefix opcodes */ -static size_t +static void parser_compute_indicies (parser_context_t *context_p, /**< context */ uint16_t *ident_end, /**< end of the identifier group */ - uint16_t *uninitialized_var_end, /**< end of the uninitialized var group */ - uint16_t *initialized_var_end, /**< end of the initialized var group */ uint16_t *const_literal_end) /**< end of the const literal group */ { parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; - size_t length = 0; - uint16_t literal_one_byte_limit; - uint32_t status_flags = context_p->status_flags; - uint16_t argument_count; - uint16_t register_count = context_p->register_count; - uint16_t uninitialized_var_count = 0; - uint16_t initialized_var_count = 0; uint16_t ident_count = 0; uint16_t const_literal_count = 0; - uint16_t register_index; - uint16_t uninitialized_var_index; - uint16_t initialized_var_index; uint16_t ident_index; uint16_t const_literal_index; uint16_t literal_index; - if (status_flags & PARSER_ARGUMENTS_NOT_NEEDED) - { - status_flags &= (uint32_t) ~PARSER_ARGUMENTS_NEEDED; - context_p->status_flags = status_flags; - } - /* First phase: count the number of items in each group. */ parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) { - if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT) - { -#if !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) - { - jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); - } -#endif /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - - context_p->literal_count--; - continue; - } - -#if !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - if (literal_p->type == LEXER_IDENT_LITERAL - || literal_p->type == LEXER_STRING_LITERAL) - { - const uint8_t *char_p = literal_p->u.char_p; - - if ((literal_p->status_flags & LEXER_FLAG_SOURCE_PTR) - && literal_p->prop.length < 0xfff) - { - size_t bytes_to_end = (size_t) (context_p->source_end_p - char_p); - - if (bytes_to_end < 0xfffff) - { - literal_p->u.source_data = ((uint32_t) bytes_to_end) | (((uint32_t) literal_p->prop.length) << 20); - literal_p->status_flags |= LEXER_FLAG_LATE_INIT; - status_flags |= PARSER_HAS_LATE_LIT_INIT; - context_p->status_flags = status_flags; - char_p = NULL; - } - } - - if (char_p != NULL) - { - literal_p->u.value = ecma_find_or_create_literal_string (char_p, - literal_p->prop.length); - - if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) - { - jmem_heap_free_block ((void *) char_p, literal_p->prop.length); - /* This literal should not be freed even if an error is encountered later. */ - literal_p->status_flags |= LEXER_FLAG_SOURCE_PTR; - } - } - } -#endif /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - switch (literal_p->type) { case LEXER_IDENT_LITERAL: { - if (literal_p->status_flags & LEXER_FLAG_VAR) - { - if (status_flags & (PARSER_NO_REG_STORE | PARSER_ARGUMENTS_NEEDED)) - { - literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - } - - if (literal_p->status_flags & LEXER_FLAG_INITIALIZED) - { - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - if ((status_flags & PARSER_ARGUMENTS_NEEDED) - && !(status_flags & PARSER_IS_STRICT)) - { - literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - } - - /* Arguments are bound to their position, or - * moved to the initialized var section. */ - if (literal_p->status_flags & LEXER_FLAG_NO_REG_STORE) - { - initialized_var_count++; - context_p->literal_count++; - } - } - else if (!(literal_p->status_flags & LEXER_FLAG_NO_REG_STORE) - && register_count < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) - { - register_count++; - } - else - { - literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - initialized_var_count++; - } - - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } - } - else if (!(literal_p->status_flags & LEXER_FLAG_NO_REG_STORE) - && register_count < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) - { - register_count++; - } - else - { - literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - uninitialized_var_count++; - } - - if (literal_p->status_flags & LEXER_FLAG_NO_REG_STORE) - { - status_flags |= PARSER_LEXICAL_ENV_NEEDED; - context_p->status_flags = status_flags; - } - } - else + if (literal_p->status_flags & LEXER_FLAG_USED) { ident_count++; + break; + } +#if !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + else if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) + { + jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); + /* This literal should not be freed even if an error is encountered later. */ + literal_p->status_flags |= LEXER_FLAG_SOURCE_PTR; + } +#endif /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + continue; + } + case LEXER_STRING_LITERAL: + { + const_literal_count++; + break; + } + case LEXER_NUMBER_LITERAL: + { + const_literal_count++; + continue; + } + case LEXER_FUNCTION_LITERAL: + case LEXER_REGEXP_LITERAL: + { + continue; + } + default: + { + JERRY_ASSERT (literal_p->type == LEXER_UNUSED_LITERAL); + continue; + } + } + +#if !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + const uint8_t *char_p = literal_p->u.char_p; + uint32_t status_flags = context_p->status_flags; + + if ((literal_p->status_flags & LEXER_FLAG_SOURCE_PTR) + && literal_p->prop.length < 0xfff) + { + size_t bytes_to_end = (size_t) (context_p->source_end_p - char_p); + + if (bytes_to_end < 0xfffff) + { + literal_p->u.source_data = ((uint32_t) bytes_to_end) | (((uint32_t) literal_p->prop.length) << 20); + literal_p->status_flags |= LEXER_FLAG_LATE_INIT; + status_flags |= PARSER_HAS_LATE_LIT_INIT; + context_p->status_flags = status_flags; + char_p = NULL; + } + } + + if (char_p != NULL) + { + literal_p->u.value = ecma_find_or_create_literal_string (char_p, + literal_p->prop.length); + + if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) + { + jmem_heap_free_block ((void *) char_p, literal_p->prop.length); + /* This literal should not be freed even if an error is encountered later. */ + literal_p->status_flags |= LEXER_FLAG_SOURCE_PTR; + } + } +#endif /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + } + + ident_index = context_p->register_count; + const_literal_index = (uint16_t) (ident_index + ident_count); + literal_index = (uint16_t) (const_literal_index + const_literal_count); + + /* Second phase: Assign an index to each literal. */ + parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); + + while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) + { + switch (literal_p->type) + { + case LEXER_IDENT_LITERAL: + { + if (literal_p->status_flags & LEXER_FLAG_USED) + { + literal_p->prop.index = ident_index; + ident_index++; } break; } case LEXER_STRING_LITERAL: case LEXER_NUMBER_LITERAL: - { - const_literal_count++; - break; - } - case LEXER_UNUSED_LITERAL: - { - if (!(literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) - { - context_p->literal_count--; - } - break; - } - } - } - - if (context_p->literal_count <= CBC_MAXIMUM_SMALL_VALUE) - { - literal_one_byte_limit = CBC_MAXIMUM_BYTE_VALUE - 1; - } - else - { - literal_one_byte_limit = CBC_LOWER_SEVEN_BIT_MASK; - } - - if (uninitialized_var_count > 0) - { - /* Opcode byte and a literal argument. */ - length += 2; - if ((register_count + uninitialized_var_count - 1) > literal_one_byte_limit) - { - length++; - } - } - - register_index = context_p->register_count; - uninitialized_var_index = register_count; - initialized_var_index = (uint16_t) (uninitialized_var_index + uninitialized_var_count); - ident_index = (uint16_t) (initialized_var_index + initialized_var_count); - const_literal_index = (uint16_t) (ident_index + ident_count); - literal_index = (uint16_t) (const_literal_index + const_literal_count); - - if (initialized_var_count > 2) - { - status_flags |= PARSER_HAS_INITIALIZED_VARS; - context_p->status_flags = status_flags; - - /* Opcode byte and two literal arguments. */ - length += 3; - if (initialized_var_index > literal_one_byte_limit) - { - length++; - } - if (ident_index - 1 > literal_one_byte_limit) - { - length++; - } - } - - /* Second phase: Assign an index to each literal. */ - parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); - argument_count = 0; - - while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) - { - uint16_t init_index; - - if (literal_p->type != LEXER_IDENT_LITERAL) - { - if (literal_p->type == LEXER_STRING_LITERAL - || literal_p->type == LEXER_NUMBER_LITERAL) { JERRY_ASSERT ((literal_p->status_flags & ~(LEXER_FLAG_SOURCE_PTR | LEXER_FLAG_LATE_INIT)) == 0); literal_p->prop.index = const_literal_index; const_literal_index++; - continue; + break; } - - if (literal_p->type != LEXER_UNUSED_LITERAL) + case LEXER_FUNCTION_LITERAL: + case LEXER_REGEXP_LITERAL: { JERRY_ASSERT (literal_p->status_flags == 0); - JERRY_ASSERT (literal_p->type == LEXER_FUNCTION_LITERAL - || literal_p->type == LEXER_REGEXP_LITERAL); literal_p->prop.index = literal_index; literal_index++; - continue; + break; } - - JERRY_ASSERT ((literal_p->status_flags & ~(LEXER_FLAG_FUNCTION_ARGUMENT | LEXER_FLAG_SOURCE_PTR)) == 0); - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + default: { - argument_count++; + JERRY_ASSERT (literal_p->type == LEXER_UNUSED_LITERAL + && literal_p->status_flags == LEXER_FLAG_FUNCTION_ARGUMENT); + break; } - continue; - } - - if (literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT) - { - continue; - } - - if (!(literal_p->status_flags & LEXER_FLAG_VAR)) - { - literal_p->prop.index = ident_index; - ident_index++; - continue; - } - - if (!(literal_p->status_flags & LEXER_FLAG_INITIALIZED)) - { - if (!(literal_p->status_flags & LEXER_FLAG_NO_REG_STORE)) - { - JERRY_ASSERT (register_count <= PARSER_MAXIMUM_NUMBER_OF_REGISTERS); - /* This var literal can be stored in a register. */ - literal_p->prop.index = register_index; - register_index++; - } - else - { - literal_p->prop.index = uninitialized_var_index; - uninitialized_var_index++; - } - continue; - } - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - if (literal_p->status_flags & LEXER_FLAG_NO_REG_STORE) - { - literal_p->prop.index = initialized_var_index; - initialized_var_index++; - init_index = argument_count; - argument_count++; - } - else - { - literal_p->prop.index = argument_count; - argument_count++; - continue; - } - } - else - { - if (!(literal_p->status_flags & LEXER_FLAG_NO_REG_STORE)) - { - JERRY_ASSERT (register_count <= PARSER_MAXIMUM_NUMBER_OF_REGISTERS); - /* This var literal can be stored in a register. */ - literal_p->prop.index = register_index; - register_index++; - } - else - { - literal_p->prop.index = initialized_var_index; - initialized_var_index++; - } - - init_index = literal_index; - literal_index++; - - lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); - - JERRY_ASSERT (func_literal_p != NULL - && func_literal_p->type == LEXER_FUNCTION_LITERAL); - func_literal_p->prop.index = init_index; - } - - /* A CBC_INITIALIZE_VAR instruction or part of a CBC_INITIALIZE_VARS instruction. */ - if (!(status_flags & PARSER_HAS_INITIALIZED_VARS) - || !(literal_p->status_flags & LEXER_FLAG_NO_REG_STORE)) - { - length += 2; - if (literal_p->prop.index > literal_one_byte_limit) - { - length++; - } - } - - length++; - if (init_index > literal_one_byte_limit) - { - length++; } } - JERRY_ASSERT (argument_count == context_p->argument_count); - JERRY_ASSERT (register_index == register_count); - JERRY_ASSERT (uninitialized_var_index == register_count + uninitialized_var_count); - JERRY_ASSERT (initialized_var_index == uninitialized_var_index + initialized_var_count); - JERRY_ASSERT (ident_index == initialized_var_index + ident_count); + JERRY_ASSERT (ident_index == context_p->register_count + ident_count); JERRY_ASSERT (const_literal_index == ident_index + const_literal_count); - JERRY_ASSERT (literal_index == context_p->literal_count); + JERRY_ASSERT (literal_index <= context_p->register_count + context_p->literal_count); + + context_p->literal_count = literal_index; *ident_end = ident_index; - *uninitialized_var_end = uninitialized_var_index; - *initialized_var_end = initialized_var_index; *const_literal_end = const_literal_index; - context_p->register_count = register_index; - - return length; } /* parser_compute_indicies */ /** - * Encode a literal argument. - * - * @return position after the encoded values + * Initialize literal pool. */ -static inline uint8_t * -parser_encode_literal (uint8_t *dst_p, /**< destination buffer */ - uint16_t literal_index, /**< literal index */ - uint16_t literal_one_byte_limit) /**< maximum value of a literal - * encoded in one byte */ -{ - if (literal_index <= literal_one_byte_limit) - { - *dst_p++ = (uint8_t) (literal_index); - } - else - { - if (literal_one_byte_limit == CBC_MAXIMUM_BYTE_VALUE - 1) - { - *dst_p++ = (uint8_t) (CBC_MAXIMUM_BYTE_VALUE); - *dst_p++ = (uint8_t) (literal_index - CBC_MAXIMUM_BYTE_VALUE); - } - else - { - *dst_p++ = (uint8_t) ((literal_index >> 8) | CBC_HIGHEST_BIT_MASK); - *dst_p++ = (uint8_t) (literal_index & CBC_MAXIMUM_BYTE_VALUE); - } - } - return dst_p; -} /* parser_encode_literal */ - -/** - * Generate initializer byte codes. - * - * @return the end of the initializer stream - */ -static uint8_t * -parser_generate_initializers (parser_context_t *context_p, /**< context */ - uint8_t *dst_p, /**< destination buffer */ - ecma_value_t *literal_pool_p, /**< start of literal pool */ - uint16_t uninitialized_var_end, /**< end of the uninitialized var group */ - uint16_t initialized_var_end, /**< end of the initialized var group */ - uint16_t literal_one_byte_limit) /**< maximum value of a literal - * encoded in one byte */ +static void +parser_init_literal_pool (parser_context_t *context_p, /**< context */ + ecma_value_t *literal_pool_p) /**< start of literal pool */ { parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; - uint16_t argument_count, register_count; - - if (uninitialized_var_end > context_p->register_count) - { - *dst_p++ = CBC_DEFINE_VARS; - dst_p = parser_encode_literal (dst_p, - (uint16_t) (uninitialized_var_end - 1), - literal_one_byte_limit); - } - - if (context_p->status_flags & PARSER_HAS_INITIALIZED_VARS) - { - const uint8_t expected_status_flags = LEXER_FLAG_VAR | LEXER_FLAG_NO_REG_STORE | LEXER_FLAG_INITIALIZED; -#ifndef JERRY_NDEBUG - uint16_t next_index = uninitialized_var_end; -#endif /* !JERRY_NDEBUG */ - - *dst_p++ = CBC_INITIALIZE_VARS; - dst_p = parser_encode_literal (dst_p, - (uint16_t) uninitialized_var_end, - literal_one_byte_limit); - dst_p = parser_encode_literal (dst_p, - (uint16_t) (initialized_var_end - 1), - literal_one_byte_limit); - - parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); - argument_count = 0; - - while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) - { - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - argument_count++; - } - - if ((literal_p->status_flags & expected_status_flags) == expected_status_flags) - { - uint16_t init_index; - - JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL); -#ifndef JERRY_NDEBUG - JERRY_ASSERT (literal_p->prop.index == next_index); - next_index++; -#endif /* !JERRY_NDEBUG */ - literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED); - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - init_index = (uint16_t) (argument_count - 1); - } - else - { - literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); - - JERRY_ASSERT (literal_p != NULL - && literal_p->type == LEXER_FUNCTION_LITERAL); - init_index = literal_p->prop.index; - } - - dst_p = parser_encode_literal (dst_p, init_index, literal_one_byte_limit); - } - } - -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) - { - JERRY_ASSERT ((argument_count - 1) == context_p->argument_count); - } - else - { -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - JERRY_ASSERT (argument_count == context_p->argument_count); -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - } parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); - argument_count = 0; - register_count = context_p->register_count; while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) { - const uint8_t expected_status_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED; - - if (literal_p->type != LEXER_UNUSED_LITERAL) + switch (literal_p->type) { - if (literal_p->type == LEXER_IDENT_LITERAL - || literal_p->type == LEXER_STRING_LITERAL) + case LEXER_IDENT_LITERAL: { - if (literal_p->prop.index >= register_count) + if (!(literal_p->status_flags & LEXER_FLAG_USED)) { - if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) - { - ecma_value_t lit_value; -#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - lit_value = ecma_find_or_create_literal_string (literal_p->u.char_p, - literal_p->prop.length); -#else /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - lit_value = literal_p->u.value; -#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - literal_pool_p[literal_p->prop.index] = lit_value; - } + break; } + /* FALLTHRU */ + } + case LEXER_STRING_LITERAL: + { + ecma_value_t lit_value; +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + lit_value = ecma_find_or_create_literal_string (literal_p->u.char_p, + literal_p->prop.length); +#else /* !ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + lit_value = literal_p->u.value; +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + + JERRY_ASSERT (literal_p->prop.index >= context_p->register_count); + literal_pool_p[literal_p->prop.index] = lit_value; #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (!context_p->is_show_opcodes @@ -651,76 +245,32 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + break; } - else if ((literal_p->type == LEXER_FUNCTION_LITERAL) - || (literal_p->type == LEXER_REGEXP_LITERAL)) + case LEXER_NUMBER_LITERAL: { - JERRY_ASSERT (literal_p->prop.index >= register_count); + JERRY_ASSERT (literal_p->prop.index >= context_p->register_count); + + literal_pool_p[literal_p->prop.index] = literal_p->u.value; + break; + } + case LEXER_FUNCTION_LITERAL: + case LEXER_REGEXP_LITERAL: + { + JERRY_ASSERT (literal_p->prop.index >= context_p->register_count); ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[literal_p->prop.index], literal_p->u.bytecode_p); + break; } - else + default: { - JERRY_ASSERT (literal_p->type == LEXER_NUMBER_LITERAL - && literal_p->prop.index >= register_count); - - literal_pool_p[literal_p->prop.index] = literal_p->u.value; + JERRY_ASSERT (literal_p->type == LEXER_UNUSED_LITERAL); + break; } } - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - argument_count++; - } - - if ((literal_p->status_flags & expected_status_flags) == expected_status_flags) - { - uint16_t index = literal_p->prop.index; - uint16_t init_index; - - JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL); - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) - { - init_index = (uint16_t) (argument_count - 1); - - if (init_index == literal_p->prop.index) - { - continue; - } - } - else - { - literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); - - JERRY_ASSERT (literal_p != NULL - && literal_p->type == LEXER_FUNCTION_LITERAL); - - init_index = literal_p->prop.index; - JERRY_ASSERT (init_index >= register_count); - - ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[init_index], - literal_p->u.bytecode_p); - } - - *dst_p++ = CBC_INITIALIZE_VAR; - dst_p = parser_encode_literal (dst_p, index, literal_one_byte_limit); - dst_p = parser_encode_literal (dst_p, init_index, literal_one_byte_limit); - } } - -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) - { - JERRY_ASSERT ((argument_count - 1) == context_p->argument_count); - return dst_p; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - - JERRY_ASSERT (argument_count == context_p->argument_count); - return dst_p; -} /* parser_generate_initializers */ +} /* parser_init_literal_pool */ /* * During byte code post processing certain bytes are not @@ -973,7 +523,6 @@ parse_print_literal (ecma_compiled_code_t *compiled_code_p, /**< compiled code * uint16_t argument_end; uint16_t register_end; uint16_t ident_end; - uint16_t const_literal_end; if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { @@ -981,7 +530,6 @@ parse_print_literal (ecma_compiled_code_t *compiled_code_p, /**< compiled code * argument_end = args_p->argument_end; register_end = args_p->register_end; ident_end = args_p->ident_end; - const_literal_end = args_p->const_literal_end; } else { @@ -989,15 +537,26 @@ parse_print_literal (ecma_compiled_code_t *compiled_code_p, /**< compiled code * argument_end = args_p->argument_end; register_end = args_p->register_end; ident_end = args_p->ident_end; - const_literal_end = args_p->const_literal_end; } -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (compiled_code_p->status_flags & CBC_CODE_FLAGS_REST_PARAMETER) { argument_end++; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ + + if (literal_index < argument_end) + { + JERRY_DEBUG_MSG (" arg:%d", literal_index); + return; + } + + if (literal_index < register_end) + { + JERRY_DEBUG_MSG (" reg:%d", literal_index); + return; + } parser_list_iterator_init (literal_pool_p, &literal_iterator); @@ -1005,40 +564,17 @@ parse_print_literal (ecma_compiled_code_t *compiled_code_p, /**< compiled code * { lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); - if (literal_p == NULL) + JERRY_ASSERT (literal_p != NULL); + + if (literal_p->prop.index == literal_index) { - if (literal_index == const_literal_end) + if (literal_index < ident_end) { - JERRY_DEBUG_MSG (" idx:%d(self)->function", literal_index); - break; - } - - JERRY_ASSERT (literal_index < argument_end); - JERRY_DEBUG_MSG (" idx:%d(arg)->undefined", literal_index); - break; - } - - if (literal_p->prop.index == literal_index - && literal_p->type != LEXER_UNUSED_LITERAL - && !(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) - { - JERRY_DEBUG_MSG (" idx:%d", literal_index); - - if (literal_index < argument_end) - { - JERRY_DEBUG_MSG ("(arg)->"); - } - else if (literal_index < register_end) - { - JERRY_DEBUG_MSG ("(reg)->"); - } - else if (literal_index < ident_end) - { - JERRY_DEBUG_MSG ("(ident)->"); + JERRY_DEBUG_MSG (" ident:%d->", literal_index); } else { - JERRY_DEBUG_MSG ("(lit)->"); + JERRY_DEBUG_MSG (" lit:%d->", literal_index); } util_print_literal (literal_p); @@ -1055,85 +591,6 @@ parse_print_literal (ecma_compiled_code_t *compiled_code_p, /**< compiled code * byte_code_p++; \ } -/** - * Print CBC_DEFINE_VARS instruction. - * - * @return next byte code position - */ -static uint8_t * -parse_print_define_vars (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ - uint8_t *byte_code_p, /**< byte code position */ - uint16_t encoding_limit, /**< literal encoding limit */ - uint16_t encoding_delta, /**< literal encoding delta */ - parser_list_t *literal_pool_p) /**< literal pool */ -{ - uint16_t identifier_index; - uint16_t identifier_end; - - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) - { - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) compiled_code_p; - identifier_index = args_p->register_end; - } - else - { - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) compiled_code_p; - identifier_index = args_p->register_end; - } - - PARSER_READ_IDENTIFIER_INDEX (identifier_end); - - JERRY_DEBUG_MSG (" from: %d to: %d\n", identifier_index, identifier_end); - - while (identifier_index <= identifier_end) - { - JERRY_DEBUG_MSG (" "); - parse_print_literal (compiled_code_p, identifier_index, literal_pool_p); - identifier_index++; - JERRY_DEBUG_MSG ("\n"); - } - - return byte_code_p; -} /* parse_print_define_vars */ - -/** - * Print CBC_INITIALIZE_VARS instruction. - * - * @return next byte code position - */ -static uint8_t * -parse_print_initialize_vars (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ - uint8_t *byte_code_p, /**< byte code position */ - uint16_t encoding_limit, /**< literal encoding limit */ - uint16_t encoding_delta, /**< literal encoding delta */ - parser_list_t *literal_pool_p) /**< literal pool */ -{ - uint16_t identifier_index; - uint16_t identifier_end; - - PARSER_READ_IDENTIFIER_INDEX (identifier_index); - PARSER_READ_IDENTIFIER_INDEX (identifier_end); - - JERRY_DEBUG_MSG (" from: %d to: %d\n", identifier_index, identifier_end); - - while (identifier_index <= identifier_end) - { - uint16_t literal_index; - - JERRY_DEBUG_MSG (" "); - parse_print_literal (compiled_code_p, identifier_index, literal_pool_p); - JERRY_DEBUG_MSG (" ="); - - PARSER_READ_IDENTIFIER_INDEX (literal_index); - - parse_print_literal (compiled_code_p, literal_index, literal_pool_p); - identifier_index++; - JERRY_DEBUG_MSG ("\n"); - } - - return byte_code_p; -} /* parse_print_initialize_vars */ - /** * Print byte code. */ @@ -1202,9 +659,14 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",strict_mode"); } - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { - JERRY_DEBUG_MSG (",arguments_needed"); + JERRY_DEBUG_MSG (",mapped_arguments_needed"); + } + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED) + { + JERRY_DEBUG_MSG (",unmapped_arguments_needed"); } if (compiled_code_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) @@ -1212,19 +674,22 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",no_lexical_env"); } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) if (compiled_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { JERRY_DEBUG_MSG (",arrow"); } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) { JERRY_DEBUG_MSG (",constructor"); } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + { + JERRY_DEBUG_MSG (",generator"); + } +#endif /* ENABLED (JERRY_ES2015) */ JERRY_DEBUG_MSG ("]\n"); @@ -1261,26 +726,6 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code flags = cbc_flags[opcode]; JERRY_DEBUG_MSG (" %3d : %s", (int) cbc_offset, cbc_names[opcode]); byte_code_p++; - - if (opcode == CBC_INITIALIZE_VARS) - { - byte_code_p = parse_print_initialize_vars (compiled_code_p, - byte_code_p, - encoding_limit, - encoding_delta, - literal_pool_p); - continue; - } - - if (opcode == CBC_DEFINE_VARS) - { - byte_code_p = parse_print_define_vars (compiled_code_p, - byte_code_p, - encoding_limit, - encoding_delta, - literal_pool_p); - continue; - } } else { @@ -1459,8 +904,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { uint16_t literal_one_byte_limit; uint16_t ident_end; - uint16_t uninitialized_var_end; - uint16_t initialized_var_end; uint16_t const_literal_end; parser_mem_page_t *page_p; parser_mem_page_t *last_page_p; @@ -1472,7 +915,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_SNAPSHOT_SAVE) size_t total_size_used; #endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */ - size_t initializers_length; uint8_t real_offset; uint8_t *byte_code_p; bool needs_uint16_arguments; @@ -1483,6 +925,30 @@ parser_post_processing (parser_context_t *context_p) /**< context */ CHECK_JERRY_STACK_USAGE(context_p); +#if ENABLED (JERRY_ES2015) + if ((context_p->status_flags & (PARSER_IS_FUNCTION | PARSER_LEXICAL_BLOCK_NEEDED)) + == (PARSER_IS_FUNCTION | PARSER_LEXICAL_BLOCK_NEEDED)) + { + PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#ifndef JERRY_NDEBUG + PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#endif /* !JERRY_NDEBUG */ + + context_p->status_flags &= (uint32_t) ~PARSER_LEXICAL_BLOCK_NEEDED; + + parser_emit_cbc (context_p, CBC_CONTEXT_END); + + parser_branch_t branch; + parser_stack_pop (context_p, &branch, sizeof (parser_branch_t)); + parser_set_branch_to_current_position (context_p, &branch); + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (context_p->stack_depth == 0); +#ifndef JERRY_NDEBUG + JERRY_ASSERT (context_p->context_stack_depth == 0); +#endif /* !JERRY_NDEBUG */ + if ((size_t) context_p->stack_limit + (size_t) context_p->register_count > PARSER_MAXIMUM_STACK_LIMIT) { parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED); @@ -1511,14 +977,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ - parser_copy_identifiers (context_p); - - initializers_length = parser_compute_indicies (context_p, - &ident_end, - &uninitialized_var_end, - &initialized_var_end, - &const_literal_end); - length = initializers_length; + parser_compute_indicies (context_p, &ident_end, &const_literal_end); if (context_p->literal_count <= CBC_MAXIMUM_SMALL_VALUE) { @@ -1540,6 +999,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ page_p = context_p->byte_code.first_p; offset = 0; + length = 0; while (page_p != last_page_p || offset < last_position) { @@ -1564,12 +1024,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */ PARSER_NEXT_BYTE (page_p, offset); length++; -#if ENABLED (JERRY_ES2015_CLASS) - if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN) +#if ENABLED (JERRY_ES2015) + if (ext_opcode == CBC_EXT_RETURN_PROMISE + || ext_opcode == CBC_EXT_RETURN_PROMISE_UNDEFINED) { last_opcode = CBC_RETURN; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_LINE_INFO) if (ext_opcode == CBC_EXT_LINE) @@ -1592,43 +1053,40 @@ parser_post_processing (parser_context_t *context_p) /**< context */ while (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) { uint8_t *first_byte = page_p->bytes + offset; - size_t literal_index = *first_byte; - lexer_literal_t *literal_p; + uint32_t literal_index = *first_byte; PARSER_NEXT_BYTE (page_p, offset); length++; - literal_index |= ((size_t) page_p->bytes[offset]) << 8; - literal_p = PARSER_GET_LITERAL (literal_index); + literal_index |= ((uint32_t) page_p->bytes[offset]) << 8; - if (literal_p->type == LEXER_UNUSED_LITERAL) + if (literal_index >= PARSER_REGISTER_START) { - /* In a few cases uninitialized literals may have been converted to initialized - * literals later. Byte code references to the old (uninitialized) literals - * must be redirected to the new instance of the literal. */ - literal_p = PARSER_GET_LITERAL (literal_p->prop.index); - - JERRY_ASSERT (literal_p != NULL && literal_p->type != LEXER_UNUSED_LITERAL); + literal_index -= PARSER_REGISTER_START; + } + else + { + literal_index = (PARSER_GET_LITERAL (literal_index))->prop.index; } - if (literal_p->prop.index <= literal_one_byte_limit) + if (literal_index <= literal_one_byte_limit) { - *first_byte = (uint8_t) literal_p->prop.index; + *first_byte = (uint8_t) literal_index; } else { if (context_p->literal_count <= CBC_MAXIMUM_SMALL_VALUE) { - JERRY_ASSERT (literal_p->prop.index <= CBC_MAXIMUM_SMALL_VALUE); + JERRY_ASSERT (literal_index <= CBC_MAXIMUM_SMALL_VALUE); *first_byte = CBC_MAXIMUM_BYTE_VALUE; - page_p->bytes[offset] = (uint8_t) (literal_p->prop.index - CBC_MAXIMUM_BYTE_VALUE); + page_p->bytes[offset] = (uint8_t) (literal_index - CBC_MAXIMUM_BYTE_VALUE); length++; } else { - JERRY_ASSERT (literal_p->prop.index <= CBC_MAXIMUM_FULL_VALUE); - *first_byte = (uint8_t) ((literal_p->prop.index >> 8) | CBC_HIGHEST_BIT_MASK); - page_p->bytes[offset] = (uint8_t) (literal_p->prop.index & 0xff); + JERRY_ASSERT (literal_index <= CBC_MAXIMUM_FULL_VALUE); + *first_byte = (uint8_t) ((literal_index >> 8) | CBC_HIGHEST_BIT_MASK); + page_p->bytes[offset] = (uint8_t) (literal_index & 0xff); length++; } } @@ -1661,11 +1119,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (flags & CBC_HAS_BRANCH_ARG) { bool prefix_zero = true; -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 - cbc_opcode_t jump_forward = CBC_JUMP_FORWARD_2; -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ - cbc_opcode_t jump_forward = CBC_JUMP_FORWARD_3; -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ /* The leading zeroes are dropped from the stream. * Although dropping these zeroes for backward @@ -1688,9 +1141,9 @@ parser_post_processing (parser_context_t *context_p) /**< context */ PARSER_NEXT_BYTE (page_p, offset); } - if (last_opcode == jump_forward + if (last_opcode == (cbc_opcode_t) (CBC_JUMP_FORWARD + PARSER_MAX_BRANCH_LENGTH - 1) && prefix_zero - && page_p->bytes[offset] == CBC_BRANCH_OFFSET_LENGTH (jump_forward) + 1) + && page_p->bytes[offset] == PARSER_MAX_BRANCH_LENGTH + 1) { /* Uncoditional jumps which jump right after the instruction * are effectively NOPs. These jumps are removed from the @@ -1714,6 +1167,14 @@ parser_post_processing (parser_context_t *context_p) /**< context */ || !(PARSER_OPCODE_IS_RETURN (last_opcode))) { context_p->status_flags &= (uint32_t) ~PARSER_NO_END_LABEL; + +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + length++; + } +#endif /* ENABLED (JERRY_ES2015) */ + length++; } @@ -1732,18 +1193,24 @@ parser_post_processing (parser_context_t *context_p) /**< context */ total_size += literal_length + length; - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { total_size += context_p->argument_count * sizeof (ecma_value_t); } -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_ES2015) + if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + total_size += sizeof (ecma_value_t); + } +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) { total_size += sizeof (ecma_value_t); } -#endif /* ENABLED (JERRY_LINE_INFO) */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #if ENABLED (JERRY_SNAPSHOT_SAVE) total_size_used = total_size; @@ -1769,13 +1236,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */ compiled_code_p->refs = 1; compiled_code_p->status_flags = CBC_CODE_FLAGS_FUNCTION; -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) { JERRY_ASSERT (context_p->argument_count > 0); context_p->argument_count--; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (needs_uint16_arguments) { @@ -1827,10 +1294,17 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->status_flags & PARSER_ARGUMENTS_NEEDED) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARGUMENTS_NEEDED; + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED; + } + else + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED; + } /* Arguments is stored in the lexical environment. */ - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + JERRY_ASSERT (context_p->status_flags & PARSER_LEXICAL_ENV_NEEDED); } if (!(context_p->status_flags & PARSER_LEXICAL_ENV_NEEDED)) @@ -1838,39 +1312,49 @@ parser_post_processing (parser_context_t *context_p) /**< context */ compiled_code_p->status_flags |= CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED; } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & (PARSER_IS_PROPERTY_GETTER | PARSER_IS_PROPERTY_SETTER)) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_ACCESSOR; + } + if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION) { compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARROW_FUNCTION; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR; + compiled_code_p->status_flags |= CBC_CODE_FLAGS_CLASS_CONSTRUCTOR; + } + + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_GENERATOR; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) { compiled_code_p->status_flags |= CBC_CODE_FLAGS_REST_PARAMETER; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - literal_pool_p = (ecma_value_t *) byte_code_p; - literal_pool_p -= context_p->register_count; + if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + compiled_code_p->status_flags |= CBC_CODE_FLAG_HAS_TAGGED_LITERALS; + } + + if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) + { + JERRY_ASSERT (!(context_p->status_flags & PARSER_IS_FUNCTION)); + compiled_code_p->status_flags |= CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED; + } +#endif /* ENABLED (JERRY_ES2015) */ + + literal_pool_p = ((ecma_value_t *) byte_code_p) - context_p->register_count; byte_code_p += literal_length; + dst_p = byte_code_p; - dst_p = parser_generate_initializers (context_p, - byte_code_p, - literal_pool_p, - uninitialized_var_end, - initialized_var_end, - literal_one_byte_limit); - - JERRY_ASSERT (dst_p == byte_code_p + initializers_length); + parser_init_literal_pool (context_p, literal_pool_p); page_p = context_p->byte_code.first_p; offset = 0; @@ -1894,11 +1378,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (opcode == CBC_JUMP_FORWARD) { /* These opcodes are deleted from the stream. */ -#if PARSER_MAXIMUM_CODE_SIZE <= 65535 - size_t counter = 3; -#else /* PARSER_MAXIMUM_CODE_SIZE > 65535 */ - size_t counter = 4; -#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */ + size_t counter = PARSER_MAX_BRANCH_LENGTH + 1; do { @@ -2058,11 +1538,19 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (!(context_p->status_flags & PARSER_NO_END_LABEL)) { *dst_p++ = CBC_RETURN_WITH_BLOCK; + +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + dst_p[-1] = CBC_EXT_OPCODE; + dst_p[0] = CBC_EXT_RETURN_PROMISE_UNDEFINED; + dst_p++; + } +#endif /* ENABLED (JERRY_ES2015) */ } JERRY_ASSERT (dst_p == byte_code_p + length); - parse_update_branches (context_p, - byte_code_p + initializers_length); + parse_update_branches (context_p, byte_code_p); parser_cbc_stream_free (&context_p->byte_code); @@ -2109,8 +1597,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { parser_list_iterator_t literal_iterator; uint16_t argument_count = 0; @@ -2134,20 +1621,12 @@ parser_post_processing (parser_context_t *context_p) /**< context */ /* All arguments must be moved to initialized registers. */ if (literal_p->type == LEXER_UNUSED_LITERAL) { - if (literal_p->u.char_p == NULL) - { - argument_base_p[argument_count] = ECMA_VALUE_EMPTY; - argument_count++; - continue; - } - - literal_p = PARSER_GET_LITERAL (literal_p->prop.index); - - JERRY_ASSERT (literal_p != NULL); + argument_base_p[argument_count] = ECMA_VALUE_EMPTY; + argument_count++; + continue; } - JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL - && (literal_p->status_flags & LEXER_FLAG_VAR)); + JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL); JERRY_ASSERT (literal_p->prop.index >= register_count); @@ -2156,20 +1635,48 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } } -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_ES2015) + if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + ecma_value_t *tagged_base_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); + + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) + { + tagged_base_p -= context_p->argument_count; + } + + tagged_base_p[-1] = (ecma_value_t) context_p->tagged_template_literal_cp; + + ecma_collection_t *collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + context_p->tagged_template_literal_cp); + + for (uint32_t i = 0; i < collection_p->item_count; i++) + { + ecma_free_value (collection_p->buffer_p[i]); + } + } +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) { ecma_value_t *resource_name_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { resource_name_p -= context_p->argument_count; } +#if ENABLED (JERRY_ES2015) + if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + resource_name_p--; + } +#endif /* ENABLED (JERRY_ES2015) */ + resource_name_p[-1] = JERRY_CONTEXT (resource_name); } -#endif /* ENABLED (JERRY_LINE_INFO) */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) @@ -2209,37 +1716,118 @@ static void parser_parse_function_arguments (parser_context_t *context_p, /**< context */ lexer_token_type_t end_type) /**< expected end type */ { -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - bool duplicated_argument_names = false; - bool initializer_found = false; -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (context_p->status_flags & PARSER_IS_FUNCTION); + JERRY_ASSERT (!(context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED)); + + bool has_duplicated_arg_names = false; + + /* TODO: Currently async iterators are not supported, so generators ignore the async modifier. */ + uint32_t mask = (PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + if ((context_p->status_flags & mask) == mask) + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_ASYNC_FUNCTION; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type == end_type) { +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR); + parser_emit_cbc (context_p, CBC_POP); + } + + context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_AWAIT_YIELD; +#endif /* ENABLED (JERRY_ES2015) */ + scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); return; } +#if ENABLED (JERRY_ES2015) + bool has_mapped_arguments = (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) != 0; +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_ARGS); + scanner_set_active (context_p); + +#if ENABLED (JERRY_ES2015) + context_p->status_flags |= PARSER_FUNCTION_IS_PARSING_ARGS; +#endif /* ENABLED (JERRY_ES2015) */ + while (true) { - uint16_t literal_count = context_p->literal_count; - -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) { parser_raise_error (context_p, PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER); } else if (context_p->token.type == LEXER_THREE_DOTS) { - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); + if (context_p->status_flags & PARSER_IS_PROPERTY_SETTER) + { + parser_raise_error (context_p, PARSER_ERR_SETTER_REST_PARAMETER); + } + lexer_next_token (context_p); - if (context_p->literal_count == literal_count) + if (has_duplicated_arg_names) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - context_p->status_flags |= PARSER_FUNCTION_HAS_REST_PARAM; + context_p->status_flags |= PARSER_FUNCTION_HAS_REST_PARAM | PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ + + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + if (has_duplicated_arg_names) + { + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); + } + + context_p->status_flags |= PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; + + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count)); + + uint32_t flags = (PARSER_PATTERN_BINDING + | PARSER_PATTERN_TARGET_ON_STACK + | PARSER_PATTERN_LOCAL + | PARSER_PATTERN_ARGUMENTS); + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + + if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) + { + parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); + } + + flags |= PARSER_PATTERN_TARGET_DEFAULT; + } + + parser_parse_initializer (context_p, flags); + + context_p->argument_count++; + if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); + } + + if (context_p->token.type != LEXER_COMMA) + { + break; + } + + lexer_next_token (context_p); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) @@ -2251,106 +1839,99 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ &context_p->token.lit_location, LEXER_IDENT_LITERAL); - if (literal_count == context_p->literal_count - || context_p->token.literal_is_reserved - || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) + if (context_p->token.keyword_type >= LEXER_FIRST_NON_STRICT_ARGUMENTS) { context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG; } - if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS) + CHECK_JERRY_STACK_USAGE(context_p); + + if (JERRY_UNLIKELY (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) { - uint8_t literal_status_flags = context_p->lit_object.literal_p->status_flags; - - literal_status_flags = (uint8_t) (literal_status_flags & ~LEXER_FLAG_NO_REG_STORE); - context_p->lit_object.literal_p->status_flags = literal_status_flags; - - context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED; - context_p->status_flags &= (uint32_t) ~(PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NEEDED); - } - - if (context_p->literal_count == literal_count) - { - lexer_literal_t *literal_p; - -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - if (initializer_found && (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) +#if ENABLED (JERRY_ES2015) + if ((context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM) + || (context_p->status_flags & PARSER_IS_ARROW_FUNCTION)) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - duplicated_argument_names = true; -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ + has_duplicated_arg_names = true; +#endif /* ENABLED (JERRY_ES2015) */ - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } - - CHECK_JERRY_STACK_USAGE(context_p); - - literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - *literal_p = *context_p->lit_object.literal_p; - - literal_p->status_flags &= LEXER_FLAG_SOURCE_PTR; - literal_p->status_flags |= LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT; - - context_p->literal_count++; - - /* There cannot be references from the byte code to these literals - * since no byte code has been emitted yet. Therefore there is no - * need to set the index field. */ - context_p->lit_object.literal_p->type = LEXER_UNUSED_LITERAL; -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - context_p->lit_object.literal_p->prop.index = context_p->literal_count; -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - - /* Only the LEXER_FLAG_FUNCTION_ARGUMENT flag is kept. */ - context_p->lit_object.literal_p->status_flags &= LEXER_FLAG_FUNCTION_ARGUMENT; - context_p->lit_object.literal_p->u.char_p = NULL; + context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG; } else { - uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT; - context_p->lit_object.literal_p->status_flags |= lexer_flags; - } - - context_p->argument_count++; - if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) - { - parser_raise_error (context_p, PARSER_ERR_REGISTER_LIMIT_REACHED); + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; } lexer_next_token (context_p); -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) +#if ENABLED (JERRY_ES2015) + uint16_t literal_index = context_p->lit_object.index; + if (context_p->token.type == LEXER_ASSIGN) { -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) + JERRY_ASSERT (!has_mapped_arguments); + if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) { parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ parser_branch_t skip_init; - if (duplicated_argument_names) + if (has_duplicated_arg_names) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - initializer_found = true; + + context_p->status_flags |= PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; /* LEXER_ASSIGN does not overwrite lit_object. */ - parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); - parser_emit_cbc_literal (context_p, CBC_STRICT_EQUAL_RIGHT_LITERAL, context_p->lit_object.index); - parser_emit_cbc_forward_branch (context_p, CBC_BRANCH_IF_FALSE_FORWARD, &skip_init); + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count)); + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); - parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); - parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_set_branch_to_current_position (context_p, &skip_init); + + uint16_t opcode = CBC_ASSIGN_LET_CONST; + + if (literal_index >= PARSER_REGISTER_START) + { + opcode = CBC_ASSIGN_SET_IDENT; + } + else if (!scanner_literal_is_created (context_p, literal_index)) + { + opcode = CBC_INIT_ARG_OR_CATCH; + } + + parser_emit_cbc_literal (context_p, opcode, literal_index); + } + else if (!has_mapped_arguments && literal_index < PARSER_REGISTER_START) + { + uint16_t opcode = CBC_INIT_ARG_OR_FUNC; + + if (scanner_literal_is_created (context_p, literal_index)) + { + opcode = CBC_ASSIGN_LET_CONST_LITERAL; + } + + parser_emit_cbc_literal_value (context_p, + opcode, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count), + literal_index); + } +#endif /* ENABLED (JERRY_ES2015) */ + + context_p->argument_count++; + if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ if (context_p->token.type != LEXER_COMMA) { @@ -2368,9 +1949,49 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, error); } - context_p->register_count = context_p->argument_count; + scanner_revert_active (context_p); + +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (!has_mapped_arguments || !(context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM)); + + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR); + parser_emit_cbc (context_p, CBC_POP); + } + + if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) + { + if ((context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_LEXICAL_ENV_NEEDED) + || scanner_is_context_needed (context_p, PARSER_CHECK_FUNCTION_CONTEXT)) + { + context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + + parser_branch_t branch; + parser_emit_cbc_forward_branch (context_p, CBC_BLOCK_CREATE_CONTEXT, &branch); + parser_stack_push (context_p, &branch, sizeof (parser_branch_t)); + +#ifndef JERRY_NDEBUG + context_p->context_stack_depth = PARSER_BLOCK_CONTEXT_STACK_ALLOCATION; +#endif /* !JERRY_NDEBUG */ + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_LEXICAL_BLOCK_NEEDED; + } + } + + context_p->status_flags &= (uint32_t) ~(PARSER_DISALLOW_AWAIT_YIELD | PARSER_FUNCTION_IS_PARSING_ARGS); +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_BODY); } /* parser_parse_function_arguments */ +#ifndef JERRY_NDEBUG +JERRY_STATIC_ASSERT (PARSER_SCANNING_SUCCESSFUL == PARSER_HAS_LATE_LIT_INIT, + parser_scanning_successful_should_share_the_bit_position_with_parser_has_late_lit_init); +#endif /* !JERRY_NDEBUG */ + /** * Parse and compile EcmaScript source code * @@ -2390,48 +2011,35 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ ecma_compiled_code_t *compiled_code_p; context.error = PARSER_ERR_NO_ERROR; - context.allocated_buffer_p = NULL; if (error_location_p != NULL) { error_location_p->error = PARSER_ERR_NO_ERROR; } - if (arg_list_p == NULL) + context.status_flags = parse_opts & PARSER_STRICT_MODE_MASK; + context.global_status_flags = parse_opts; + + if (arg_list_p != NULL) { - context.status_flags = PARSER_NO_REG_STORE | PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NOT_NEEDED; - } - else - { - context.status_flags = PARSER_IS_FUNCTION; -#if ENABLED (JERRY_DEBUGGER) - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + context.status_flags |= PARSER_IS_FUNCTION; +#if ENABLED (JERRY_ES2015) + if (parse_opts & ECMA_PARSE_GENERATOR_FUNCTION) { - /* This option has a high memory and performance costs, - * but it is necessary for executing eval operations by the debugger. */ - context.status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; + context.status_flags |= PARSER_IS_GENERATOR_FUNCTION; } -#endif /* ENABLED (JERRY_DEBUGGER) */ +#endif /* ENABLED (JERRY_ES2015) */ } -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (parse_opts & ECMA_PARSE_EVAL) - { - context.status_flags |= PARSER_IS_EVAL; - } - - context.module_current_node_p = NULL; -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - -#if ENABLED (JERRY_ES2015_CLASS) - context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015) + context.status_flags |= PARSER_RESTORE_STATUS_FLAGS (parse_opts); + context.tagged_template_literal_cp = JMEM_CP_NULL; +#endif /* ENABLED (JERRY_ES2015) */ context.stack_depth = 0; context.stack_limit = 0; context.last_context_p = NULL; context.last_statement.current_p = NULL; - context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK; context.token.flags = 0; context.line = 1; @@ -2457,6 +2065,14 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ parser_list_init (&context.literal_pool, sizeof (lexer_literal_t), (uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_literal_t))); + context.scope_stack_p = NULL; + context.scope_stack_size = 0; + context.scope_stack_top = 0; + context.scope_stack_reg_top = 0; +#if ENABLED (JERRY_ES2015) + context.scope_stack_global_end = 0; + context.tagged_template_literal_cp = JMEM_CP_NULL; +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG context.context_stack_depth = 0; @@ -2504,8 +2120,10 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.source_end_p = arg_list_p + arg_list_size; } + context.u.allocated_buffer_p = NULL; context.line = 1; context.column = 1; + context.token.flags = 0; parser_stack_init (&context); @@ -2513,6 +2131,15 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.breakpoint_info_count = 0; #endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (context.global_status_flags & ECMA_PARSE_MODULE) + { + context.status_flags |= PARSER_IS_STRICT; + } + + context.module_current_node_p = NULL; +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + PARSER_TRY (context.try_buffer) { /* Pushing a dummy value ensures the stack is never empty. @@ -2537,27 +2164,58 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ lexer_next_token (&context); } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + else if (parse_opts & ECMA_PARSE_MODULE) + { + scanner_create_variables (&context, SCANNER_CREATE_VARS_NO_OPTS); + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + else + { + JERRY_ASSERT (context.next_scanner_info_p->source_p == source_p + && context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + +#if ENABLED (JERRY_ES2015) + if (scanner_is_context_needed (&context, PARSER_CHECK_GLOBAL_CONTEXT)) + { + context.status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; + } + + if ((parse_opts & ECMA_PARSE_EVAL) == 0) + { + scanner_check_variables (&context); + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_create_variables (&context, SCANNER_CREATE_VARS_IS_SCRIPT); + } parser_parse_statements (&context); - /* When the parsing is successful, only the - * dummy value can be remained on the stack. */ + JERRY_ASSERT (context.last_statement.current_p == NULL); + + JERRY_ASSERT (context.last_cbc_opcode == PARSER_CBC_UNAVAILABLE); + JERRY_ASSERT (context.u.allocated_buffer_p == NULL); + +#ifndef JERRY_NDEBUG + JERRY_ASSERT (context.status_flags & PARSER_SCANNING_SUCCESSFUL); + JERRY_ASSERT (!(context.global_status_flags & ECMA_PARSE_INTERNAL_FOR_IN_OFF_CONTEXT_ERROR)); + context.status_flags &= (uint32_t) ~PARSER_SCANNING_SUCCESSFUL; +#endif /* !JERRY_NDEBUG */ + + JERRY_ASSERT (!(context.status_flags & PARSER_HAS_LATE_LIT_INIT)); + + compiled_code_p = parser_post_processing (&context); + parser_list_free (&context.literal_pool); + + /* When parsing is successful, only the dummy value can be remained on the stack. */ JERRY_ASSERT (context.stack_top_uint8 == CBC_MAXIMUM_BYTE_VALUE && context.stack.last_position == 1 && context.stack.first_p != NULL && context.stack.first_p->next_p == NULL && context.stack.last_p == NULL); - JERRY_ASSERT (context.last_statement.current_p == NULL); - JERRY_ASSERT (context.last_cbc_opcode == PARSER_CBC_UNAVAILABLE); - JERRY_ASSERT (context.allocated_buffer_p == NULL); - - compiled_code_p = parser_post_processing (&context); - parser_list_free (&context.literal_pool); - -#ifndef JERRY_NDEBUG - JERRY_ASSERT (context.status_flags & PARSER_SCANNING_SUCCESSFUL); -#endif /* !JERRY_NDEBUG */ + JERRY_ASSERT (arg_list_p != NULL || !(context.status_flags & PARSER_ARGUMENTS_NEEDED)); #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context.is_show_opcodes) @@ -2576,11 +2234,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ parser_free_jumps (context.last_statement); } - if (context.allocated_buffer_p != NULL) - { - parser_free_local (context.allocated_buffer_p, - context.allocated_buffer_size); - } + parser_free_allocated_buffer (&context); scanner_cleanup (&context); @@ -2604,6 +2258,11 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ } PARSER_TRY_END + if (context.scope_stack_p != NULL) + { + parser_free (context.scope_stack_p, context.scope_stack_size * sizeof (parser_scope_stack_t)); + } + #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context.is_show_opcodes) { @@ -2636,6 +2295,13 @@ parser_save_context (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS) + { + context_p->status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; + } +#endif /* ENABLED (JERRY_ES2015) */ + /* Save private part of the context. */ saved_context_p->status_flags = context_p->status_flags; @@ -2651,6 +2317,14 @@ parser_save_context (parser_context_t *context_p, /**< context */ saved_context_p->byte_code = context_p->byte_code; saved_context_p->byte_code_size = context_p->byte_code_size; saved_context_p->literal_pool_data = context_p->literal_pool.data; + saved_context_p->scope_stack_p = context_p->scope_stack_p; + saved_context_p->scope_stack_size = context_p->scope_stack_size; + saved_context_p->scope_stack_top = context_p->scope_stack_top; + saved_context_p->scope_stack_reg_top = context_p->scope_stack_reg_top; +#if ENABLED (JERRY_ES2015) + saved_context_p->scope_stack_global_end = context_p->scope_stack_global_end; + saved_context_p->tagged_template_literal_cp = context_p->tagged_template_literal_cp; +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG saved_context_p->context_stack_depth = context_p->context_stack_depth; @@ -2671,6 +2345,14 @@ parser_save_context (parser_context_t *context_p, /**< context */ parser_cbc_stream_init (&context_p->byte_code); context_p->byte_code_size = 0; parser_list_reset (&context_p->literal_pool); + context_p->scope_stack_p = NULL; + context_p->scope_stack_size = 0; + context_p->scope_stack_top = 0; + context_p->scope_stack_reg_top = 0; +#if ENABLED (JERRY_ES2015) + context_p->scope_stack_global_end = 0; + context_p->tagged_template_literal_cp = JMEM_CP_NULL; +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG context_p->context_stack_depth = 0; @@ -2686,6 +2368,11 @@ parser_restore_context (parser_context_t *context_p, /**< context */ { parser_list_free (&context_p->literal_pool); + if (context_p->scope_stack_p != NULL) + { + parser_free (context_p->scope_stack_p, context_p->scope_stack_size * sizeof (parser_scope_stack_t)); + } + /* Restore private part of the context. */ JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); @@ -2703,6 +2390,14 @@ parser_restore_context (parser_context_t *context_p, /**< context */ context_p->byte_code = saved_context_p->byte_code; context_p->byte_code_size = saved_context_p->byte_code_size; context_p->literal_pool.data = saved_context_p->literal_pool_data; + context_p->scope_stack_p = saved_context_p->scope_stack_p; + context_p->scope_stack_size = saved_context_p->scope_stack_size; + context_p->scope_stack_top = saved_context_p->scope_stack_top; + context_p->scope_stack_reg_top = saved_context_p->scope_stack_reg_top; +#if ENABLED (JERRY_ES2015) + context_p->scope_stack_global_end = saved_context_p->scope_stack_global_end; + context_p->tagged_template_literal_cp = saved_context_p->tagged_template_literal_cp; +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG context_p->context_stack_depth = saved_context_p->context_stack_depth; @@ -2724,27 +2419,27 @@ parser_parse_function (parser_context_t *context_p, /**< context */ JERRY_ASSERT (status_flags & PARSER_IS_FUNCTION); parser_save_context (context_p, &saved_context); context_p->status_flags |= status_flags; +#if ENABLED (JERRY_ES2015) + context_p->status_flags |= PARSER_ALLOW_NEW_TARGET; +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context_p->is_show_opcodes) { -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) JERRY_DEBUG_MSG ("\n--- %s parsing start ---\n\n", (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) ? "Class constructor" : "Function"); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ JERRY_DEBUG_MSG ("\n--- Function parsing start ---\n\n"); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ #if ENABLED (JERRY_DEBUGGER) - if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column)) + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { - /* This option has a high memory and performance costs, - * but it is necessary for executing eval operations by the debugger. */ - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; + jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column); } #endif /* ENABLED (JERRY_DEBUGGER) */ @@ -2788,26 +2483,19 @@ parser_parse_function (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); - -#if ENABLED (JERRY_ES2015_CLASS) - if ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) - { - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ parser_parse_statements (context_p); compiled_code_p = parser_post_processing (context_p); #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context_p->is_show_opcodes) { -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) JERRY_DEBUG_MSG ("\n--- %s parsing end ---\n\n", (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) ? "Class constructor" : "Function"); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ JERRY_DEBUG_MSG ("\n--- Function parsing end ---\n\n"); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ @@ -2816,7 +2504,7 @@ parser_parse_function (parser_context_t *context_p, /**< context */ return compiled_code_p; } /* parser_parse_function */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) /** * Parse arrow function code @@ -2830,13 +2518,13 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ parser_saved_context_t saved_context; ecma_compiled_code_t *compiled_code_p; - JERRY_ASSERT ((status_flags & PARSER_IS_FUNCTION) - && (status_flags & PARSER_IS_ARROW_FUNCTION)); + JERRY_ASSERT (status_flags & PARSER_IS_FUNCTION); + JERRY_ASSERT (status_flags & PARSER_IS_ARROW_FUNCTION); parser_save_context (context_p, &saved_context); - context_p->status_flags |= status_flags | PARSER_ARGUMENTS_NOT_NEEDED; -#if ENABLED (JERRY_ES2015_CLASS) - context_p->status_flags |= saved_context.status_flags & PARSER_CLASS_HAS_SUPER; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + context_p->status_flags |= status_flags; + context_p->status_flags |= saved_context.status_flags & (PARSER_ALLOW_NEW_TARGET + | PARSER_ALLOW_SUPER + | PARSER_ALLOW_SUPER_CALL); #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context_p->is_show_opcodes) @@ -2846,44 +2534,23 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ #if ENABLED (JERRY_DEBUGGER) - if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column)) + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { - /* This option has a high memory and performance costs, - * but it is necessary for executing eval operations by the debugger. */ - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; + jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column); } #endif /* ENABLED (JERRY_DEBUGGER) */ - if (status_flags & PARSER_ARROW_PARSE_ARGS) + if (context_p->token.type == LEXER_LEFT_PAREN) { + lexer_next_token (context_p); parser_parse_function_arguments (context_p, LEXER_RIGHT_PAREN); + lexer_next_token (context_p); } else { - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); - - lexer_construct_literal_object (context_p, - &context_p->token.lit_location, - LEXER_IDENT_LITERAL); - - JERRY_ASSERT (context_p->argument_count == 0 && context_p->literal_count == 1); - - if (context_p->token.literal_is_reserved - || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) - { - context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG; - } - - uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT; - context_p->lit_object.literal_p->status_flags |= lexer_flags; - - context_p->argument_count = 1; - context_p->register_count = 1; + parser_parse_function_arguments (context_p, LEXER_ARROW); } - lexer_next_token (context_p); JERRY_ASSERT (context_p->token.type == LEXER_ARROW); lexer_next_token (context_p); @@ -2909,15 +2576,24 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); - if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { - context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); } else { - parser_emit_cbc (context_p, CBC_RETURN); + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) + { + context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + } + else + { + parser_emit_cbc (context_p, CBC_RETURN); + } } parser_flush_cbc (context_p); + + lexer_update_await_yield (context_p, saved_context.status_flags); } compiled_code_p = parser_post_processing (context_p); @@ -2934,7 +2610,7 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ return compiled_code_p; } /* parser_parse_arrow_function */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Raise a parse error. @@ -2959,14 +2635,37 @@ parser_raise_error (parser_context_t *context_p, /**< context */ parser_free_literals (&context_p->literal_pool); context_p->literal_pool.data = saved_context_p->literal_pool_data; + if (context_p->scope_stack_p != NULL) + { + parser_free (context_p->scope_stack_p, context_p->scope_stack_size * sizeof (parser_scope_stack_t)); + } + context_p->scope_stack_p = saved_context_p->scope_stack_p; + context_p->scope_stack_size = saved_context_p->scope_stack_size; + if (saved_context_p->last_statement.current_p != NULL) { parser_free_jumps (saved_context_p->last_statement); } +#if ENABLED (JERRY_ES2015) + if (saved_context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + ecma_collection_free (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + saved_context_p->tagged_template_literal_cp)); + } +#endif /* ENABLED (JERRY_ES2015) */ + saved_context_p = saved_context_p->prev_context_p; } +#if ENABLED (JERRY_ES2015) + if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) + { + ecma_collection_free (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + context_p->tagged_template_literal_cp)); + } +#endif /* ENABLED (JERRY_ES2015) */ + context_p->error = error; PARSER_THROW (context_p->try_buffer); /* Should never been reached. */ @@ -3032,10 +2731,17 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ { /* It is unlikely that memory can be allocated in an out-of-memory * situation. However, a simple value can still be thrown. */ - JERRY_CONTEXT (error_value) = ECMA_VALUE_NULL; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (ECMA_VALUE_NULL); return ECMA_VALUE_ERROR; } + + if (parser_error.error == PARSER_ERR_INVALID_REGEXP) + { + /* The RegExp compiler has already raised an exception. */ + JERRY_ASSERT (jcontext_has_pending_exception ()); + return ECMA_VALUE_ERROR; + } + #if ENABLED (JERRY_ERROR_MESSAGES) const lit_utf8_byte_t *err_bytes_p = (const lit_utf8_byte_t *) parser_error_to_string (parser_error.error); lit_utf8_size_t err_bytes_size = lit_zt_utf8_string_size (err_bytes_p); diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 64acb286..e9f3e2c5 100755 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -37,17 +37,22 @@ typedef enum PARSER_ERR_OUT_OF_MEMORY, /**< out of memory */ PARSER_ERR_LITERAL_LIMIT_REACHED, /**< maximum number of literals reached */ + PARSER_ERR_SCOPE_STACK_LIMIT_REACHED, /**< maximum depth of scope stack reached */ PARSER_ERR_ARGUMENT_LIMIT_REACHED, /**< maximum number of function arguments reached */ PARSER_ERR_STACK_LIMIT_REACHED, /**< maximum function stack size reached */ PARSER_ERR_JERRY_STACK_LIMIT_REACHED, /**< maximum jerry context stack limit reached */ - PARSER_ERR_REGISTER_LIMIT_REACHED, /**< maximum register size reached */ PARSER_ERR_INVALID_CHARACTER, /**< unexpected character */ + PARSER_ERR_INVALID_OCTAL_DIGIT, /**< invalid octal digit */ PARSER_ERR_INVALID_HEX_DIGIT, /**< invalid hexadecimal digit */ +#if ENABLED (JERRY_ES2015) + PARSER_ERR_INVALID_BIN_DIGIT, /**< invalid binary digit */ +#endif /* ENABLED (JERRY_ES2015) */ PARSER_ERR_INVALID_ESCAPE_SEQUENCE, /**< invalid escape sequence */ PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE, /**< invalid unicode escape sequence */ PARSER_ERR_INVALID_IDENTIFIER_START, /**< character cannot be start of an identifier */ PARSER_ERR_INVALID_IDENTIFIER_PART, /**< character cannot be part of an identifier */ + PARSER_ERR_INVALID_KEYWORD, /**< escape sequences are not allowed in keywords */ PARSER_ERR_INVALID_NUMBER, /**< invalid number literal */ PARSER_ERR_MISSING_EXPONENT, /**< missing exponent */ @@ -73,6 +78,13 @@ typedef enum PARSER_ERR_STRICT_IDENT_NOT_ALLOWED, /**< identifier name is reserved in strict mode */ PARSER_ERR_EVAL_NOT_ALLOWED, /**< eval is not allowed here in strict mode */ PARSER_ERR_ARGUMENTS_NOT_ALLOWED, /**< arguments is not allowed here in strict mode */ +#if ENABLED (JERRY_ES2015) + PARSER_ERR_USE_STRICT_NOT_ALLOWED, /**< use strict directive is not allowed */ + PARSER_ERR_YIELD_NOT_ALLOWED, /**< yield expression is not allowed */ + PARSER_ERR_AWAIT_NOT_ALLOWED, /**< await expression is not allowed */ + PARSER_ERR_FOR_IN_OF_DECLARATION, /**< variable declaration in for-in or for-of loop */ + PARSER_ERR_DUPLICATED_PROTO, /**< duplicated __proto__ fields are not allowed */ +#endif /* ENABLED (JERRY_ES2015) */ PARSER_ERR_DELETE_IDENT_NOT_ALLOWED, /**< identifier delete is not allowed in strict mode */ PARSER_ERR_EVAL_CANNOT_ASSIGNED, /**< eval cannot be assigned in strict mode */ PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED, /**< arguments cannot be assigned in strict mode */ @@ -80,28 +92,16 @@ typedef enum PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED, /**< multiple default cases are not allowed */ PARSER_ERR_DEFAULT_NOT_IN_SWITCH, /**< default statement is not in switch block */ PARSER_ERR_CASE_NOT_IN_SWITCH, /**< case statement is not in switch block */ -#if ENABLED (JERRY_ES2015_CLASS) - PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */ - PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */ - PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */ - PARSER_ERR_UNEXPECTED_SUPER_REFERENCE, /**< unexpected super keyword */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ PARSER_ERR_LEFT_PAREN_EXPECTED, /**< left paren expected */ PARSER_ERR_LEFT_BRACE_EXPECTED, /**< left brace expected */ PARSER_ERR_RIGHT_PAREN_EXPECTED, /**< right paren expected */ PARSER_ERR_RIGHT_SQUARE_EXPECTED, /**< right square expected */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - PARSER_ERR_RIGHT_BRACE_EXPECTED, /**< right brace expected */ -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ PARSER_ERR_COLON_EXPECTED, /**< colon expected */ PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED, /**< colon expected for conditional expression */ PARSER_ERR_SEMICOLON_EXPECTED, /**< semicolon expected */ PARSER_ERR_IN_EXPECTED, /**< in keyword expected */ -#if ENABLED (JERRY_ES2015_FOR_OF) - PARSER_ERR_OF_EXPECTED, /**< of keyword expected */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ PARSER_ERR_WHILE_EXPECTED, /**< while expected for do-while loop */ PARSER_ERR_CATCH_FINALLY_EXPECTED, /**< catch or finally expected */ PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED, /**< array item separator expected */ @@ -109,6 +109,7 @@ typedef enum PARSER_ERR_IDENTIFIER_EXPECTED, /**< identifier expected */ PARSER_ERR_EXPRESSION_EXPECTED, /**< expression expected */ PARSER_ERR_PRIMARY_EXP_EXPECTED, /**< primary expression expected */ + PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED, /**< left-hand-side expression expected */ PARSER_ERR_STATEMENT_EXPECTED, /**< statement expected */ PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED, /**< property identifier expected */ PARSER_ERR_ARGUMENT_LIST_EXPECTED, /**< argument list expected */ @@ -124,15 +125,34 @@ typedef enum PARSER_ERR_INVALID_RETURN, /**< return must be inside a function */ PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */ PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) || ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - PARSER_ERR_DUPLICATED_ARGUMENT_NAMES, /**< duplicated argument names */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) || ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER, /**< formal parameter after rest parameter */ - PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER, /**< rest parameter default initializer */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */ +#if ENABLED (JERRY_ES2015) + PARSER_ERR_VARIABLE_REDECLARED, /**< a variable redeclared */ + PARSER_ERR_LEXICAL_SINGLE_STATEMENT, /**< lexical declaration in single statement context */ + PARSER_ERR_LABELLED_FUNC_NOT_IN_BLOCK, /**< labelled functions are only allowed inside blocks */ + PARSER_ERR_LEXICAL_LET_BINDING, /**< let binding cannot be declared in let/const */ + PARSER_ERR_MISSING_ASSIGN_AFTER_CONST, /**< an assignment is required after a const declaration */ + PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */ + PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */ + PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR, /**< class constructor cannot be a generator */ + PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */ + PARSER_ERR_UNEXPECTED_SUPER_KEYWORD, /**< unexpected super keyword */ + + PARSER_ERR_RIGHT_BRACE_EXPECTED, /**< right brace expected */ + PARSER_ERR_OF_EXPECTED, /**< of keyword expected */ + + PARSER_ERR_ASSIGNMENT_EXPECTED, /**< assignment expression expected */ + PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER, /**< formal parameter after rest parameter */ + PARSER_ERR_SETTER_REST_PARAMETER, /**< setter rest parameter */ + PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER, /**< rest parameter default initializer */ + PARSER_ERR_DUPLICATED_ARGUMENT_NAMES, /**< duplicated argument names */ + PARSER_ERR_INVALID_DESTRUCTURING_PATTERN, /**< invalid destructuring pattern */ + PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION, /**< illegal property in declaration context */ + PARSER_ERR_INVALID_EXPONENTIATION, /**< left operand of ** operator cannot be unary expression */ + PARSER_ERR_NEW_TARGET_EXPECTED, /**< expected new.target expression */ + PARSER_ERR_NEW_TARGET_NOT_ALLOWED, /**< new.target is not allowed in the given context */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) PARSER_ERR_FILE_NOT_FOUND, /**< file not found*/ PARSER_ERR_FROM_EXPECTED, /**< from expected */ diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index ab1942c0..3dbaf97a 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -16,7 +16,7 @@ #ifndef JS_SCANNER_INTERNAL_H #define JS_SCANNER_INTERNAL_H -/** \addtogroup parser Parser +/* \addtogroup parser Parser * @{ * * \addtogroup jsparser JavaScript @@ -26,6 +26,118 @@ * @{ */ +/** + * Scan mode types. + */ +typedef enum +{ + SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */ + SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */ + SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */ + SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning primary expression end */ + SCAN_MODE_STATEMENT, /**< scanning statement */ + SCAN_MODE_STATEMENT_OR_TERMINATOR, /**< scanning statement or statement end */ + SCAN_MODE_STATEMENT_END, /**< scanning statement end */ + SCAN_MODE_VAR_STATEMENT, /**< scanning var statement */ + SCAN_MODE_PROPERTY_NAME, /**< scanning property name */ + SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */ +#if ENABLED (JERRY_ES2015) + SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS, /**< continue scanning function arguments */ + SCAN_MODE_BINDING, /**< array or object binding */ + SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */ + SCAN_MODE_CLASS_METHOD, /**< scanning class method */ +#endif /* ENABLED (JERRY_ES2015) */ +} scan_modes_t; + +/** + * Scan stack mode types. + */ +typedef enum +{ + SCAN_STACK_SCRIPT, /**< script */ + SCAN_STACK_SCRIPT_FUNCTION, /**< script is a function body */ + SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */ + SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */ + SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */ + SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */ +#if ENABLED (JERRY_ES2015) + SCAN_STACK_FUNCTION_ARROW, /**< arrow function expression */ +#endif /* ENABLED (JERRY_ES2015) */ + SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */ + SCAN_STACK_IF_STATEMENT, /**< statement part of "if" statements */ + SCAN_STACK_WITH_STATEMENT, /**< statement part of "with" statements */ + SCAN_STACK_WITH_EXPRESSION, /**< expression part of "with" statements */ + SCAN_STACK_DO_STATEMENT, /**< statement part of "do" statements */ + SCAN_STACK_DO_EXPRESSION, /**< expression part of "do" statements */ + SCAN_STACK_WHILE_EXPRESSION, /**< expression part of "while" iterator */ + SCAN_STACK_PAREN_EXPRESSION, /**< expression in brackets */ + SCAN_STACK_STATEMENT_WITH_EXPR, /**< statement which starts with expression enclosed in brackets */ +#if ENABLED (JERRY_ES2015) + SCAN_STACK_BINDING_INIT, /**< post processing after a single initializer */ + SCAN_STACK_BINDING_LIST_INIT, /**< post processing after an initializer list */ + SCAN_STACK_LET, /**< let statement */ + SCAN_STACK_CONST, /**< const statement */ +#endif /* ENABLED (JERRY_ES2015) */ + /* The SCANNER_IS_FOR_START macro needs to be updated when the following constants are reordered. */ + SCAN_STACK_VAR, /**< var statement */ + SCAN_STACK_FOR_VAR_START, /**< start of "for" iterator with var statement */ +#if ENABLED (JERRY_ES2015) + SCAN_STACK_FOR_LET_START, /**< start of "for" iterator with let statement */ + SCAN_STACK_FOR_CONST_START, /**< start of "for" iterator with const statement */ +#endif /* ENABLED (JERRY_ES2015) */ + SCAN_STACK_FOR_START, /**< start of "for" iterator */ + SCAN_STACK_FOR_CONDITION, /**< condition part of "for" iterator */ + SCAN_STACK_FOR_EXPRESSION, /**< expression part of "for" iterator */ + SCAN_STACK_SWITCH_EXPRESSION, /**< expression part of "switch" statement */ + SCAN_STACK_CASE_STATEMENT, /**< case statement inside a switch statement */ + SCAN_STACK_COLON_EXPRESSION, /**< expression between a question mark and colon */ + SCAN_STACK_TRY_STATEMENT, /**< try statement */ + SCAN_STACK_CATCH_STATEMENT, /**< catch statement */ + SCAN_STACK_ARRAY_LITERAL, /**< array literal or destructuring assignment or binding */ + SCAN_STACK_OBJECT_LITERAL, /**< object literal group */ + SCAN_STACK_PROPERTY_ACCESSOR, /**< property accessor in square brackets */ +#if ENABLED (JERRY_ES2015) + /* These four must be in this order. */ + SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ + SCAN_STACK_COMPUTED_GENERATOR, /**< computed generator function */ + SCAN_STACK_COMPUTED_ASYNC, /**< computed async function */ + SCAN_STACK_COMPUTED_ASYNC_GENERATOR, /**< computed async function */ + SCAN_STACK_TEMPLATE_STRING, /**< template string */ + SCAN_STACK_TAGGED_TEMPLATE_LITERAL, /**< tagged template literal */ + SCAN_STACK_PRIVATE_BLOCK_EARLY, /**< private block for single statements (force early declarations) */ + SCAN_STACK_PRIVATE_BLOCK, /**< private block for single statements */ + SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */ + SCAN_STACK_ARROW_EXPRESSION, /**< expression body of an arrow function */ + SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR, /**< explicit class constructor */ + SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR, /**< implicit class constructor */ + SCAN_STACK_CLASS_STATEMENT, /**< class statement */ + SCAN_STACK_CLASS_EXPRESSION, /**< class expression */ + SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ + SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ + SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */ +#endif /* ENABLED (JERRY_ES2015) */ +} scan_stack_modes_t; + +/** + * Scanner context flag types. + */ +typedef enum +{ + SCANNER_CONTEXT_NO_FLAGS = 0, /**< no flags are set */ +#if ENABLED (JERRY_ES2015) + SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION = (1 << 0), /**< throw async function error */ +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_DEBUGGER) + SCANNER_CONTEXT_DEBUGGER_ENABLED = (1 << 1), /**< debugger is enabled */ +#endif /* ENABLED (JERRY_DEBUGGER) */ +} scanner_context_flags_t; + +/** + * Checks whether the stack top is a for statement start. + */ +#define SCANNER_IS_FOR_START(stack_top) \ + ((stack_top) >= SCAN_STACK_FOR_VAR_START && (stack_top) <= SCAN_STACK_FOR_START) + /** * Generic descriptor which stores only the start position. */ @@ -34,6 +146,61 @@ typedef struct const uint8_t *source_p; /**< start source byte */ } scanner_source_start_t; +/** + * Descriptor for storing a binding literal on stack. + */ +typedef struct +{ + lexer_lit_location_t *literal_p; /**< binding literal */ +} scanner_binding_literal_t; + +/** + * Flags for type member of lexer_lit_location_t structure in the literal pool. + */ +typedef enum +{ + SCANNER_LITERAL_IS_ARG = (1 << 0), /**< literal is argument */ + SCANNER_LITERAL_IS_VAR = (1 << 1), /**< literal is var */ +#if ENABLED (JERRY_ES2015) + /** literal is a destructured argument binding of a possible arrow function */ + SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_VAR, +#endif /* ENABLED (JERRY_ES2015) */ + SCANNER_LITERAL_IS_FUNC = (1 << 2), /**< literal is function */ + SCANNER_LITERAL_NO_REG = (1 << 3), /**< literal cannot be stored in a register */ + SCANNER_LITERAL_IS_LET = (1 << 4), /**< literal is let */ +#if ENABLED (JERRY_ES2015) + /** literal is a function declared in this block (prevents declaring let/const with the same name) */ + SCANNER_LITERAL_IS_FUNC_DECLARATION = SCANNER_LITERAL_IS_LET, +#endif /* ENABLED (JERRY_ES2015) */ + SCANNER_LITERAL_IS_CONST = (1 << 5), /**< literal is const */ +#if ENABLED (JERRY_ES2015) + /** literal is a destructured argument binding */ + SCANNER_LITERAL_IS_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_CONST, + SCANNER_LITERAL_IS_USED = (1 << 6), /**< literal is used */ + SCANNER_LITERAL_EARLY_CREATE = (1 << 7), /**< binding should be created early with ECMA_VALUE_UNINITIALIZED */ +#endif /* ENABLED (JERRY_ES2015) */ +} scanner_literal_type_flags_t; + +/* + * Known combinations: + * + * SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION : + * function declared in this block + * SCANNER_LITERAL_IS_LOCAL : + * module import on global scope, catch block variable otherwise + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC : + * a function argument which is reassigned to a function later + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG : + * destructured binding argument + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_FUNC : + * destructured binding argument which is reassigned to a function later + */ + +/** + * Literal is a local declration (let, const, catch variable, etc.) + */ +#define SCANNER_LITERAL_IS_LOCAL (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST) + /** * For statement descriptor. */ @@ -55,14 +222,181 @@ typedef struct scanner_case_info_t **last_case_p; /**< last case info */ } scanner_switch_statement_t; +#if ENABLED (JERRY_ES2015) + +/** + * Types of scanner destructuring bindings. + */ +typedef enum +{ + /* Update SCANNER_NEEDS_BINDING_LIST after changing these values. */ + SCANNER_BINDING_NONE, /**< not a destructuring binding expression */ + SCANNER_BINDING_VAR, /**< destructuring var binding */ + SCANNER_BINDING_LET, /**< destructuring let binding */ + SCANNER_BINDING_CATCH, /**< destructuring catch binding */ + SCANNER_BINDING_CONST, /**< destructuring const binding */ + SCANNER_BINDING_ARG, /**< destructuring arg binding */ + SCANNER_BINDING_ARROW_ARG, /**< possible destructuring arg binding of an arrow function */ +} scanner_binding_type_t; + +/** + * Check whether a binding list is needed for the binding pattern. + */ +#define SCANNER_NEEDS_BINDING_LIST(type) ((type) >= SCANNER_BINDING_LET) + +/** + * Scanner binding items for destructuring binding patterns. + */ +typedef struct scanner_binding_item_t +{ + struct scanner_binding_item_t *next_p; /**< next binding in the list */ + lexer_lit_location_t *literal_p; /**< binding literal */ +} scanner_binding_item_t; + +/** + * Scanner binding lists for destructuring binding patterns. + */ +typedef struct scanner_binding_list_t +{ + struct scanner_binding_list_t *prev_p; /**< prev list */ + scanner_binding_item_t *items_p; /**< list of bindings */ + bool is_nested; /**< is nested binding declaration */ +} scanner_binding_list_t; + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Flags for scanner_literal_pool_t structure. + */ +typedef enum +{ + SCANNER_LITERAL_POOL_FUNCTION = (1 << 0), /**< literal pool represents a function */ + SCANNER_LITERAL_POOL_BLOCK = (1 << 1), /**< literal pool represents a code block */ + SCANNER_LITERAL_POOL_IS_STRICT = (1 << 2), /**< literal pool represents a strict mode code block */ + SCANNER_LITERAL_POOL_CAN_EVAL = (1 << 3), /**< prepare for executing eval in this block */ + SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 4), /**< arguments object must not be constructed */ +#if ENABLED (JERRY_ES2015) + SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 5), /**< arguments object should be unmapped */ +#endif /* ENABLED (JERRY_ES2015) */ + SCANNER_LITERAL_POOL_IN_WITH = (1 << 6), /**< literal pool is in a with statement */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + SCANNER_LITERAL_POOL_IN_EXPORT = (1 << 7), /**< the declared variables are exported by the module system */ +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_ES2015) + SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 8), /**< function statement */ + SCANNER_LITERAL_POOL_GENERATOR = (1 << 9), /**< generator function */ + SCANNER_LITERAL_POOL_ASYNC = (1 << 10), /**< async function */ + SCANNER_LITERAL_POOL_ASYNC_ARROW = (1 << 11), /**< can be an async arrow function */ +#endif /* ENABLED (JERRY_ES2015) */ +} scanner_literal_pool_flags_t; + +/** + * Define a function where no arguments are allowed. + */ +#define SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS \ + (SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_NO_ARGUMENTS) + +/** + * Getting the generator and async properties of literal pool status flags. + */ +#define SCANNER_FROM_LITERAL_POOL_TO_COMPUTED(status_flags) \ + ((uint8_t) ((((status_flags) >> 9) & 0x3) + SCAN_STACK_COMPUTED_PROPERTY)) + +/** + * Setting the generator and async properties of literal pool status flags. + */ +#define SCANNER_FROM_COMPUTED_TO_LITERAL_POOL(mode) \ + (((mode) - SCAN_STACK_COMPUTED_PROPERTY) << 9) + +/** + * Local literal pool. + */ +typedef struct scanner_literal_pool_t +{ + struct scanner_literal_pool_t *prev_p; /**< previous literal pool */ + const uint8_t *source_p; /**< source position where the final data needs to be inserted */ + parser_list_t literal_pool; /**< list of literal */ + uint16_t status_flags; /**< combination of scanner_literal_pool_flags_t flags */ + uint16_t no_declarations; /**< size of scope stack required during parsing */ +} scanner_literal_pool_t; + /** * Scanner context. */ -typedef struct +struct scanner_context_t { + uint32_t context_status_flags; /**< original status flags of the context */ uint8_t mode; /**< scanner mode */ +#if ENABLED (JERRY_ES2015) + uint8_t binding_type; /**< current destructuring binding type */ +#endif /* ENABLED (JERRY_ES2015) */ + uint16_t status_flags; /**< scanner status flags */ +#if ENABLED (JERRY_ES2015) + scanner_binding_list_t *active_binding_list_p; /**< currently active binding list */ +#endif /* ENABLED (JERRY_ES2015) */ + scanner_literal_pool_t *active_literal_pool_p; /**< currently active literal pool */ scanner_switch_statement_t active_switch_statement; /**< currently active switch statement */ -} scanner_context_t; + scanner_info_t *end_arguments_p; /**< position of end arguments */ +#if ENABLED (JERRY_ES2015) + const uint8_t *async_source_p; /**< source position for async functions */ +#endif /* ENABLED (JERRY_ES2015) */ +}; + +/* Scanner utils. */ + +void scanner_raise_error (parser_context_t *context_p); +#if ENABLED (JERRY_ES2015) +void scanner_raise_redeclaration_error (parser_context_t *context_p); +#endif /* ENABLED (JERRY_ES2015) */ + +void *scanner_malloc (parser_context_t *context_p, size_t size); +void scanner_free (void *ptr, size_t size); + +size_t scanner_get_stream_size (scanner_info_t *info_p, size_t size); +scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, size_t size); +scanner_info_t *scanner_insert_info_before (parser_context_t *context_p, const uint8_t *source_p, + scanner_info_t *start_info_p, size_t size); +scanner_literal_pool_t *scanner_push_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p, + uint16_t status_flags); +void scanner_pop_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p); +#if ENABLED (JERRY_ES2015) +void scanner_construct_global_block (parser_context_t *context_p, scanner_context_t *scanner_context_p); +#endif /* ENABLED (JERRY_ES2015) */ +void scanner_filter_arguments (parser_context_t *context_p, scanner_context_t *scanner_context_p); +lexer_lit_location_t *scanner_add_custom_literal (parser_context_t *context_p, scanner_literal_pool_t *literal_pool_p, + const lexer_lit_location_t *literal_location_p); +lexer_lit_location_t *scanner_add_literal (parser_context_t *context_p, scanner_context_t *scanner_context_p); +void scanner_add_reference (parser_context_t *context_p, scanner_context_t *scanner_context_p); +lexer_lit_location_t *scanner_append_argument (parser_context_t *context_p, scanner_context_t *scanner_context_p); +#if ENABLED (JERRY_ES2015) +void scanner_detect_invalid_var (parser_context_t *context_p, scanner_context_t *scanner_context_p, + lexer_lit_location_t *var_literal_p); +void scanner_detect_invalid_let (parser_context_t *context_p, lexer_lit_location_t *let_literal_p); +#endif /* ENABLED (JERRY_ES2015) */ +void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *scanner_context_p); + +#if ENABLED (JERRY_ES2015) +void scanner_push_class_declaration (parser_context_t *context_p, scanner_context_t *scanner_context_p, + uint8_t stack_mode); +void scanner_push_destructuring_pattern (parser_context_t *context_p, scanner_context_t *scanner_context_p, + uint8_t binding_type, bool is_nested); +void scanner_pop_binding_list (scanner_context_t *scanner_context_p); +void scanner_append_hole (parser_context_t *context_p, scanner_context_t *scanner_context_p); +#endif /* ENABLED (JERRY_ES2015) */ + +/* Scanner operations. */ + +#if ENABLED (JERRY_ES2015) +void scanner_add_async_literal (parser_context_t *context_p, scanner_context_t *scanner_context_p); +void scanner_check_arrow (parser_context_t *context_p, scanner_context_t *scanner_context_p); +void scanner_scan_simple_arrow (parser_context_t *context_p, scanner_context_t *scanner_context_p, + const uint8_t *source_p); +void scanner_check_arrow_arg (parser_context_t *context_p, scanner_context_t *scanner_context_p); +bool scanner_check_async_function (parser_context_t *context_p, scanner_context_t *scanner_context_p); +void scanner_check_function_after_if (parser_context_t *context_p, scanner_context_t *scanner_context_p); +#endif /* ENABLED (JERRY_ES2015) */ +void scanner_scan_bracket (parser_context_t *context_p, scanner_context_t *scanner_context_p); +void scanner_check_directives (parser_context_t *context_p, scanner_context_t *scanner_context_p); /** * @} diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c new file mode 100644 index 00000000..325b3786 --- /dev/null +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -0,0 +1,590 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "js-parser-internal.h" +#include "js-scanner-internal.h" +#include "lit-char-helpers.h" + +#if ENABLED (JERRY_PARSER) + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_scanner Scanner + * @{ + */ + +#if ENABLED (JERRY_ES2015) + +/** + * Add the "async" literal to the literal pool. + */ +void +scanner_add_async_literal (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + lexer_lit_location_t async_literal; + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC); + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &async_literal, sizeof (lexer_lit_location_t)); + + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &async_literal); + + lit_location_p->type |= SCANNER_LITERAL_IS_USED; + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } +} /* scanner_add_async_literal */ + +/** + * Init scanning the body of an arrow function. + */ +static void +scanner_check_arrow_body (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_EXPRESSION); + return; + } + + lexer_next_token (context_p); + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_ARROW); + scanner_check_directives (context_p, scanner_context_p); +} /* scanner_check_arrow_body */ + +/** + * Process arrow function with argument list. + */ +void +scanner_check_arrow (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + parser_stack_pop_uint8 (context_p); + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_ARROW + || (context_p->token.flags & LEXER_WAS_NEWLINE)) + { + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + scanner_add_async_literal (context_p, scanner_context_p); + } + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + scanner_pop_literal_pool (context_p, scanner_context_p); + return; + } + + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + parser_stack_pop (context_p, NULL, sizeof (lexer_lit_location_t) + 1); + } + + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + uint16_t status_flags = literal_pool_p->status_flags; + + status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; + status_flags &= (uint16_t) ~(SCANNER_LITERAL_POOL_IN_WITH + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_LITERAL_POOL_ASYNC); + + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (status_flags & SCANNER_LITERAL_POOL_ASYNC_ARROW) + { + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + + literal_pool_p->status_flags = status_flags; + + scanner_filter_arguments (context_p, scanner_context_p); + scanner_check_arrow_body (context_p, scanner_context_p); +} /* scanner_check_arrow */ + +/** + * Process arrow function with a single argument. + */ +void +scanner_scan_simple_arrow (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + const uint8_t *source_p) /**< identifier end position */ +{ + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; + + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (scanner_context_p->async_source_p != NULL) + { + JERRY_ASSERT (scanner_context_p->async_source_p == source_p); + + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + + scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + literal_pool_p->source_p = source_p; + + lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p); + location_p->type |= SCANNER_LITERAL_IS_ARG; + + /* Skip the => token, which size is two. */ + context_p->source_p += 2; + PARSER_PLUS_EQUAL_LC (context_p->column, 2); + context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES); + + scanner_check_arrow_body (context_p, scanner_context_p); +} /* scanner_scan_simple_arrow */ + +/** + * Process the next argument of a might-be arrow function. + */ +void +scanner_check_arrow_arg (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); + + const uint8_t *source_p = context_p->source_p; + bool process_arrow = false; + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + if (context_p->token.type == LEXER_THREE_DOTS) + { + lexer_next_token (context_p); + } + + if (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + + if (lexer_check_arrow (context_p)) + { + process_arrow = true; + } + else + { + lexer_lit_location_t *argument_literal_p = scanner_append_argument (context_p, scanner_context_p); + + scanner_detect_eval_call (context_p, scanner_context_p); + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_ASSIGN) + { + if (argument_literal_p->type & SCANNER_LITERAL_IS_USED) + { + JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE); + return; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = argument_literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + return; + } + + if (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_PAREN) + { + return; + } + } + } + else if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + scanner_append_hole (context_p, scanner_context_p); + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_ARROW_ARG, false); + + if (context_p->token.type == LEXER_LEFT_BRACE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context_p->mode = SCAN_MODE_BINDING; + lexer_next_token (context_p); + return; + } + + scanner_pop_literal_pool (context_p, scanner_context_p); + + parser_stack_pop_uint8 (context_p); + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); + + if (process_arrow) + { + scanner_scan_simple_arrow (context_p, scanner_context_p, source_p); + } +} /* scanner_check_arrow_arg */ + +/** + * Detect async functions. + * + * @return true, if async is followed by a function keyword, false otherwise + */ +bool +scanner_check_async_function (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + JERRY_ASSERT (lexer_token_is_async (context_p)); + JERRY_ASSERT (scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION + || scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW); + JERRY_ASSERT (scanner_context_p->async_source_p != NULL); + + lexer_lit_location_t async_literal = context_p->token.lit_location; + + lexer_next_token (context_p); + + if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) + { + if (context_p->token.type == LEXER_KEYW_FUNCTION) + { + return true; + } + + if (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + if (!lexer_check_arrow (context_p)) + { + scanner_raise_error (context_p); + } + + scanner_scan_simple_arrow (context_p, scanner_context_p, scanner_context_p->async_source_p); + scanner_context_p->async_source_p = NULL; + return false; + } + + if (context_p->token.type == LEXER_LEFT_PAREN) + { + parser_stack_push (context_p, &async_literal, sizeof (lexer_lit_location_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_USE_ASYNC); + return false; + } + } + + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &async_literal); + lit_location_p->type |= SCANNER_LITERAL_IS_USED; + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } + + scanner_context_p->async_source_p = NULL; + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return false; +} /* scanner_check_async_function */ + +/** + * Check whether the statement of an if/else construct is a function statement. + */ +void +scanner_check_function_after_if (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + lexer_next_token (context_p); + scanner_context_p->mode = SCAN_MODE_STATEMENT; + + if (JERRY_UNLIKELY (context_p->token.type == LEXER_KEYW_FUNCTION)) + { + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, + scanner_context_p, + SCANNER_LITERAL_POOL_BLOCK); + + literal_pool_p->source_p = context_p->source_p; + parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK); + } +} /* scanner_check_function_after_if */ + +/** + * Arrow types for scanner_scan_bracket() function. + */ +typedef enum +{ + SCANNER_SCAN_BRACKET_NO_ARROW, /**< not an arrow function */ + SCANNER_SCAN_BRACKET_SIMPLE_ARROW, /**< simple arrow function */ + SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG, /**< arrow function with one argument */ +} scanner_scan_bracket_arrow_type_t; + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Scan bracketed expressions. + */ +void +scanner_scan_bracket (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + size_t depth = 0; +#if ENABLED (JERRY_ES2015) + const uint8_t *arrow_source_p; + const uint8_t *async_source_p = NULL; + scanner_scan_bracket_arrow_type_t arrow_type = SCANNER_SCAN_BRACKET_NO_ARROW; +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_PAREN); + + do + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + depth++; + lexer_next_token (context_p); + } + while (context_p->token.type == LEXER_LEFT_PAREN); + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + switch (context_p->token.type) + { + case LEXER_LITERAL: + { + if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } + +#if ENABLED (JERRY_ES2015) + const uint8_t *source_p = context_p->source_p; + + if (lexer_check_arrow (context_p)) + { + arrow_source_p = source_p; + arrow_type = SCANNER_SCAN_BRACKET_SIMPLE_ARROW; + break; + } + + size_t total_depth = depth; +#endif /* ENABLED (JERRY_ES2015) */ + + while (depth > 0 && lexer_check_next_character (context_p, LIT_CHAR_RIGHT_PAREN)) + { + lexer_consume_next_character (context_p); + depth--; + } + + if (context_p->token.keyword_type == LEXER_KEYW_EVAL + && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) + { +#if ENABLED (JERRY_ES2015) + /* A function call cannot be an eval function. */ + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + break; + } + +#if ENABLED (JERRY_ES2015) + if (total_depth == depth) + { + if (lexer_check_arrow_param (context_p)) + { + JERRY_ASSERT (depth > 0); + depth--; + break; + } + + if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + async_source_p = source_p; + } + } + else if (depth == total_depth - 1) + { + if (lexer_check_arrow (context_p)) + { + arrow_type = SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG; + break; + } + + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + scanner_add_async_literal (context_p, scanner_context_p); + } + } + + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } +#if ENABLED (JERRY_ES2015) + case LEXER_THREE_DOTS: + case LEXER_LEFT_SQUARE: + case LEXER_LEFT_BRACE: + case LEXER_RIGHT_PAREN: + { + JERRY_ASSERT (depth > 0); + depth--; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + default: + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } + } + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL) + && (arrow_source_p == NULL || depth > 0)) + { + scanner_context_p->async_source_p = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ + + while (depth > 0) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); + depth--; + } + +#if ENABLED (JERRY_ES2015) + if (arrow_source_p != NULL) + { + JERRY_ASSERT (async_source_p == NULL); + + if (arrow_type == SCANNER_SCAN_BRACKET_SIMPLE_ARROW) + { + scanner_scan_simple_arrow (context_p, scanner_context_p, arrow_source_p); + return; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS); + + uint16_t status_flags = 0; + + if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL)) + { + status_flags |= SCANNER_LITERAL_POOL_ASYNC_ARROW; + arrow_source_p = scanner_context_p->async_source_p; + scanner_context_p->async_source_p = NULL; + } + + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + literal_pool_p->source_p = arrow_source_p; + + if (arrow_type == SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG) + { + scanner_append_argument (context_p, scanner_context_p); + scanner_detect_eval_call (context_p, scanner_context_p); + + context_p->token.type = LEXER_RIGHT_PAREN; + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } + else if (context_p->token.type == LEXER_RIGHT_PAREN) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } + else + { + scanner_check_arrow_arg (context_p, scanner_context_p); + } + } + else if (JERRY_UNLIKELY (async_source_p != NULL)) + { + scanner_context_p->async_source_p = async_source_p; + scanner_check_async_function (context_p, scanner_context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ +} /* scanner_scan_bracket */ + +/** + * Check directives before a source block. + */ +void +scanner_check_directives (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; + + while (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_STRING_LITERAL) + { + bool is_use_strict = false; + + if (lexer_string_is_use_strict (context_p) + && !(context_p->status_flags & PARSER_IS_STRICT)) + { + is_use_strict = true; + context_p->status_flags |= PARSER_IS_STRICT; + } + + lexer_next_token (context_p); + + if (!lexer_string_is_directive (context_p)) + { + if (is_use_strict) + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; + } + + /* The string is part of an expression statement. */ + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + + if (is_use_strict) + { + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_IS_STRICT; + } + + if (context_p->token.type == LEXER_SEMICOLON) + { + lexer_next_token (context_p); + } + } +} /* scanner_check_directives */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_PARSER) */ diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index e0655c93..d7a402e3 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -13,8 +13,11 @@ * limitations under the License. */ +#include "ecma-helpers.h" +#include "jcontext.h" #include "js-parser-internal.h" #include "js-scanner-internal.h" +#include "lit-char-helpers.h" #if ENABLED (JERRY_PARSER) @@ -28,6 +31,34 @@ * @{ */ +JERRY_STATIC_ASSERT (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_OF_REGISTERS < PARSER_REGISTER_START, + maximum_number_of_literals_plus_registers_must_be_less_than_register_start); + +#if ENABLED (JERRY_ES2015) + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG & SCANNER_LITERAL_IS_LOCAL) == 0, + is_arrow_arg_binding_flag_must_not_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_LET & SCANNER_LITERAL_IS_LOCAL) != 0, + is_let_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_CONST & SCANNER_LITERAL_IS_LOCAL) != 0, + is_const_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_FUNC_DECLARATION & SCANNER_LITERAL_IS_LOCAL) != 0, + is_func_declaration_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_DESTRUCTURED_ARG & SCANNER_LITERAL_IS_LOCAL) != 0, + is_arg_binding_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT (SCANNER_LITERAL_IS_FUNC_DECLARATION != SCANNER_LITERAL_IS_DESTRUCTURED_ARG, + is_func_declaration_must_be_different_from_is_arg_binding); + +JERRY_STATIC_ASSERT (PARSER_SCOPE_STACK_IS_CONST_REG == PARSER_SCOPE_STACK_IS_LOCAL_CREATED, + scope_stack_is_const_reg_and_scope_stack_is_local_created_must_be_the_same); + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Raise a scanner error. */ @@ -39,6 +70,22 @@ scanner_raise_error (parser_context_t *context_p) /**< context */ JERRY_ASSERT (0); } /* scanner_raise_error */ +#if ENABLED (JERRY_ES2015) + +/** + * Raise a variable redeclaration error. + */ +void +scanner_raise_redeclaration_error (parser_context_t *context_p) /**< context */ +{ + scanner_info_t *info_p = scanner_insert_info (context_p, context_p->source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_ERR_REDECLARED; + + scanner_raise_error (context_p); +} /* scanner_raise_redeclaration_error */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Allocate memory for scanner. * @@ -74,6 +121,68 @@ scanner_free (void *ptr, /**< pointer to free */ jmem_heap_free_block (ptr, size); } /* scanner_free */ +/** + * Count the size of a stream after an info block. + * + * @return the size in bytes + */ +size_t +scanner_get_stream_size (scanner_info_t *info_p, /**< scanner info block */ + size_t size) /**< size excluding the stream */ +{ + const uint8_t *data_p = ((const uint8_t *) info_p) + size; + const uint8_t *data_p_start = data_p; + + while (data_p[0] != SCANNER_STREAM_TYPE_END) + { + switch (data_p[0] & SCANNER_STREAM_TYPE_MASK) + { + case SCANNER_STREAM_TYPE_VAR: +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_LET: + case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_LOCAL: +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + case SCANNER_STREAM_TYPE_IMPORT: +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + case SCANNER_STREAM_TYPE_ARG: +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_ARG_VAR: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR: +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + case SCANNER_STREAM_TYPE_ARG_FUNC: +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: +#endif /* ENABLED (JERRY_ES2015) */ + case SCANNER_STREAM_TYPE_FUNC: + { + break; + } + default: + { + JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE); + data_p++; + continue; + } + } + + data_p += 3; + + if (data_p[-3] & SCANNER_STREAM_UINT16_DIFF) + { + data_p++; + } + else if (data_p[-1] == 0) + { + data_p += sizeof (const uint8_t *); + } + } + + return size + 1 + (size_t) (data_p - data_p_start); +} /* scanner_get_stream_size */ + /** * Insert a scanner info block into the scanner info chain. * @@ -89,6 +198,7 @@ scanner_insert_info (parser_context_t *context_p, /**< context */ scanner_info_t *prev_scanner_info_p = NULL; JERRY_ASSERT (scanner_info_p != NULL); + JERRY_ASSERT (source_p != NULL); new_scanner_info_p->source_p = source_p; @@ -117,6 +227,42 @@ scanner_insert_info (parser_context_t *context_p, /**< context */ return new_scanner_info_p; } /* scanner_insert_info */ +/** + * Insert a scanner info block into the scanner info chain before a given info block. + * + * @return newly allocated scanner info + */ +scanner_info_t * +scanner_insert_info_before (parser_context_t *context_p, /**< context */ + const uint8_t *source_p, /**< triggering position */ + scanner_info_t *start_info_p, /**< first info position */ + size_t size) /**< size of the memory block */ +{ + JERRY_ASSERT (start_info_p != NULL); + + scanner_info_t *new_scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, size); + scanner_info_t *scanner_info_p = start_info_p->next_p; + scanner_info_t *prev_scanner_info_p = start_info_p; + + new_scanner_info_p->source_p = source_p; + + while (source_p < scanner_info_p->source_p) + { + prev_scanner_info_p = scanner_info_p; + scanner_info_p = scanner_info_p->next_p; + + JERRY_ASSERT (scanner_info_p != NULL); + } + + /* Multiple scanner info blocks cannot be assigned to the same position. */ + JERRY_ASSERT (source_p != scanner_info_p->source_p); + + new_scanner_info_p->next_p = scanner_info_p; + + prev_scanner_info_p->next_p = new_scanner_info_p; + return new_scanner_info_p; +} /* scanner_insert_info_before */ + /** * Release the next scanner info. */ @@ -143,6 +289,19 @@ scanner_set_active (parser_context_t *context_p) /**< context */ context_p->active_scanner_info_p = scanner_info_p; } /* scanner_set_active */ +/** + * Set the next scanner info to the active scanner info. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_revert_active (parser_context_t *context_p) /**< context */ +{ + scanner_info_t *scanner_info_p = context_p->active_scanner_info_p; + + context_p->active_scanner_info_p = scanner_info_p->next_p; + scanner_info_p->next_p = context_p->next_scanner_info_p; + context_p->next_scanner_info_p = scanner_info_p; +} /* scanner_revert_active */ + /** * Release the active scanner info. */ @@ -225,6 +384,1182 @@ scanner_seek (parser_context_t *context_p) /**< context */ context_p->next_scanner_info_p = prev_p->next_p; } /* scanner_seek */ +/** + * Push a new literal pool. + * + * @return the newly created literal pool + */ +scanner_literal_pool_t * +scanner_push_literal_pool (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + uint16_t status_flags) /**< combination of scanner_literal_pool_flags_t flags */ +{ + scanner_literal_pool_t *prev_literal_pool_p = scanner_context_p->active_literal_pool_p; + scanner_literal_pool_t *literal_pool_p; + + literal_pool_p = (scanner_literal_pool_t *) scanner_malloc (context_p, sizeof (scanner_literal_pool_t)); + + if (!(status_flags & SCANNER_LITERAL_POOL_FUNCTION)) + { + JERRY_ASSERT (prev_literal_pool_p != NULL); + status_flags |= SCANNER_LITERAL_POOL_NO_ARGUMENTS; + +#if ENABLED (JERRY_ES2015) + const uint16_t copied_flags = (SCANNER_LITERAL_POOL_IN_WITH + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_LITERAL_POOL_ASYNC); +#else /* !ENABLED (JERRY_ES2015) */ + const uint16_t copied_flags = SCANNER_LITERAL_POOL_IN_WITH; +#endif /* ENABLED (JERRY_ES2015) */ + + status_flags |= (uint16_t) (prev_literal_pool_p->status_flags & copied_flags); + } +#if ENABLED (JERRY_ES2015) + else + { + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (status_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } + + if (status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (prev_literal_pool_p != NULL) + { + const uint16_t copied_flags = SCANNER_LITERAL_POOL_IS_STRICT; + status_flags |= (uint16_t) (prev_literal_pool_p->status_flags & copied_flags); + + /* The logical value of these flags must be the same. */ + JERRY_ASSERT (!(status_flags & SCANNER_LITERAL_POOL_IS_STRICT) == !(context_p->status_flags & PARSER_IS_STRICT)); + } + + parser_list_init (&literal_pool_p->literal_pool, + sizeof (lexer_lit_location_t), + (uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_lit_location_t))); + literal_pool_p->source_p = NULL; + literal_pool_p->status_flags = status_flags; + literal_pool_p->no_declarations = 0; + + literal_pool_p->prev_p = prev_literal_pool_p; + scanner_context_p->active_literal_pool_p = literal_pool_p; + + return literal_pool_p; +} /* scanner_push_literal_pool */ + +JERRY_STATIC_ASSERT (PARSER_MAXIMUM_IDENT_LENGTH <= UINT8_MAX, + maximum_ident_length_must_fit_in_a_byte); + +/** + * Checks whether a literal is equal to "arguments". + */ +static inline bool JERRY_ATTR_ALWAYS_INLINE +scanner_literal_is_arguments (lexer_lit_location_t *literal_p) /**< literal */ +{ + return lexer_compare_identifier_to_string (literal_p, (const uint8_t *) "arguments", 9); +} /* scanner_literal_is_arguments */ + +/** + * Pop the last literal pool from the end. + */ +void +scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p; + + if (literal_pool_p->source_p == NULL) + { + JERRY_ASSERT (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION); + JERRY_ASSERT (literal_pool_p->literal_pool.data.first_p == NULL + && literal_pool_p->literal_pool.data.last_p == NULL); + + scanner_context_p->active_literal_pool_p = literal_pool_p->prev_p; + scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t)); + return; + } + + parser_list_iterator_t literal_iterator; + lexer_lit_location_t *literal_p; + uint16_t status_flags = literal_pool_p->status_flags; + bool arguments_required = ((status_flags & (SCANNER_LITERAL_POOL_CAN_EVAL | SCANNER_LITERAL_POOL_NO_ARGUMENTS)) + == SCANNER_LITERAL_POOL_CAN_EVAL); + + uint8_t can_eval_types = 0; +#if ENABLED (JERRY_ES2015) + if (prev_literal_pool_p == NULL && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + { + can_eval_types |= SCANNER_LITERAL_IS_FUNC; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && prev_literal_pool_p != NULL) + { + prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + } + +#if ENABLED (JERRY_DEBUGGER) + if (scanner_context_p->status_flags & SCANNER_CONTEXT_DEBUGGER_ENABLED) + { + /* When debugger is enabled, identifiers are not stored in registers. However, + * this does not affect 'eval' detection, so 'arguments' object is not created. */ + status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + } +#endif /* ENABLED (JERRY_DEBUGGER) */ + + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + + const uint8_t *prev_source_p = literal_pool_p->source_p - 1; + size_t compressed_size = 1; + uint32_t no_declarations = literal_pool_p->no_declarations; + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + uint8_t type = literal_p->type; + + if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)) + { + continue; + } + + if (!(status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) && scanner_literal_is_arguments (literal_p)) + { + status_flags |= SCANNER_LITERAL_POOL_NO_ARGUMENTS; + + if (type & (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LOCAL)) + { + arguments_required = false; + } + else + { + literal_p->type = 0; + arguments_required = true; + continue; + } + } + +#if ENABLED (JERRY_ES2015) + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) + && (type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION)) == SCANNER_LITERAL_IS_FUNC) + { + if (prev_literal_pool_p == NULL + && (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) + && scanner_scope_find_let_declaration (context_p, literal_p)) + { + literal_p->type = 0; + continue; + } + + if (!(type & SCANNER_LITERAL_IS_ARG)) + { + type |= SCANNER_LITERAL_IS_VAR; + } + + type &= (uint8_t) ~SCANNER_LITERAL_IS_FUNC; + literal_p->type = type; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if ((type & SCANNER_LITERAL_IS_LOCAL) + || ((type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) + && (status_flags & SCANNER_LITERAL_POOL_FUNCTION))) + { + JERRY_ASSERT ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) + || !(literal_p->type & SCANNER_LITERAL_IS_ARG)); + + if (literal_p->length == 0) + { + compressed_size += 1; + continue; + } + + no_declarations++; + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) || (type & can_eval_types)) + { + type |= SCANNER_LITERAL_NO_REG; + literal_p->type = type; + } + + if (type & SCANNER_LITERAL_IS_FUNC) + { + no_declarations++; + +#if ENABLED (JERRY_ES2015) + if ((type & (SCANNER_LITERAL_IS_CONST | SCANNER_LITERAL_IS_ARG)) == SCANNER_LITERAL_IS_CONST) + { + JERRY_ASSERT (type & SCANNER_LITERAL_IS_LET); + + /* Catch parameters cannot be functions. */ + literal_p->type = (uint8_t) (type & ~SCANNER_LITERAL_IS_FUNC); + no_declarations--; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (type & SCANNER_LITERAL_IS_LOCAL) + { + /* Catch parameters cannot be functions. */ + literal_p->type = (uint8_t) (type & ~SCANNER_LITERAL_IS_FUNC); + no_declarations--; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p); + + if (diff >= 1 && diff <= UINT8_MAX) + { + compressed_size += 2 + 1; + } + else if (diff >= -UINT8_MAX && diff <= UINT16_MAX) + { + compressed_size += 2 + 2; + } + else + { + compressed_size += 2 + 1 + sizeof (const uint8_t *); + } + + prev_source_p = literal_p->char_p + literal_p->length; + + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) +#if ENABLED (JERRY_ES2015) + || ((type & SCANNER_LITERAL_IS_FUNC) && (status_flags & SCANNER_LITERAL_POOL_IS_STRICT)) +#endif /* ENABLED (JERRY_ES2015) */ + || !(type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC))) + { + continue; + } + } + + if (prev_literal_pool_p != NULL && literal_p->length > 0) + { + /* Propagate literal to upper level. */ + lexer_lit_location_t *literal_location_p = scanner_add_custom_literal (context_p, + prev_literal_pool_p, + literal_p); + uint8_t extended_type = literal_location_p->type; + + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) || (type & SCANNER_LITERAL_NO_REG)) + { + extended_type |= SCANNER_LITERAL_NO_REG; + } + +#if ENABLED (JERRY_ES2015) + extended_type |= SCANNER_LITERAL_IS_USED; + + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) + { + extended_type |= SCANNER_LITERAL_EARLY_CREATE; + } + + const uint8_t mask = (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_LOCAL); + + if ((type & SCANNER_LITERAL_IS_ARG) + || (literal_location_p->type & mask) == SCANNER_LITERAL_IS_LET + || (literal_location_p->type & mask) == SCANNER_LITERAL_IS_CONST) + { + /* Clears the SCANNER_LITERAL_IS_VAR and SCANNER_LITERAL_IS_FUNC flags + * for speculative arrow parameters and local (non-var) functions. */ + type = 0; + } +#endif /* ENABLED (JERRY_ES2015) */ + + type = (uint8_t) (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC)); + JERRY_ASSERT (type == 0 || !(status_flags & SCANNER_LITERAL_POOL_FUNCTION)); + + literal_location_p->type = (uint8_t) (extended_type | type); + } + } + + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) || (compressed_size > 1)) + { + compressed_size += sizeof (scanner_info_t); + + scanner_info_t *info_p; + + if (prev_literal_pool_p != NULL || scanner_context_p->end_arguments_p == NULL) + { + info_p = scanner_insert_info (context_p, literal_pool_p->source_p, compressed_size); + } + else + { + scanner_info_t *start_info_p = scanner_context_p->end_arguments_p; + info_p = scanner_insert_info_before (context_p, literal_pool_p->source_p, start_info_p, compressed_size); + } + + if (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK) + { + no_declarations = PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK; + } + + uint8_t *data_p = (uint8_t *) (info_p + 1); + + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION) + { + info_p->type = SCANNER_TYPE_FUNCTION; + + uint8_t u8_arg = 0; + + if (arguments_required) + { + u8_arg |= SCANNER_FUNCTION_ARGUMENTS_NEEDED; + + if (no_declarations < PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK) + { + no_declarations++; + } + +#if ENABLED (JERRY_ES2015) + const uint16_t is_unmapped = SCANNER_LITERAL_POOL_IS_STRICT | SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; +#else /* !ENABLED (JERRY_ES2015) */ + const uint16_t is_unmapped = SCANNER_LITERAL_POOL_IS_STRICT; +#endif /* ENABLED (JERRY_ES2015) */ + + if (status_flags & is_unmapped) + { + arguments_required = false; + } + else + { + u8_arg |= SCANNER_FUNCTION_MAPPED_ARGUMENTS; + } + } + +#if ENABLED (JERRY_ES2015) + if (status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + u8_arg |= SCANNER_FUNCTION_ASYNC; + + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) + { + u8_arg |= SCANNER_FUNCTION_STATEMENT; + } + } + + if (status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) + { + u8_arg |= SCANNER_FUNCTION_LEXICAL_ENV_NEEDED; + } +#endif /* ENABLED (JERRY_ES2015) */ + + info_p->u8_arg = u8_arg; + info_p->u16_arg = (uint16_t) no_declarations; + } + else + { + info_p->type = SCANNER_TYPE_BLOCK; + + JERRY_ASSERT (prev_literal_pool_p != NULL); + } + + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + prev_source_p = literal_pool_p->source_p - 1; + no_declarations = literal_pool_p->no_declarations; + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK) + || (!(literal_p->type & SCANNER_LITERAL_IS_LOCAL) + && (!(literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) + || !(status_flags & SCANNER_LITERAL_POOL_FUNCTION)))) + { + continue; + } + + if (literal_p->length == 0) + { + *data_p++ = SCANNER_STREAM_TYPE_HOLE; + continue; + } + + no_declarations++; + + uint8_t type = SCANNER_STREAM_TYPE_VAR; + + if (literal_p->type & SCANNER_LITERAL_IS_FUNC) + { + no_declarations++; + type = SCANNER_STREAM_TYPE_FUNC; + + if (literal_p->type & SCANNER_LITERAL_IS_ARG) + { + type = SCANNER_STREAM_TYPE_ARG_FUNC; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + type = SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + } + else if (literal_p->type & SCANNER_LITERAL_IS_ARG) + { + type = SCANNER_STREAM_TYPE_ARG; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + type = SCANNER_STREAM_TYPE_DESTRUCTURED_ARG; + } + + if (literal_p->type & SCANNER_LITERAL_IS_VAR) + { + type = (uint8_t) (type + 1); + + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_ARG_VAR + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR); + } +#endif /* ENABLED (JERRY_ES2015) */ + } +#if ENABLED (JERRY_ES2015) + else if (literal_p->type & SCANNER_LITERAL_IS_LET) + { + if (!(literal_p->type & SCANNER_LITERAL_IS_CONST)) + { + type = SCANNER_STREAM_TYPE_LET; + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && (literal_p->type & SCANNER_LITERAL_NO_REG)) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + else if (prev_literal_pool_p == NULL) + { + type = SCANNER_STREAM_TYPE_IMPORT; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + else + { + type = SCANNER_STREAM_TYPE_LOCAL; + } + } + else if (literal_p->type & SCANNER_LITERAL_IS_CONST) + { + type = SCANNER_STREAM_TYPE_CONST; + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && (literal_p->type & SCANNER_LITERAL_NO_REG)) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + } + + if (literal_p->type & SCANNER_LITERAL_EARLY_CREATE) + { + type |= SCANNER_STREAM_NO_REG | SCANNER_STREAM_EARLY_CREATE; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (literal_p->has_escape) + { + type |= SCANNER_STREAM_HAS_ESCAPE; + } + + if ((literal_p->type & SCANNER_LITERAL_NO_REG) + || (arguments_required && (literal_p->type & SCANNER_LITERAL_IS_ARG))) + { + type |= SCANNER_STREAM_NO_REG; + } + + data_p[0] = type; + data_p[1] = (uint8_t) literal_p->length; + data_p += 3; + + intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p); + + if (diff >= 1 && diff <= UINT8_MAX) + { + data_p[-1] = (uint8_t) diff; + } + else if (diff >= -UINT8_MAX && diff <= UINT16_MAX) + { + if (diff < 0) + { + diff = -diff; + } + + data_p[-3] |= SCANNER_STREAM_UINT16_DIFF; + data_p[-1] = (uint8_t) diff; + data_p[0] = (uint8_t) (diff >> 8); + data_p += 1; + } + else + { + data_p[-1] = 0; + memcpy (data_p, &literal_p->char_p, sizeof (const uint8_t *)); + data_p += sizeof (const uint8_t *); + } + + prev_source_p = literal_p->char_p + literal_p->length; + } + + data_p[0] = SCANNER_STREAM_TYPE_END; + + JERRY_ASSERT (((uint8_t *) info_p) + compressed_size == data_p + 1); + } + + if (!(status_flags & SCANNER_LITERAL_POOL_FUNCTION) + && prev_literal_pool_p->no_declarations < no_declarations) + { + prev_literal_pool_p->no_declarations = (uint16_t) no_declarations; + } + + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) && prev_literal_pool_p != NULL) + { + if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IS_STRICT) + { + context_p->status_flags |= PARSER_IS_STRICT; + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; + } + +#if ENABLED (JERRY_ES2015) + if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; + } + + if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_ASYNC_FUNCTION; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + scanner_context_p->active_literal_pool_p = literal_pool_p->prev_p; + + parser_list_free (&literal_pool_p->literal_pool); + scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t)); +} /* scanner_pop_literal_pool */ + +/** + * Filter out the arguments from a literal pool. + */ +void +scanner_filter_arguments (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + /* Fast case: check whether all literals are arguments. */ + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p; + parser_list_iterator_t literal_iterator; + lexer_lit_location_t *literal_p; + bool can_eval = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) != 0; + bool has_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0; + + if (can_eval && prev_literal_pool_p != NULL) + { + prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + } + + literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_CAN_EVAL; + + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { +#if ENABLED (JERRY_ES2015) + if (can_eval || (literal_p->type & SCANNER_LITERAL_EARLY_CREATE)) + { + literal_p->type |= SCANNER_LITERAL_NO_REG | SCANNER_LITERAL_EARLY_CREATE; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (can_eval) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } +#endif /* ENABLED (JERRY_ES2015) */ + + uint8_t type = literal_p->type; + + if (!(type & SCANNER_LITERAL_IS_ARG) && !(has_arguments && scanner_literal_is_arguments (literal_p))) + { + break; + } + +#if ENABLED (JERRY_ES2015) + if (type & (SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + if (literal_p == NULL) + { + return; + } + + scanner_literal_pool_t *new_literal_pool_p; + + new_literal_pool_p = (scanner_literal_pool_t *) scanner_malloc (context_p, sizeof (scanner_literal_pool_t)); + + new_literal_pool_p->prev_p = literal_pool_p; + scanner_context_p->active_literal_pool_p = new_literal_pool_p; + + *new_literal_pool_p = *literal_pool_p; + parser_list_init (&new_literal_pool_p->literal_pool, + sizeof (lexer_lit_location_t), + (uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_lit_location_t))); + + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + +#if ENABLED (JERRY_ES2015) + /* Destructured args are placed after the other arguments because of register assignments. */ + bool has_destructured_arg = false; +#endif /* ENABLED (JERRY_ES2015) */ + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + uint8_t type = literal_p->type; + + if ((type & SCANNER_LITERAL_IS_ARG) || (has_arguments && scanner_literal_is_arguments (literal_p))) + { +#if ENABLED (JERRY_ES2015) + if (can_eval || (literal_p->type & SCANNER_LITERAL_EARLY_CREATE)) + { + type |= SCANNER_LITERAL_NO_REG | SCANNER_LITERAL_EARLY_CREATE; + literal_p->type = type; + } + + if (type & (SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG)) + { + has_destructured_arg = true; + + if (type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + continue; + } + + type &= (uint8_t) ~SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG; + type |= SCANNER_LITERAL_IS_DESTRUCTURED_ARG; + + literal_p->type = type; + continue; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (can_eval) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_lit_location_t *new_literal_p; + new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool); + *new_literal_p = *literal_p; + } + else if (prev_literal_pool_p != NULL) + { + /* Propagate literal to upper level. */ + lexer_lit_location_t *literal_location_p = scanner_add_custom_literal (context_p, + prev_literal_pool_p, + literal_p); + type |= SCANNER_LITERAL_NO_REG; + +#if ENABLED (JERRY_ES2015) + type |= SCANNER_LITERAL_IS_USED; +#endif /* ENABLED (JERRY_ES2015) */ + + literal_location_p->type |= type; + } + } + +#if ENABLED (JERRY_ES2015) + if (has_destructured_arg) + { + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + const uint8_t expected_flags = SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG; + + if ((literal_p->type & expected_flags) == expected_flags) + { + lexer_lit_location_t *new_literal_p; + new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool); + *new_literal_p = *literal_p; + } + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + new_literal_pool_p->prev_p = prev_literal_pool_p; + + parser_list_free (&literal_pool_p->literal_pool); + scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t)); +} /* scanner_filter_arguments */ + +/** + * Add any literal to the specified literal pool. + * + * @return pointer to the literal + */ +lexer_lit_location_t * +scanner_add_custom_literal (parser_context_t *context_p, /**< context */ + scanner_literal_pool_t *literal_pool_p, /**< literal pool */ + const lexer_lit_location_t *literal_location_p) /**< literal */ +{ + parser_list_iterator_t literal_iterator; + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + lexer_lit_location_t *literal_p; + + const uint8_t *char_p = literal_location_p->char_p; + prop_length_t length = literal_location_p->length; + + if (JERRY_LIKELY (!literal_location_p->has_escape)) + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (literal_p->length == length) + { + if (JERRY_LIKELY (!literal_p->has_escape)) + { + if (memcmp (literal_p->char_p, char_p, length) == 0) + { + return literal_p; + } + } + else if (lexer_compare_identifier_to_string (literal_p, char_p, length)) + { + /* The non-escaped version is preferred. */ + literal_p->char_p = char_p; + literal_p->has_escape = 0; + return literal_p; + } + } + } + } + else + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (lexer_compare_identifiers (context_p, literal_p, literal_location_p)) + { + return literal_p; + } + } + } + + literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool); + *literal_p = *literal_location_p; + + literal_p->type = 0; + + return literal_p; +} /* scanner_add_custom_literal */ + +/** + * Add the current literal token to the current literal pool. + * + * @return pointer to the literal + */ +inline lexer_lit_location_t * JERRY_ATTR_ALWAYS_INLINE +scanner_add_literal (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + return scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &context_p->token.lit_location); +} /* scanner_add_literal */ + +/** + * Add the current literal token to the current literal pool and + * set SCANNER_LITERAL_NO_REG if it is inside a with statement. + * + * @return pointer to the literal + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_add_reference (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &context_p->token.lit_location); +#if ENABLED (JERRY_ES2015) + lit_location_p->type |= SCANNER_LITERAL_IS_USED; +#endif /* ENABLED (JERRY_ES2015) */ + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } + + scanner_detect_eval_call (context_p, scanner_context_p); +} /* scanner_add_reference */ + +/** + * Append an argument to the literal pool. If the argument is already present, make it a "hole". + * + * @return newly created literal + */ +lexer_lit_location_t * +scanner_append_argument (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + parser_list_iterator_t literal_iterator; + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + lexer_lit_location_t *literal_location_p = &context_p->token.lit_location; + lexer_lit_location_t *literal_p; + + const uint8_t *char_p = literal_location_p->char_p; + prop_length_t length = literal_location_p->length; + + if (JERRY_LIKELY (!context_p->token.lit_location.has_escape)) + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (literal_p->length == length) + { + if (JERRY_LIKELY (!literal_p->has_escape)) + { + if (memcmp (literal_p->char_p, char_p, length) == 0) + { + break; + } + } + else if (lexer_compare_identifier_to_string (literal_p, char_p, length)) + { + break; + } + } + } + } + else + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (lexer_compare_identifiers (context_p, literal_p, literal_location_p)) + { + break; + } + } + } + + uint8_t literal_type = SCANNER_LITERAL_IS_ARG; + + if (literal_p != NULL) + { + literal_p->length = 0; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_type = SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_EARLY_CREATE; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + + literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool); + + *literal_p = context_p->token.lit_location; + literal_p->type = literal_type; + + return literal_p; +} /* scanner_append_argument */ + +/** + * Check whether an eval call is performed and update the status flags accordingly. + */ +void +scanner_detect_eval_call (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + if (context_p->token.keyword_type == LEXER_KEYW_EVAL + && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) + { + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + } +} /* scanner_detect_eval_call */ + +#if ENABLED (JERRY_ES2015) + +/** + * Find a let/const declaration of a given literal. + * + * @return true - if the literal is found, false - otherwise + */ +bool +scanner_scope_find_let_declaration (parser_context_t *context_p, /**< context */ + lexer_lit_location_t *literal_p) /**< literal */ +{ + ecma_string_t *name_p; + + if (JERRY_LIKELY (!literal_p->has_escape)) + { + name_p = ecma_new_ecma_string_from_utf8 (literal_p->char_p, literal_p->length); + } + else + { + uint8_t *destination_p = (uint8_t *) scanner_malloc (context_p, literal_p->length); + + lexer_convert_ident_to_cesu8 (destination_p, literal_p->char_p, literal_p->length); + + name_p = ecma_new_ecma_string_from_utf8 (destination_p, literal_p->length); + scanner_free (destination_p, literal_p->length); + } + + ecma_object_t *lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p; + + while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p != NULL && ecma_is_property_enumerable (*property_p)) + { + ecma_deref_ecma_string (name_p); + return true; + } + } + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p != NULL && ecma_is_property_enumerable (*property_p)) + { + ecma_deref_ecma_string (name_p); + return true; + } + } + + ecma_deref_ecma_string (name_p); + return false; +} /* scanner_scope_find_let_declaration */ + +/** + * Throws an error for invalid var statements. + */ +void +scanner_detect_invalid_var (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + lexer_lit_location_t *var_literal_p) /**< var literal */ +{ + if (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL + && !(var_literal_p->type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_ARG)) + && (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL) + { + scanner_raise_redeclaration_error (context_p); + } + + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + const uint8_t *char_p = var_literal_p->char_p; + prop_length_t length = var_literal_p->length; + + while (!(literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION)) + { + literal_pool_p = literal_pool_p->prev_p; + + parser_list_iterator_t literal_iterator; + parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); + lexer_lit_location_t *literal_p; + + if (JERRY_LIKELY (!context_p->token.lit_location.has_escape)) + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (literal_p->type & SCANNER_LITERAL_IS_LOCAL + && !(literal_p->type & SCANNER_LITERAL_IS_ARG) + && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL + && literal_p->length == length) + { + if (JERRY_LIKELY (!literal_p->has_escape)) + { + if (memcmp (literal_p->char_p, char_p, length) == 0) + { + scanner_raise_redeclaration_error (context_p); + return; + } + } + else if (lexer_compare_identifier_to_string (literal_p, char_p, length)) + { + scanner_raise_redeclaration_error (context_p); + return; + } + } + } + } + else + { + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if (literal_p->type & SCANNER_LITERAL_IS_LOCAL + && !(literal_p->type & SCANNER_LITERAL_IS_ARG) + && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL + && lexer_compare_identifiers (context_p, literal_p, var_literal_p)) + { + scanner_raise_redeclaration_error (context_p); + return; + } + } + } + } + + if ((context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) + && scanner_scope_find_let_declaration (context_p, var_literal_p)) + { + scanner_raise_redeclaration_error (context_p); + } +} /* scanner_detect_invalid_var */ + +/** + * Throws an error for invalid let statements. + */ +void +scanner_detect_invalid_let (parser_context_t *context_p, /**< context */ + lexer_lit_location_t *let_literal_p) /**< let literal */ +{ + if (let_literal_p->type & (SCANNER_LITERAL_IS_ARG + | SCANNER_LITERAL_IS_VAR + | SCANNER_LITERAL_IS_LOCAL)) + { + scanner_raise_redeclaration_error (context_p); + } + + if (let_literal_p->type & SCANNER_LITERAL_IS_FUNC) + { + let_literal_p->type &= (uint8_t) ~SCANNER_LITERAL_IS_FUNC; + } +} /* scanner_detect_invalid_let */ + +/** + * Push the values required for class declaration parsing. + */ +void +scanner_push_class_declaration (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /* scanner context */ + uint8_t stack_mode) /**< stack mode */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS); + + parser_stack_push_uint8 (context_p, stack_mode); + scanner_source_start_t source_start; + source_start.source_p = context_p->source_p; + + parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR); + scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; + + lexer_next_token (context_p); +} /* scanner_push_class_declaration */ + +/** + * Push the values required for destructuring assignment or binding parsing. + */ +void +scanner_push_destructuring_pattern (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + uint8_t binding_type, /**< type of destructuring binding pattern */ + bool is_nested) /**< nested declaration */ +{ + JERRY_ASSERT (binding_type != SCANNER_BINDING_NONE || !is_nested); + + scanner_source_start_t source_start; + source_start.source_p = context_p->source_p; + + parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t)); + parser_stack_push_uint8 (context_p, scanner_context_p->binding_type); + scanner_context_p->binding_type = binding_type; + + if (SCANNER_NEEDS_BINDING_LIST (binding_type)) + { + scanner_binding_list_t *binding_list_p; + binding_list_p = (scanner_binding_list_t *) scanner_malloc (context_p, sizeof (scanner_binding_list_t)); + + binding_list_p->prev_p = scanner_context_p->active_binding_list_p; + binding_list_p->items_p = NULL; + binding_list_p->is_nested = is_nested; + + scanner_context_p->active_binding_list_p = binding_list_p; + } +} /* scanner_push_destructuring_pattern */ + +/** + * Pop binding list. + */ +void +scanner_pop_binding_list (scanner_context_t *scanner_context_p) /**< scanner context */ +{ + scanner_binding_list_t *binding_list_p = scanner_context_p->active_binding_list_p; + scanner_binding_item_t *item_p = binding_list_p->items_p; + scanner_binding_list_t *prev_binding_list_p = binding_list_p->prev_p; + bool is_nested = binding_list_p->is_nested; + + scanner_free (binding_list_p, sizeof (scanner_binding_list_t)); + scanner_context_p->active_binding_list_p = prev_binding_list_p; + + JERRY_ASSERT (binding_list_p != NULL); + + if (!is_nested) + { + while (item_p != NULL) + { + scanner_binding_item_t *next_p = item_p->next_p; + + JERRY_ASSERT (item_p->literal_p->type & (SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_IS_ARG)); + + scanner_free (item_p, sizeof (scanner_binding_item_t)); + item_p = next_p; + } + return; + } + + JERRY_ASSERT (prev_binding_list_p != NULL); + + while (item_p != NULL) + { + scanner_binding_item_t *next_p = item_p->next_p; + + item_p->next_p = prev_binding_list_p->items_p; + prev_binding_list_p->items_p = item_p; + + item_p = next_p; + } +} /* scanner_pop_binding_list */ + +/** + * Append a hole into the literal pool. + */ +void +scanner_append_hole (parser_context_t *context_p, scanner_context_t *scanner_context_p) +{ + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + + lexer_lit_location_t *literal_p; + literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool); + + literal_p->char_p = NULL; + literal_p->length = 0; + literal_p->type = SCANNER_LITERAL_IS_ARG; + literal_p->has_escape = 0; +} /* scanner_append_hole */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Reverse the scanner info chain after the scanning is completed. */ @@ -282,12 +1617,21 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ scanner_info_p = context_p->active_scanner_info_p; continue; } + case SCANNER_TYPE_FUNCTION: + case SCANNER_TYPE_BLOCK: + { + size = scanner_get_stream_size (scanner_info_p, sizeof (scanner_info_t)); + break; + } case SCANNER_TYPE_WHILE: case SCANNER_TYPE_FOR_IN: -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case SCANNER_TYPE_FOR_OF: -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ case SCANNER_TYPE_CASE: +#if ENABLED (JERRY_ES2015) + case SCANNER_TYPE_INITIALIZER: +#endif /* ENABLED (JERRY_ES2015) */ { size = sizeof (scanner_location_info_t); break; @@ -305,12 +1649,15 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ } default: { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS - || scanner_info_p->type == SCANNER_TYPE_ARROW); -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION + || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR + || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED + || scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ break; } } @@ -323,6 +1670,792 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ context_p->active_scanner_info_p = NULL; } /* scanner_cleanup */ +/** + * Checks whether a context needs to be created for a block. + * + * @return true - if context is needed, + * false - otherwise + */ +bool +scanner_is_context_needed (parser_context_t *context_p, /**< context */ + parser_check_context_type_t check_type) /**< context type */ +{ + scanner_info_t *info_p = context_p->next_scanner_info_p; + const uint8_t *data_p = (const uint8_t *) (info_p + 1); + + JERRY_UNUSED (check_type); + +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT ((check_type == PARSER_CHECK_BLOCK_CONTEXT ? info_p->type == SCANNER_TYPE_BLOCK + : info_p->type == SCANNER_TYPE_FUNCTION)); + + uint32_t scope_stack_reg_top = (check_type != PARSER_CHECK_GLOBAL_CONTEXT ? context_p->scope_stack_reg_top + : 0); +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (check_type == PARSER_CHECK_BLOCK_CONTEXT); + JERRY_ASSERT (info_p->type == SCANNER_TYPE_BLOCK); + + uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top; +#endif /* !JERRY_NDEBUG */ + + while (data_p[0] != SCANNER_STREAM_TYPE_END) + { + uint8_t data = data_p[0]; + +#if ENABLED (JERRY_ES2015) + uint32_t type = data & SCANNER_STREAM_TYPE_MASK; + + if (JERRY_UNLIKELY (type == SCANNER_STREAM_TYPE_HOLE)) + { + JERRY_ASSERT (check_type == PARSER_CHECK_FUNCTION_CONTEXT); + data_p++; + continue; + } + +#ifndef JERRY_NDEBUG + if (check_type == PARSER_CHECK_BLOCK_CONTEXT) + { + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_LOCAL + || type == SCANNER_STREAM_TYPE_FUNC); + } + else if (check_type == PARSER_CHECK_GLOBAL_CONTEXT) + { + /* FIXME: a private declarative lexical environment should always be present + * for modules. Remove SCANNER_STREAM_TYPE_IMPORT after it is implemented. */ + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_FUNC + || type == SCANNER_STREAM_TYPE_IMPORT); + + /* Only let/const can be stored in registers */ + JERRY_ASSERT ((data & SCANNER_STREAM_NO_REG) + || (type == SCANNER_STREAM_TYPE_FUNC && (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST); + } + else + { + JERRY_ASSERT (check_type == PARSER_CHECK_FUNCTION_CONTEXT); + + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_LOCAL + || type == SCANNER_STREAM_TYPE_ARG + || type == SCANNER_STREAM_TYPE_ARG_VAR + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR + || type == SCANNER_STREAM_TYPE_ARG_FUNC + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC + || type == SCANNER_STREAM_TYPE_FUNC); + } +#endif /* !JERRY_NDEBUG */ + +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT ((data & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_VAR); +#endif /* ENABLED (JERRY_ES2015) */ + + if (!(data & SCANNER_STREAM_UINT16_DIFF)) + { + if (data_p[2] != 0) + { + data_p += 2 + 1; + } + else + { + data_p += 2 + 1 + sizeof (const uint8_t *); + } + } + else + { + data_p += 2 + 2; + } + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (check_type == PARSER_CHECK_GLOBAL_CONTEXT) + && (type == SCANNER_STREAM_TYPE_VAR + || (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + || type == SCANNER_STREAM_TYPE_IMPORT)) + { + continue; + } + + if (JERRY_UNLIKELY (check_type == PARSER_CHECK_FUNCTION_CONTEXT)) + { + if (SCANNER_STREAM_TYPE_IS_ARG_FUNC (type) + || type == SCANNER_STREAM_TYPE_ARG_VAR + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR) + { + /* The return value is true, if the variable is stored in the lexical environment + * or all registers have already been used for function arguments. This can be + * inprecise in the latter case, but this is a very rare corner case. A more + * sophisticated check would require to decode the literal. */ + if ((data & SCANNER_STREAM_NO_REG) + || scope_stack_reg_top >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + return true; + } + continue; + } + + if (SCANNER_STREAM_TYPE_IS_ARG (type)) + { + continue; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + if ((data & SCANNER_STREAM_NO_REG) + || scope_stack_reg_top >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + return true; + } + + scope_stack_reg_top++; + } + + return false; +} /* scanner_is_context_needed */ + +#if ENABLED (JERRY_ES2015) + +/** + * Try to scan/parse the ".target" part in the "new.target" expression. + * + * Upon exiting with "true" the current token will point to the "target" + * literal. + * + * If the "target" literal is not after the "new." then a scanner/parser + * error will be raised. + * + * @returns true if the ".target" part was found + * false if there is no "." after the new. + */ +bool +scanner_try_scan_new_target (parser_context_t *context_p) /**< parser/scanner context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_NEW); + + if (lexer_check_next_character (context_p, LIT_CHAR_DOT)) + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_DOT) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); + } + + lexer_next_token (context_p); + if (!lexer_token_is_identifier (context_p, "target", 6)) + { + parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_EXPECTED); + } + + return true; + } + return false; +} /* scanner_try_scan_new_target */ + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Description of "arguments" literal string. + */ +const lexer_lit_location_t lexer_arguments_literal = +{ + (const uint8_t *) "arguments", 9, LEXER_IDENT_LITERAL, false +}; + +/** + * Create an unused literal. + */ +static void +scanner_create_unused_literal (parser_context_t *context_p, /**< context */ + uint8_t status_flags) /**< initial status flags */ +{ + if (JERRY_UNLIKELY (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)) + { + parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); + } + + lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); + + literal_p->type = LEXER_UNUSED_LITERAL; + literal_p->status_flags = status_flags; + + context_p->literal_count++; +} /* scanner_create_unused_literal */ + +#if ENABLED (JERRY_ES2015) +/** + * Emit checks for redeclared bindings in the global lexical scope. + */ +void +scanner_check_variables (parser_context_t *context_p) /**< context */ +{ + scanner_info_t *info_p = context_p->next_scanner_info_p; + const uint8_t *next_data_p = (const uint8_t *) (info_p + 1); + lexer_lit_location_t literal; + + JERRY_ASSERT (info_p->type == SCANNER_TYPE_FUNCTION); + + literal.char_p = info_p->source_p - 1; + + while (next_data_p[0] != SCANNER_STREAM_TYPE_END) + { + uint32_t type = next_data_p[0] & SCANNER_STREAM_TYPE_MASK; + const uint8_t *data_p = next_data_p; + + JERRY_ASSERT (type != SCANNER_STREAM_TYPE_HOLE + && !SCANNER_STREAM_TYPE_IS_ARG (type) + && !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)); + JERRY_ASSERT (data_p[0] & SCANNER_STREAM_NO_REG); + + if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF)) + { + if (data_p[2] != 0) + { + literal.char_p += data_p[2]; + next_data_p += 2 + 1; + } + else + { + memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *)); + next_data_p += 2 + 1 + sizeof (const uint8_t *); + } + } + else + { + int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8; + + if (diff <= UINT8_MAX) + { + diff = -diff; + } + + literal.char_p += diff; + next_data_p += 2 + 2; + } + + literal.length = data_p[1]; + literal.type = LEXER_IDENT_LITERAL; + literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0; + + lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL); + literal.char_p += data_p[1]; + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (type == SCANNER_STREAM_TYPE_IMPORT) + { + continue; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED; + + uint16_t opcode; + if (type == SCANNER_STREAM_TYPE_VAR || type == SCANNER_STREAM_TYPE_FUNC) + { + opcode = CBC_CHECK_VAR; + } + else + { + opcode = CBC_CHECK_LET; + } + + parser_emit_cbc_literal (context_p, opcode, context_p->lit_object.index); + } + + parser_flush_cbc (context_p); +} /* scanner_check_variables */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Create and/or initialize var/let/const/function/etc. variables. + */ +void +scanner_create_variables (parser_context_t *context_p, /**< context */ + uint32_t option_flags) /**< combination of scanner_create_variables_flags_t bits */ +{ + scanner_info_t *info_p = context_p->next_scanner_info_p; + const uint8_t *next_data_p = (const uint8_t *) (info_p + 1); + uint8_t info_type = info_p->type; + uint8_t info_u8_arg = info_p->u8_arg; + lexer_lit_location_t literal; + parser_scope_stack_t *scope_stack_p; + parser_scope_stack_t *scope_stack_end_p; + + JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION || info_type == SCANNER_TYPE_BLOCK); + JERRY_ASSERT (!(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS) + || !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)); + JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION + || !(option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_ARGS | SCANNER_CREATE_VARS_IS_FUNCTION_BODY))); + + if (info_type == SCANNER_TYPE_FUNCTION && !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)) + { + JERRY_ASSERT (context_p->scope_stack_p == NULL); + + size_t stack_size = info_p->u16_arg * sizeof (parser_scope_stack_t); + context_p->scope_stack_size = info_p->u16_arg; + + scope_stack_p = NULL; + + if (stack_size > 0) + { + scope_stack_p = (parser_scope_stack_t *) parser_malloc (context_p, stack_size); + } + + context_p->scope_stack_p = scope_stack_p; + scope_stack_end_p = scope_stack_p + context_p->scope_stack_size; + } + else + { + JERRY_ASSERT (context_p->scope_stack_p != NULL || context_p->scope_stack_size == 0); + + scope_stack_p = context_p->scope_stack_p; + scope_stack_end_p = scope_stack_p + context_p->scope_stack_size; + scope_stack_p += context_p->scope_stack_top; + } + + uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top; + + literal.char_p = info_p->source_p - 1; + + while (next_data_p[0] != SCANNER_STREAM_TYPE_END) + { + uint32_t type = next_data_p[0] & SCANNER_STREAM_TYPE_MASK; + const uint8_t *data_p = next_data_p; + + JERRY_ASSERT ((option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_BODY | SCANNER_CREATE_VARS_IS_FUNCTION_ARGS)) + || (type != SCANNER_STREAM_TYPE_HOLE + && !SCANNER_STREAM_TYPE_IS_ARG (type) + && !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type))); + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + JERRY_ASSERT (type != SCANNER_STREAM_TYPE_IMPORT || (data_p[0] & SCANNER_STREAM_NO_REG)); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + if (type == SCANNER_STREAM_TYPE_HOLE) + { + next_data_p++; + + if (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY) + { + continue; + } + + if (info_u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) + { + scanner_create_unused_literal (context_p, LEXER_FLAG_FUNCTION_ARGUMENT); + } + + if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + scope_stack_reg_top++; + } + continue; + } + + JERRY_ASSERT (context_p->scope_stack_size != 0); + + if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF)) + { + if (data_p[2] != 0) + { + literal.char_p += data_p[2]; + next_data_p += 2 + 1; + } + else + { + memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *)); + next_data_p += 2 + 1 + sizeof (const uint8_t *); + } + } + else + { + int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8; + + if (diff <= UINT8_MAX) + { + diff = -diff; + } + + literal.char_p += diff; + next_data_p += 2 + 2; + } + + if (SCANNER_STREAM_TYPE_IS_ARG (type)) + { + if (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY) + { +#if ENABLED (JERRY_ES2015) + if ((context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) + && (type == SCANNER_STREAM_TYPE_ARG_VAR || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR)) + { + literal.length = data_p[1]; + literal.type = LEXER_IDENT_LITERAL; + literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0; + + /* Literal must be exists. */ + lexer_construct_literal_object (context_p, &literal, LEXER_IDENT_LITERAL); + + if (context_p->lit_object.index < PARSER_REGISTER_START) + { + parser_emit_cbc_ext_literal_from_token (context_p, CBC_EXT_COPY_FROM_ARG); + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + literal.char_p += data_p[1]; + continue; + } + } + else if ((option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS) + && !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)) + { + /* Function arguments must come first. */ + break; + } + + literal.length = data_p[1]; + literal.type = LEXER_IDENT_LITERAL; + literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0; + + lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL); + literal.char_p += data_p[1]; + + if (SCANNER_STREAM_TYPE_IS_ARG_FUNC (type) && (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)) + { + JERRY_ASSERT (scope_stack_p >= context_p->scope_stack_p + 2); + JERRY_ASSERT (context_p->status_flags & PARSER_IS_FUNCTION); +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (!(context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS)); +#endif /* ENABLED (JERRY_ES2015) */ + + parser_scope_stack_t *function_map_p = scope_stack_p - 2; + uint16_t literal_index = context_p->lit_object.index; + + while (literal_index != function_map_p->map_from) + { + function_map_p--; + + JERRY_ASSERT (function_map_p >= context_p->scope_stack_p); + } + + JERRY_ASSERT (function_map_p[1].map_from == PARSER_SCOPE_STACK_FUNC); + + cbc_opcode_t opcode = CBC_SET_VAR_FUNC; + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) + && (function_map_p[0].map_to & PARSER_SCOPE_STACK_REGISTER_MASK) == 0) + { + opcode = CBC_INIT_ARG_OR_FUNC; + } +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc_literal_value (context_p, + (uint16_t) opcode, + function_map_p[1].map_to, + scanner_decode_map_to (function_map_p)); + continue; + } + + if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p)) + { + JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK); + parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED); + } + + scope_stack_p->map_from = context_p->lit_object.index; + +#if ENABLED (JERRY_ES2015) + if (info_type == SCANNER_TYPE_FUNCTION) + { + if (type != SCANNER_STREAM_TYPE_LET +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + && type != SCANNER_STREAM_TYPE_IMPORT +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + && type != SCANNER_STREAM_TYPE_CONST) + { + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_GLOBAL; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + uint16_t map_to; + uint16_t func_init_opcode = CBC_INIT_ARG_OR_FUNC; + + if (!(data_p[0] & SCANNER_STREAM_NO_REG) + && scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + map_to = (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top); + +#if ENABLED (JERRY_ES2015) + scope_stack_p->map_to = (uint16_t) (scope_stack_reg_top + 1); +#else /* !ENABLED (JERRY_ES2015) */ + scope_stack_p->map_to = map_to; +#endif /* ENABLED (JERRY_ES2015) */ + + scope_stack_reg_top++; +#if ENABLED (JERRY_ES2015) + switch (type) + { + case SCANNER_STREAM_TYPE_CONST: + { + scope_stack_p->map_to |= PARSER_SCOPE_STACK_IS_CONST_REG; + /* FALLTHRU */ + } + case SCANNER_STREAM_TYPE_LET: + case SCANNER_STREAM_TYPE_ARG: + case SCANNER_STREAM_TYPE_ARG_VAR: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR: + case SCANNER_STREAM_TYPE_ARG_FUNC: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: + { + scope_stack_p->map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; + break; + } + } + + func_init_opcode = CBC_SET_VAR_FUNC; +#endif /* ENABLED (JERRY_ES2015) */ + } + else + { + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED; + map_to = context_p->lit_object.index; + +#if ENABLED (JERRY_ES2015) + uint16_t scope_stack_map_to = 0; +#else /* !ENABLED (JERRY_ES2015) */ + scope_stack_p->map_to = map_to; +#endif /* ENABLED (JERRY_ES2015) */ + + if (info_type == SCANNER_TYPE_FUNCTION) + { + context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + } + + switch (type) + { +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_LET: + case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: + { + scope_stack_map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; + + if (!(data_p[0] & SCANNER_STREAM_EARLY_CREATE)) + { + break; + } + scope_stack_map_to |= PARSER_SCOPE_STACK_IS_LOCAL_CREATED; + /* FALLTHRU */ + } + case SCANNER_STREAM_TYPE_LOCAL: +#endif /* ENABLED (JERRY_ES2015) */ + case SCANNER_STREAM_TYPE_VAR: + { +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + +#if ENABLED (JERRY_ES2015) + uint16_t opcode; + + switch (type) + { + case SCANNER_STREAM_TYPE_LET: + { + opcode = CBC_CREATE_LET; + break; + } + case SCANNER_STREAM_TYPE_CONST: + { + opcode = CBC_CREATE_CONST; + break; + } + case SCANNER_STREAM_TYPE_VAR: + { + opcode = CBC_CREATE_VAR; + + if (option_flags & SCANNER_CREATE_VARS_IS_SCRIPT) + { + opcode = CBC_CREATE_VAR_EVAL; + + if (context_p->global_status_flags & ECMA_PARSE_FUNCTION_CONTEXT) + { + opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CREATE_VAR_EVAL); + } + } + break; + } + default: + { + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_LOCAL + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC); + + opcode = CBC_CREATE_LOCAL; + break; + } + } +#else /* !ENABLED (JERRY_ES2015) */ + uint16_t opcode = ((option_flags & SCANNER_CREATE_VARS_IS_SCRIPT) ? CBC_CREATE_VAR_EVAL + : CBC_CREATE_VAR); +#endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc_literal (context_p, opcode, map_to); + break; + } + case SCANNER_STREAM_TYPE_ARG: +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_ARG_VAR: +#endif /* ENABLED (JERRY_ES2015) */ + case SCANNER_STREAM_TYPE_ARG_FUNC: + { +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + +#if ENABLED (JERRY_ES2015) + scope_stack_map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; + + /* Argument initializers of functions with mapped arguments (e.g. function f(a,b,a) {}) are + * generated here. The other initializers are handled by parser_parse_function_arguments(). */ + if (info_u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) + { +#endif /* ENABLED (JERRY_ES2015) */ + parser_emit_cbc_literal_value (context_p, + CBC_INIT_ARG_OR_FUNC, + (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top), + map_to); +#if ENABLED (JERRY_ES2015) + } + else if (data_p[0] & SCANNER_STREAM_EARLY_CREATE) + { + parser_emit_cbc_literal (context_p, CBC_CREATE_LOCAL, map_to); + scope_stack_map_to |= PARSER_SCOPE_STACK_IS_LOCAL_CREATED; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + scope_stack_reg_top++; + } + break; + } + } + +#if ENABLED (JERRY_ES2015) + scope_stack_p->map_to = scope_stack_map_to; +#endif /* ENABLED (JERRY_ES2015) */ + } + + scope_stack_p++; + + if (!SCANNER_STREAM_TYPE_IS_FUNCTION (type)) + { + continue; + } + + if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p)) + { + JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK); + parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED); + } + +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + + if (!SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)) + { + if (func_init_opcode == CBC_INIT_ARG_OR_FUNC && (option_flags & SCANNER_CREATE_VARS_IS_SCRIPT)) + { +#if ENABLED (JERRY_ES2015) + literal.char_p -= data_p[1]; + if (!(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) + || !scanner_scope_find_let_declaration (context_p, &literal)) + { + func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL; + + if (context_p->global_status_flags & ECMA_PARSE_FUNCTION_CONTEXT) + { + func_init_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CREATE_VAR_FUNC_EVAL); + } + } + literal.char_p += data_p[1]; +#else /* !ENABLED (JERRY_ES2015) */ + func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL; +#endif /* ENABLED (JERRY_ES2015) */ + } + + parser_emit_cbc_literal_value (context_p, func_init_opcode, context_p->literal_count, map_to); + } + + scope_stack_p->map_from = PARSER_SCOPE_STACK_FUNC; + scope_stack_p->map_to = context_p->literal_count; + scope_stack_p++; + + scanner_create_unused_literal (context_p, 0); + } + + if (info_type == SCANNER_TYPE_FUNCTION + && !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY) + && (info_u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED)) + { + JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION); + + if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p)) + { + JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK); + parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED); + } + + context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED; + + lexer_construct_literal_object (context_p, &lexer_arguments_literal, lexer_arguments_literal.type); + + scope_stack_p->map_from = context_p->lit_object.index; +#if ENABLED (JERRY_ES2015) + scope_stack_p->map_to = 0; +#else /* !ENABLED (JERRY_ES2015) */ + scope_stack_p->map_to = context_p->lit_object.index; +#endif /* ENABLED (JERRY_ES2015) */ + scope_stack_p++; + } + + context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); + context_p->scope_stack_reg_top = (uint16_t) scope_stack_reg_top; + +#if ENABLED (JERRY_ES2015) + if (info_type == SCANNER_TYPE_FUNCTION) + { + context_p->scope_stack_global_end = context_p->scope_stack_top; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (context_p->register_count < scope_stack_reg_top) + { + context_p->register_count = (uint16_t) scope_stack_reg_top; + } + + if (!(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS)) + { + scanner_release_next (context_p, (size_t) (next_data_p + 1 - ((const uint8_t *) info_p))); + } + parser_flush_cbc (context_p); +} /* scanner_create_variables */ + /** * Get location from context. */ @@ -347,6 +2480,82 @@ scanner_set_location (parser_context_t *context_p, /**< context */ context_p->column = location_p->column; } /* scanner_set_location */ +/** + * Get the real map_to value. + */ +inline uint16_t JERRY_ATTR_ALWAYS_INLINE +scanner_decode_map_to (parser_scope_stack_t *stack_item_p) /**< scope stack item */ +{ + JERRY_ASSERT (stack_item_p->map_from != PARSER_SCOPE_STACK_FUNC); + +#if ENABLED (JERRY_ES2015) + uint16_t value = (stack_item_p->map_to & PARSER_SCOPE_STACK_REGISTER_MASK); + return (value == 0) ? stack_item_p->map_from : (uint16_t) (value + (PARSER_REGISTER_START - 1)); +#else /* !ENABLED (JERRY_ES2015) */ + return stack_item_p->map_to; +#endif /* ENABLED (JERRY_ES2015) */ +} /* scanner_decode_map_to */ + +#if ENABLED (JERRY_ES2015) + +/** + * Checks whether the literal is a const in the current scope. + * + * @return true if the literal is a const, false otherwise + */ +bool +scanner_literal_is_const_reg (parser_context_t *context_p, /**< context */ + uint16_t literal_index) /**< literal index */ +{ + if (literal_index < PARSER_REGISTER_START) + { + /* Re-assignment of non-register const bindings are detected elsewhere. */ + return false; + } + + parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top; + + literal_index = (uint16_t) (literal_index - (PARSER_REGISTER_START - 1)); + + do + { + /* Registers must be found in the scope stack. */ + JERRY_ASSERT (scope_stack_p > context_p->scope_stack_p); + scope_stack_p--; + } + while (literal_index != (scope_stack_p->map_to & PARSER_SCOPE_STACK_REGISTER_MASK)); + + return (scope_stack_p->map_to & PARSER_SCOPE_STACK_IS_CONST_REG) != 0; +} /* scanner_literal_is_const_reg */ + +/** + * Checks whether the literal is created before. + * + * @return true if the literal is created before, false otherwise + */ +bool +scanner_literal_is_created (parser_context_t *context_p, /**< context */ + uint16_t literal_index) /**< literal index */ +{ + JERRY_ASSERT (literal_index < PARSER_REGISTER_START); + + parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top; + + do + { + /* These literals must be found in the scope stack. */ + JERRY_ASSERT (scope_stack_p > context_p->scope_stack_p); + scope_stack_p--; + } + while (literal_index != scope_stack_p->map_from); + + JERRY_ASSERT ((scope_stack_p->map_to & PARSER_SCOPE_STACK_REGISTER_MASK) == 0); + + return (scope_stack_p->map_to & PARSER_SCOPE_STACK_IS_LOCAL_CREATED) != 0; +} /* scanner_literal_is_created */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 9b8f61d4..926b5067 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "jcontext.h" #include "js-parser-internal.h" #include "js-scanner-internal.h" #include "lit-char-helpers.h" @@ -30,88 +31,7 @@ */ /** - * Scan mode types types. - */ -typedef enum -{ - SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */ - SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */ - SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */ - SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning primary expression end */ - SCAN_MODE_STATEMENT, /**< scanning statement */ - SCAN_MODE_STATEMENT_OR_TERMINATOR, /**< scanning statement or statement end */ - SCAN_MODE_STATEMENT_END, /**< scanning statement end */ - SCAN_MODE_VAR_STATEMENT, /**< scanning var statement */ - SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS, /**< continue scanning function arguments */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - SCAN_MODE_PROPERTY_NAME, /**< scanning property name */ -#if ENABLED (JERRY_ES2015_CLASS) - SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */ - SCAN_MODE_CLASS_METHOD, /**< scanning class method */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -} scan_modes_t; - -/** - * Scan stack mode types types. - */ -typedef enum -{ - SCAN_STACK_SCRIPT, /**< script */ - SCAN_STACK_EVAL_FUNCTION, /**< evaluated function */ - SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */ - SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */ - SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */ - SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */ - SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */ - SCAN_STACK_IF_STATEMENT, /**< statement part of "if" statements */ - SCAN_STACK_DO_STATEMENT, /**< statement part of "do" statements */ - SCAN_STACK_DO_EXPRESSION, /**< expression part of "do" statements */ - SCAN_STACK_WHILE_EXPRESSION, /**< expression part of "while" iterator */ - SCAN_STACK_PAREN_EXPRESSION, /**< expression in brackets */ - SCAN_STACK_STATEMENT_WITH_EXPR, /**< statement which starts with expression enclosed in brackets */ - /* The SCANNER_IS_FOR_START macro needs to be updated when the following constants are reordered. */ - SCAN_STACK_VAR, /**< var statement */ - SCAN_STACK_FOR_VAR_START, /**< start of "for" iterator with var statement */ - SCAN_STACK_FOR_START, /**< start of "for" iterator */ - SCAN_STACK_FOR_CONDITION, /**< condition part of "for" iterator */ - SCAN_STACK_FOR_EXPRESSION, /**< expression part of "for" iterator */ - SCAN_STACK_SWITCH_EXPRESSION, /**< expression part of "switch" statement */ - SCAN_STACK_CASE_STATEMENT, /**< case statement inside a switch statement */ - SCAN_STACK_COLON_EXPRESSION, /**< expression between a question mark and colon */ - SCAN_STACK_TRY_STATEMENT, /**< try statement */ - SCAN_STACK_CATCH_STATEMENT, /**< catch statement */ - SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */ - SCAN_STACK_OBJECT_LITERAL, /**< object literal group */ -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - SCAN_STACK_TEMPLATE_STRING, /**< template string */ -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */ - SCAN_STACK_ARROW_EXPRESSION, /**< expression body of an arrow function */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) - SCAN_STACK_CLASS_STATEMENT, /**< class statement */ - SCAN_STACK_CLASS_EXPRESSION, /**< class expression */ - SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ -} scan_stack_modes_t; - -/** - * Checks whether the stack top is a for statement start. - */ -#define SCANNER_IS_FOR_START(stack_top) \ - ((stack_top) >= SCAN_STACK_FOR_VAR_START && (stack_top) <= SCAN_STACK_FOR_START) - -/** - * Scan mode types types. + * Scan return types. */ typedef enum { @@ -122,82 +42,29 @@ typedef enum /** * Checks whether token type is "of". */ -#if ENABLED (JERRY_ES2015_FOR_OF) -#define SCANNER_IDENTIFIER_IS_OF() (lexer_compare_literal_to_identifier (context_p, "of", 2)) +#if ENABLED (JERRY_ES2015) +#define SCANNER_IDENTIFIER_IS_OF() (lexer_token_is_identifier (context_p, "of", 2)) #else #define SCANNER_IDENTIFIER_IS_OF() (false) -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) -/** - * Init scanning the body of an arrow function. - */ -static void -scanner_check_arrow_body (parser_context_t *context_p, /**< context */ - scanner_context_t *scanner_context_p) /**< scanner context */ -{ - lexer_next_token (context_p); +JERRY_STATIC_ASSERT (SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (SCANNER_LITERAL_POOL_GENERATOR) + == SCAN_STACK_COMPUTED_GENERATOR, + scanner_invalid_conversion_from_literal_pool_generator_to_computed_generator); +JERRY_STATIC_ASSERT (SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (SCANNER_LITERAL_POOL_ASYNC) + == SCAN_STACK_COMPUTED_ASYNC, + scanner_invalid_conversion_from_literal_pool_async_to_computed_async); - if (context_p->token.type != LEXER_LEFT_BRACE) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_EXPRESSION); - return; - } +JERRY_STATIC_ASSERT (SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (SCAN_STACK_COMPUTED_GENERATOR) + == SCANNER_LITERAL_POOL_GENERATOR, + scanner_invalid_conversion_from_computed_generator_to_literal_pool_generator); +JERRY_STATIC_ASSERT (SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (SCAN_STACK_COMPUTED_ASYNC) + == SCANNER_LITERAL_POOL_ASYNC, + scanner_invalid_conversion_from_computed_async_to_literal_pool_async); - lexer_next_token (context_p); - scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_EXPRESSION); -} /* scanner_check_arrow_body */ - -/** - * Process arrow function with argument list. - */ -static void -scanner_process_arrow (parser_context_t *context_p, /**< context */ - scanner_context_t *scanner_context_p) /**< scanner context */ -{ - scanner_source_start_t source_start; - - parser_stack_pop_uint8 (context_p); - parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); - - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_ARROW - || (context_p->token.flags & LEXER_WAS_NEWLINE)) - { - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - return; - } - - scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); - info_p->type = SCANNER_TYPE_ARROW; - - scanner_check_arrow_body (context_p, scanner_context_p); -} /* scanner_process_arrow */ - -/** - * Process arrow function with a single argument. - */ -static void -scanner_process_simple_arrow (parser_context_t *context_p, /**< context */ - scanner_context_t *scanner_context_p, /**< scanner context */ - const uint8_t *source_p) /**< identifier end position */ -{ - scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t)); - info_p->type = SCANNER_TYPE_ARROW; - - /* Skip the => token, which size is two. */ - context_p->source_p += 2; - PARSER_PLUS_EQUAL_LC (context_p->column, 2); - context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES); - - scanner_check_arrow_body (context_p, scanner_context_p); -} /* scanner_process_simple_arrow */ - -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Scan primary expression. @@ -215,6 +82,13 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ case LEXER_KEYW_NEW: { scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW; + +#if ENABLED (JERRY_ES2015) + if (scanner_try_scan_new_target (context_p)) + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + } +#endif /* ENABLED (JERRY_ES2015) */ break; } case LEXER_DIVIDE: @@ -226,7 +100,24 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; + +#if ENABLED (JERRY_ES2015) + if (scanner_context_p->async_source_p != NULL) + { + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + } + + if (lexer_consume_generator (context_p)) + { + status_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + lexer_next_token (context_p); + if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { @@ -239,31 +130,30 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ } case LEXER_LEFT_PAREN: { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - scanner_source_start_t source_start; - source_start.source_p = context_p->source_p; - - parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t)); - parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS); -#else - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; + scanner_scan_bracket (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; } case LEXER_LEFT_SQUARE: { - parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); +#if ENABLED (JERRY_ES2015) + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_NONE, false); +#endif /* ENABLED (JERRY_ES2015) */ + + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } case LEXER_LEFT_BRACE: { +#if ENABLED (JERRY_ES2015) + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_NONE, false); +#endif /* ENABLED (JERRY_ES2015) */ + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; return SCAN_KEEP_TOKEN; } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) +#if ENABLED (JERRY_ES2015) case LEXER_TEMPLATE_LITERAL: { if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) @@ -276,21 +166,32 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ /* The string is a normal string literal. */ /* FALLTHRU */ } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_LITERAL: -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) { +#if ENABLED (JERRY_ES2015) const uint8_t *source_p = context_p->source_p; if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL && lexer_check_arrow (context_p)) { - scanner_process_simple_arrow (context_p, scanner_context_p, source_p); + scanner_scan_simple_arrow (context_p, scanner_context_p, source_p); return SCAN_KEEP_TOKEN; } + else if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + scanner_context_p->async_source_p = source_p; + scanner_check_async_function (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + scanner_add_reference (context_p, scanner_context_p); + } /* FALLTHRU */ } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ case LEXER_KEYW_THIS: case LEXER_KEYW_SUPER: case LEXER_LIT_TRUE: @@ -300,33 +201,73 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; break; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXPRESSION); - scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_EXPRESSION); + + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + return SCAN_KEEP_TOKEN; + } break; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_RIGHT_SQUARE: { - if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) + if (stack_top != SCAN_STACK_ARRAY_LITERAL) { scanner_raise_error (context_p); } - parser_stack_pop_uint8 (context_p); - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return SCAN_KEEP_TOKEN; } - case LEXER_COMMA: +#if ENABLED (JERRY_ES2015) + case LEXER_THREE_DOTS: { - if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) + /* Elision or spread arguments */ + if (stack_top != SCAN_STACK_PAREN_EXPRESSION && stack_top != SCAN_STACK_ARRAY_LITERAL) { scanner_raise_error (context_p); } scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } +#endif /* ENABLED (JERRY_ES2015) */ + case LEXER_COMMA: + { + if (stack_top != SCAN_STACK_ARRAY_LITERAL) + { + scanner_raise_error (context_p); + } + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + +#if ENABLED (JERRY_ES2015) + if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) + { + scanner_context_p->mode = SCAN_MODE_BINDING; + } +#endif /* ENABLED (JERRY_ES2015) */ + break; + } +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_YIELD: + { + lexer_next_token (context_p); + + if (lexer_check_yield_no_arg (context_p)) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } + + if (context_p->token.type == LEXER_MULTIPLY) + { + return SCAN_NEXT_TOKEN; + } + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_RIGHT_PAREN: { if (stack_top == SCAN_STACK_PAREN_EXPRESSION) @@ -335,13 +276,6 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ parser_stack_pop_uint8 (context_p); break; } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (stack_top == SCAN_STACK_ARROW_ARGUMENTS) - { - scanner_process_arrow (context_p, scanner_context_p); - return SCAN_KEEP_TOKEN; - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ /* FALLTHRU */ } default: @@ -360,13 +294,21 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ static bool scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context */ scanner_context_t *scanner_context_p, /**< scanner context */ - lexer_token_type_t type) /**< current token type */ + lexer_token_type_t type, /**< current token type */ + scan_stack_modes_t stack_top) /**< current stack top */ { switch (type) { case LEXER_DOT: { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); + + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + return true; } case LEXER_LEFT_PAREN: @@ -375,28 +317,61 @@ scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; return true; } +#if ENABLED (JERRY_ES2015) + case LEXER_TEMPLATE_LITERAL: + { + if (JERRY_UNLIKELY (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT)) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + parser_stack_push_uint8 (context_p, SCAN_STACK_TAGGED_TEMPLATE_LITERAL); + } + return true; + } +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_LEFT_SQUARE: { - parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); + parser_stack_push_uint8 (context_p, SCAN_STACK_PROPERTY_ACCESSOR); scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; return true; } case LEXER_INCREASE: case LEXER_DECREASE: { - if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + + if (context_p->token.flags & LEXER_WAS_NEWLINE) { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return true; + return false; + } + + lexer_next_token (context_p); + type = (lexer_token_type_t) context_p->token.type; + + if (type != LEXER_QUESTION_MARK) + { + break; } /* FALLTHRU */ } + case LEXER_QUESTION_MARK: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } default: { break; } } + if (LEXER_IS_BINARY_OP_TOKEN (type) + && (type != LEXER_KEYW_IN || !SCANNER_IS_FOR_START (stack_top))) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + return false; } /* scanner_scan_post_primary_expression */ @@ -411,95 +386,94 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * lexer_token_type_t type, /**< current token type */ scan_stack_modes_t stack_top) /**< current stack top */ { - switch (type) + if (type == LEXER_COMMA) { - case LEXER_QUESTION_MARK: + switch (stack_top) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; - } - case LEXER_COMMA: - { - switch (stack_top) + case SCAN_STACK_VAR: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_LET: + case SCAN_STACK_CONST: +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_FOR_VAR_START: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_FOR_LET_START: + case SCAN_STACK_FOR_CONST_START: +#endif /* ENABLED (JERRY_ES2015) */ { - case SCAN_STACK_OBJECT_LITERAL: - { - scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; - return SCAN_KEEP_TOKEN; - } - case SCAN_STACK_VAR: - case SCAN_STACK_FOR_VAR_START: - { - scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; - return SCAN_NEXT_TOKEN; - } - case SCAN_STACK_COLON_EXPRESSION: - { - scanner_raise_error (context_p); - break; - } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case SCAN_STACK_ARROW_EXPRESSION: - { - break; - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - case SCAN_STACK_FUNCTION_PARAMETERS: - { - scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS; - parser_stack_pop_uint8 (context_p); - return SCAN_NEXT_TOKEN; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - default: - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; - } + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + return SCAN_NEXT_TOKEN; } - break; - } - default: - { - break; - } - } + case SCAN_STACK_COLON_EXPRESSION: + { + scanner_raise_error (context_p); + break; + } +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_BINDING_INIT: + case SCAN_STACK_BINDING_LIST_INIT: + { + break; + } + case SCAN_STACK_ARROW_ARGUMENTS: + { + lexer_next_token (context_p); + scanner_check_arrow_arg (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; + } + case SCAN_STACK_ARROW_EXPRESSION: + { + break; + } + case SCAN_STACK_FUNCTION_PARAMETERS: + { + scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS; + parser_stack_pop_uint8 (context_p); + return SCAN_NEXT_TOKEN; + } + case SCAN_STACK_ARRAY_LITERAL: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - if (LEXER_IS_BINARY_OP_TOKEN (type) - && (type != LEXER_KEYW_IN || !SCANNER_IS_FOR_START (stack_top))) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; + if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) + { + scanner_context_p->mode = SCAN_MODE_BINDING; + } + + return SCAN_NEXT_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_OBJECT_LITERAL: + { + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return SCAN_KEEP_TOKEN; + } + default: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return SCAN_NEXT_TOKEN; + } + } } switch (stack_top) { - case SCAN_STACK_VAR: - { - parser_stack_pop_uint8 (context_p); - return SCAN_KEEP_TOKEN; - } - case SCAN_STACK_PAREN_EXPRESSION: - { - if (type != LEXER_RIGHT_PAREN) - { - break; - } - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - parser_stack_pop_uint8 (context_p); - return SCAN_NEXT_TOKEN; - } - case SCAN_STACK_STATEMENT_WITH_EXPR: + case SCAN_STACK_WITH_EXPRESSION: { if (type != LEXER_RIGHT_PAREN) { break; } - scanner_context_p->mode = SCAN_MODE_STATEMENT; parser_stack_pop_uint8 (context_p); + + uint16_t status_flags = scanner_context_p->active_literal_pool_p->status_flags; + parser_stack_push_uint8 (context_p, (status_flags & SCANNER_LITERAL_POOL_IN_WITH) ? 1 : 0); + parser_stack_push_uint8 (context_p, SCAN_STACK_WITH_STATEMENT); + status_flags |= SCANNER_LITERAL_POOL_IN_WITH; + scanner_context_p->active_literal_pool_p->status_flags = status_flags; + + scanner_context_p->mode = SCAN_MODE_STATEMENT; return SCAN_NEXT_TOKEN; } case SCAN_STACK_DO_EXPRESSION: @@ -535,7 +509,120 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * scanner_context_p->mode = SCAN_MODE_STATEMENT; return SCAN_NEXT_TOKEN; } + case SCAN_STACK_PAREN_EXPRESSION: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + parser_stack_pop_uint8 (context_p); + +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + scanner_add_async_literal (context_p, scanner_context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return SCAN_NEXT_TOKEN; + } + case SCAN_STACK_STATEMENT_WITH_EXPR: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + parser_stack_pop_uint8 (context_p); + +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_IF_STATEMENT) + { + scanner_check_function_after_if (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return SCAN_NEXT_TOKEN; + } +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_BINDING_LIST_INIT: + { + parser_stack_pop_uint8 (context_p); + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_LET + || context_p->stack_top_uint8 == SCAN_STACK_CONST + || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START + || context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START + || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS + || context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); + + scanner_binding_item_t *item_p = scanner_context_p->active_binding_list_p->items_p; + + while (item_p != NULL) + { + if (item_p->literal_p->type & SCANNER_LITERAL_IS_USED) + { + item_p->literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + item_p = item_p->next_p; + } + + scanner_pop_binding_list (scanner_context_p); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return SCAN_KEEP_TOKEN; + } + case SCAN_STACK_BINDING_INIT: + { + scanner_binding_literal_t binding_literal; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_LET + || context_p->stack_top_uint8 == SCAN_STACK_CONST + || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START + || context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START + || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS + || context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); + + JERRY_ASSERT ((stack_top != SCAN_STACK_ARRAY_LITERAL && stack_top != SCAN_STACK_OBJECT_LITERAL) + || SCANNER_NEEDS_BINDING_LIST (scanner_context_p->binding_type)); + + if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) + { + binding_literal.literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_VAR: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_LET: + case SCAN_STACK_CONST: +#endif /* ENABLED (JERRY_ES2015) */ + { +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + scanner_context_p->active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT; +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + parser_stack_pop_uint8 (context_p); + return SCAN_KEEP_TOKEN; + } case SCAN_STACK_FOR_VAR_START: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_FOR_LET_START: + case SCAN_STACK_FOR_CONST_START: +#endif /* ENABLED (JERRY_ES2015) */ case SCAN_STACK_FOR_START: { if (type == LEXER_KEYW_IN || SCANNER_IDENTIFIER_IS_OF ()) @@ -549,11 +636,16 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * location_info = (scanner_location_info_t *) scanner_insert_info (context_p, for_statement.u.source_p, sizeof (scanner_location_info_t)); -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) location_info->info.type = (type == LEXER_KEYW_IN) ? SCANNER_TYPE_FOR_IN : SCANNER_TYPE_FOR_OF; -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ + + if (stack_top == SCAN_STACK_FOR_LET_START || stack_top == SCAN_STACK_FOR_CONST_START) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK_EARLY); + } +#else /* !ENABLED (JERRY_ES2015) */ location_info->info.type = SCANNER_TYPE_FOR_IN; -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ scanner_get_location (&location_info->location, context_p); @@ -572,6 +664,13 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, NULL, sizeof (scanner_for_statement_t)); +#if ENABLED (JERRY_ES2015) + if (stack_top == SCAN_STACK_FOR_LET_START || stack_top == SCAN_STACK_FOR_CONST_START) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK); + } +#endif /* ENABLED (JERRY_ES2015) */ + for_statement.u.source_p = context_p->source_p; parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t)); parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_CONDITION); @@ -655,6 +754,12 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * break; } +#if ENABLED (JERRY_ES2015) + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p - 1; +#endif /* ENABLED (JERRY_ES2015) */ + parser_stack_pop_uint8 (context_p); scanner_switch_statement_t switch_statement = scanner_context_p->active_switch_statement; @@ -715,27 +820,107 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } - case SCAN_STACK_SQUARE_BRACKETED_EXPRESSION: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_ARRAY_LITERAL: + case SCAN_STACK_OBJECT_LITERAL: + { + if (((stack_top == SCAN_STACK_ARRAY_LITERAL) && (type != LEXER_RIGHT_SQUARE)) + || ((stack_top == SCAN_STACK_OBJECT_LITERAL) && (type != LEXER_RIGHT_BRACE))) + { + break; + } + + scanner_source_start_t source_start; + uint8_t binding_type = scanner_context_p->binding_type; + + parser_stack_pop_uint8 (context_p); + scanner_context_p->binding_type = context_p->stack_top_uint8; + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + lexer_next_token (context_p); + + if (binding_type == SCANNER_BINDING_CATCH && context_p->stack_top_uint8 == SCAN_STACK_CATCH_STATEMENT) + { + scanner_pop_binding_list (scanner_context_p); + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; + return SCAN_NEXT_TOKEN; + } + + if (context_p->token.type != LEXER_ASSIGN) + { + if (SCANNER_NEEDS_BINDING_LIST (binding_type)) + { + scanner_pop_binding_list (scanner_context_p); + } + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return SCAN_KEEP_TOKEN; + } + + scanner_location_info_t *location_info_p; + location_info_p = (scanner_location_info_t *) scanner_insert_info (context_p, + source_start.source_p, + sizeof (scanner_location_info_t)); + location_info_p->info.type = SCANNER_TYPE_INITIALIZER; + scanner_get_location (&location_info_p->location, context_p); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + if (SCANNER_NEEDS_BINDING_LIST (binding_type)) + { + scanner_binding_item_t *item_p = scanner_context_p->active_binding_list_p->items_p; + + while (item_p != NULL) + { + item_p->literal_p->type &= (uint8_t) ~SCANNER_LITERAL_IS_USED; + item_p = item_p->next_p; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_LIST_INIT); + } + return SCAN_NEXT_TOKEN; + } +#else /* !ENABLED (JERRY_ES2015) */ + case SCAN_STACK_ARRAY_LITERAL: +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_PROPERTY_ACCESSOR: { if (type != LEXER_RIGHT_SQUARE) { break; } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } +#if !ENABLED (JERRY_ES2015) case SCAN_STACK_OBJECT_LITERAL: { if (type != LEXER_RIGHT_BRACE) { break; } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#endif /* !ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015) case SCAN_STACK_COMPUTED_PROPERTY: { if (type != LEXER_RIGHT_SQUARE) @@ -750,6 +935,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * if (stack_top == SCAN_STACK_FUNCTION_PROPERTY) { + scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION); + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; return SCAN_KEEP_TOKEN; } @@ -758,6 +945,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * if (context_p->token.type == LEXER_LEFT_PAREN) { + scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION); + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; return SCAN_KEEP_TOKEN; @@ -769,11 +958,39 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) + { + scanner_context_p->mode = SCAN_MODE_BINDING; + } return SCAN_NEXT_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) + case SCAN_STACK_COMPUTED_GENERATOR: + case SCAN_STACK_COMPUTED_ASYNC: + case SCAN_STACK_COMPUTED_ASYNC_GENERATOR: + { + if (type != LEXER_RIGHT_SQUARE) + { + break; + } + + lexer_next_token (context_p); + parser_stack_pop_uint8 (context_p); + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY); + + uint16_t status_flags = (uint16_t) (SCANNER_LITERAL_POOL_FUNCTION + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (stack_top)); + + scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return SCAN_KEEP_TOKEN; + } case SCAN_STACK_TEMPLATE_STRING: + case SCAN_STACK_TAGGED_TEMPLATE_LITERAL: { if (type != LEXER_RIGHT_BRACE) { @@ -782,7 +999,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * context_p->source_p--; context_p->column--; - lexer_parse_string (context_p); + lexer_parse_string (context_p, LEXER_STRING_NO_OPTS); if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) { @@ -795,8 +1012,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } return SCAN_NEXT_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) case SCAN_STACK_ARROW_ARGUMENTS: { if (type != LEXER_RIGHT_PAREN) @@ -804,35 +1019,35 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * break; } - scanner_process_arrow (context_p, scanner_context_p); + scanner_check_arrow (context_p, scanner_context_p); return SCAN_KEEP_TOKEN; } case SCAN_STACK_ARROW_EXPRESSION: { + scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + lexer_update_await_yield (context_p, context_p->status_flags); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) case SCAN_STACK_CLASS_EXTENDS: { if (type != LEXER_LEFT_BRACE) { break; } + scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; parser_stack_pop_uint8 (context_p); + return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) case SCAN_STACK_FUNCTION_PARAMETERS: { parser_stack_pop_uint8 (context_p); if (type != LEXER_RIGHT_PAREN - && (type != LEXER_EOS || context_p->stack_top_uint8 != SCAN_STACK_EVAL_FUNCTION)) + && (type != LEXER_EOS || context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION)) { break; } @@ -840,7 +1055,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS; return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { scanner_context_p->mode = SCAN_MODE_STATEMENT_END; @@ -872,6 +1087,14 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } case LEXER_LEFT_BRACE: { +#if ENABLED (JERRY_ES2015) + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, + scanner_context_p, + SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); return SCAN_NEXT_TOKEN; @@ -891,6 +1114,14 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } +#if ENABLED (JERRY_ES2015) + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, + scanner_context_p, + SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; parser_stack_push_uint8 (context_p, SCAN_STACK_TRY_STATEMENT); return SCAN_NEXT_TOKEN; @@ -916,6 +1147,10 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ { parser_stack_push_uint8 (context_p, SCAN_STACK_IF_STATEMENT); } + else if (type == LEXER_KEYW_WITH) + { + mode = SCAN_STACK_WITH_EXPRESSION; + } else if (type == LEXER_KEYW_SWITCH) { mode = SCAN_STACK_SWITCH_EXPRESSION; @@ -954,10 +1189,15 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_for_statement_t for_statement; for_statement.u.source_p = context_p->source_p; uint8_t stack_mode = SCAN_STACK_FOR_START; + scan_return_types_t return_type = SCAN_KEEP_TOKEN; lexer_next_token (context_p); scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; +#if ENABLED (JERRY_ES2015) + const uint8_t *source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + switch (context_p->token.type) { case LEXER_SEMICOLON: @@ -969,13 +1209,70 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ { scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; stack_mode = SCAN_STACK_FOR_VAR_START; + return_type = SCAN_NEXT_TOKEN; break; } +#if ENABLED (JERRY_ES2015) + case LEXER_LITERAL: + { + if (!lexer_token_is_let (context_p)) + { + break; + } + + parser_line_counter_t line = context_p->line; + parser_line_counter_t column = context_p->column; + + if (lexer_check_arrow (context_p)) + { + context_p->source_p = source_p; + context_p->line = line; + context_p->column = column; + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; + break; + } + + lexer_next_token (context_p); + + type = (lexer_token_type_t) context_p->token.type; + + if (type != LEXER_LEFT_SQUARE + && type != LEXER_LEFT_BRACE + && (type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)) + { + scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_LET_EXPRESSION; + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + /* FALLTHRU */ + } + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: + { + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = source_p; + + if (scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION) + { + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + return_type = SCAN_NEXT_TOKEN; + } + + stack_mode = ((context_p->token.type == LEXER_KEYW_CONST) ? SCAN_STACK_FOR_CONST_START + : SCAN_STACK_FOR_LET_START); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t)); parser_stack_push_uint8 (context_p, stack_mode); - return (stack_mode == SCAN_STACK_FOR_START) ? SCAN_KEEP_TOKEN : SCAN_NEXT_TOKEN; + return return_type; } case LEXER_KEYW_VAR: { @@ -983,6 +1280,20 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ parser_stack_push_uint8 (context_p, SCAN_STACK_VAR); return SCAN_NEXT_TOKEN; } +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_LET: + { + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + parser_stack_push_uint8 (context_p, SCAN_STACK_LET); + return SCAN_NEXT_TOKEN; + } + case LEXER_KEYW_CONST: + { + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + parser_stack_push_uint8 (context_p, SCAN_STACK_CONST); + return SCAN_NEXT_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ case LEXER_KEYW_THROW: { scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; @@ -994,6 +1305,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if (!(context_p->token.flags & LEXER_WAS_NEWLINE) && context_p->token.type != LEXER_SEMICOLON + && context_p->token.type != LEXER_EOS && context_p->token.type != LEXER_RIGHT_BRACE) { scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; @@ -1058,25 +1370,85 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { +#if ENABLED (JERRY_ES2015) + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_FUNCTION_STATEMENT; + + if (scanner_context_p->async_source_p != NULL) + { + scanner_context_p->status_flags |= SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION; + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + } +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); + +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_MULTIPLY) + { + status_flags |= SCANNER_LITERAL_POOL_GENERATOR; + lexer_next_token (context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { scanner_raise_error (context_p); } + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + +#if ENABLED (JERRY_ES2015) + const uint8_t mask = (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LOCAL); + + if ((literal_p->type & SCANNER_LITERAL_IS_LOCAL) + && (literal_p->type & mask) != (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + && (literal_p->type & mask) != (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION)) + { + scanner_raise_redeclaration_error (context_p); + } + + literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION; + + scanner_context_p->status_flags &= (uint16_t) ~SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION; +#else + literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC; + + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT); return SCAN_NEXT_TOKEN; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { - scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT); + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_STATEMENT); + + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + + scanner_detect_invalid_let (context_p, literal_p); + literal_p->type |= SCANNER_LITERAL_IS_LET; + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + scanner_context_p->active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + return SCAN_NEXT_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) case LEXER_KEYW_IMPORT: { @@ -1085,6 +1457,8 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } + context_p->global_status_flags |= ECMA_PARSE_MODULE; + scanner_context_p->mode = SCAN_MODE_STATEMENT_END; lexer_next_token (context_p); @@ -1099,6 +1473,15 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + +#if ENABLED (JERRY_ES2015) + scanner_detect_invalid_let (context_p, literal_p); + literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG; +#else /* !ENABLED (JERRY_ES2015) */ + literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG; +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); if (context_p->token.type == LEXER_COMMA) @@ -1116,7 +1499,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_MULTIPLY) { lexer_next_token (context_p); - if (!lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (!lexer_token_is_identifier (context_p, "as", 2)) { scanner_raise_error (context_p); } @@ -1129,6 +1512,15 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + +#if ENABLED (JERRY_ES2015) + scanner_detect_invalid_let (context_p, literal_p); + literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG; +#else /* !ENABLED (JERRY_ES2015) */ + literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG; +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); } else if (context_p->token.type == LEXER_LEFT_BRACE) @@ -1143,21 +1535,55 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + const uint8_t *source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ - if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (lexer_check_next_character (context_p, LIT_CHAR_LOWERCASE_A)) { lexer_next_token (context_p); + if (!lexer_token_is_identifier (context_p, "as", 2)) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { scanner_raise_error (context_p); } - lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ } + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & (SCANNER_LITERAL_IS_ARG + | SCANNER_LITERAL_IS_VAR + | SCANNER_LITERAL_IS_LOCAL)) + { + context_p->source_p = source_p; + scanner_raise_redeclaration_error (context_p); + } + + if (literal_p->type & SCANNER_LITERAL_IS_FUNC) + { + literal_p->type &= (uint8_t) ~SCANNER_LITERAL_IS_FUNC; + } + + literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG; +#else /* !ENABLED (JERRY_ES2015) */ + literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG; +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_next_token (context_p); + if (context_p->token.type != LEXER_RIGHT_BRACE) { if (context_p->token.type != LEXER_COMMA) @@ -1177,7 +1603,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } } - if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (!lexer_token_is_identifier (context_p, "from", 4)) { scanner_raise_error (context_p); } @@ -1199,6 +1625,8 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } + context_p->global_status_flags |= ECMA_PARSE_MODULE; + lexer_next_token (context_p); if (context_p->token.type == LEXER_KEYW_DEFAULT) @@ -1211,23 +1639,81 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { + lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p); + +#if ENABLED (JERRY_ES2015) + if (location_p->type & SCANNER_LITERAL_IS_LOCAL + && !(location_p->type & SCANNER_LITERAL_IS_FUNC)) + { + scanner_raise_redeclaration_error (context_p); + } + location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET; +#else /* !ENABLED (JERRY_ES2015) */ + location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC; +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); } + else + { + lexer_lit_location_t *location_p; + location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &lexer_default_literal); +#if ENABLED (JERRY_ES2015) + location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET; +#else /* !ENABLED (JERRY_ES2015) */ + location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC; +#endif /* ENABLED (JERRY_ES2015) */ + } + + scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION); parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT); scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; return SCAN_KEEP_TOKEN; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_KEYW_CLASS) { - scanner_context_p->mode = SCAN_MODE_STATEMENT; + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_STATEMENT); + + if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p); + + scanner_detect_invalid_let (context_p, literal_p); + + literal_p->type |= SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_NO_REG; + return SCAN_NEXT_TOKEN; + } + + lexer_lit_location_t *literal_p; + literal_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &lexer_default_literal); + literal_p->type |= SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_NO_REG; return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ + /* Assignment expression. */ + lexer_lit_location_t *location_p; + location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &lexer_default_literal); + location_p->type |= SCANNER_LITERAL_IS_VAR; scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_KEEP_TOKEN; + + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + return SCAN_KEEP_TOKEN; + } + + location_p = scanner_add_literal (context_p, scanner_context_p); + location_p->type |= SCANNER_LITERAL_IS_VAR; + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return SCAN_NEXT_TOKEN; } scanner_context_p->mode = SCAN_MODE_STATEMENT_END; @@ -1235,7 +1721,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_MULTIPLY) { lexer_next_token (context_p); - if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (!lexer_token_is_identifier (context_p, "from", 4)) { scanner_raise_error (context_p); } @@ -1265,7 +1751,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); - if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + if (lexer_token_is_identifier (context_p, "as", 2)) { lexer_next_token (context_p); @@ -1291,7 +1777,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); - if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + if (!lexer_token_is_identifier (context_p, "from", 4)) { return SCAN_KEEP_TOKEN; } @@ -1307,6 +1793,20 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ return SCAN_NEXT_TOKEN; } + switch (context_p->token.type) + { +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_CLASS: + case LEXER_KEYW_LET: + case LEXER_KEYW_CONST: +#endif /* ENABLED (JERRY_ES2015) */ + case LEXER_KEYW_VAR: + { + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_IN_EXPORT; + break; + } + } + scanner_context_p->mode = SCAN_MODE_STATEMENT; return SCAN_KEEP_TOKEN; } @@ -1324,23 +1824,70 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ { if (JERRY_UNLIKELY (lexer_check_next_character (context_p, LIT_CHAR_COLON))) { - lexer_next_token (context_p); - JERRY_ASSERT (context_p->token.type == LEXER_COLON); + lexer_consume_next_character (context_p); scanner_context_p->mode = SCAN_MODE_STATEMENT; return SCAN_NEXT_TOKEN; } JERRY_ASSERT (context_p->token.flags & LEXER_NO_SKIP_SPACES); -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) +#if ENABLED (JERRY_ES2015) /* The colon needs to be checked first because the parser also checks * it first, and this check skips the spaces which affects source_p. */ if (JERRY_UNLIKELY (lexer_check_arrow (context_p))) { - scanner_process_simple_arrow (context_p, scanner_context_p, context_p->source_p); + scanner_scan_simple_arrow (context_p, scanner_context_p, context_p->source_p); return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + + if (JERRY_UNLIKELY (lexer_token_is_let (context_p))) + { + lexer_lit_location_t let_literal = context_p->token.lit_location; + const uint8_t *source_p = context_p->source_p; + + lexer_next_token (context_p); + + type = (lexer_token_type_t) context_p->token.type; + + if (type == LEXER_LEFT_SQUARE + || type == LEXER_LEFT_BRACE + || (type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)) + { + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + parser_stack_push_uint8 (context_p, SCAN_STACK_LET); + return SCAN_KEEP_TOKEN; + } + + scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_LET_EXPRESSION; + + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &let_literal); + lit_location_p->type |= SCANNER_LITERAL_IS_USED; + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return SCAN_KEEP_TOKEN; + } + + if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + scanner_context_p->async_source_p = context_p->source_p; + + if (scanner_check_async_function (context_p, scanner_context_p)) + { + scanner_context_p->mode = SCAN_MODE_STATEMENT; + } + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_add_reference (context_p, scanner_context_p); scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; return SCAN_NEXT_TOKEN; @@ -1374,7 +1921,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ switch (context_p->stack_top_uint8) { case SCAN_STACK_SCRIPT: - case SCAN_STACK_EVAL_FUNCTION: + case SCAN_STACK_SCRIPT_FUNCTION: { if (type == LEXER_EOS) { @@ -1383,9 +1930,9 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ break; } case SCAN_STACK_BLOCK_STATEMENT: -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case SCAN_STACK_CLASS_STATEMENT: -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ case SCAN_STACK_FUNCTION_STATEMENT: { if (type != LEXER_RIGHT_BRACE) @@ -1393,12 +1940,27 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ break; } +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 != SCAN_STACK_CLASS_STATEMENT) + { + scanner_pop_literal_pool (context_p, scanner_context_p); + } +#else /* !ENABLED (JERRY_ES2015) */ + if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_STATEMENT) + { + scanner_pop_literal_pool (context_p, scanner_context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + terminator_found = true; parser_stack_pop_uint8 (context_p); lexer_next_token (context_p); continue; } case SCAN_STACK_FUNCTION_EXPRESSION: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_FUNCTION_ARROW: +#endif /* ENABLED (JERRY_ES2015) */ { if (type != LEXER_RIGHT_BRACE) { @@ -1406,6 +1968,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ } scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_ARROW) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } @@ -1416,16 +1986,17 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ break; } + scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); -#if ENABLED (JERRY_ES2015_CLASS) - if (context_p->stack_top_uint8 == SCAN_STACK_CLASS_STATEMENT - || context_p->stack_top_uint8 == SCAN_STACK_CLASS_EXPRESSION) +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR + || context_p->stack_top_uint8 == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) { scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL); @@ -1459,6 +2030,10 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_context_p->active_switch_statement = switch_statement; +#if ENABLED (JERRY_ES2015) + scanner_pop_literal_pool (context_p, scanner_context_p); +#endif /* ENABLED (JERRY_ES2015) */ + terminator_found = true; lexer_next_token (context_p); continue; @@ -1470,11 +2045,32 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ if (type == LEXER_KEYW_ELSE && (terminator_found || (context_p->token.flags & LEXER_WAS_NEWLINE))) { +#if ENABLED (JERRY_ES2015) + scanner_check_function_after_if (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; +#else /* !ENABLED (JERRY_ES2015) */ scanner_context_p->mode = SCAN_MODE_STATEMENT; return SCAN_NEXT_TOKEN; +#endif /* ENABLED (JERRY_ES2015) */ } continue; } + case SCAN_STACK_WITH_STATEMENT: + { + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + + JERRY_ASSERT (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH); + + parser_stack_pop_uint8 (context_p); + + if (context_p->stack_top_uint8 == 0) + { + literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_WITH; + } + + parser_stack_pop_uint8 (context_p); + continue; + } case SCAN_STACK_DO_STATEMENT: { parser_stack_pop_uint8 (context_p); @@ -1501,6 +2097,31 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ terminator_found = true; continue; } +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_PRIVATE_BLOCK_EARLY: + { + parser_list_iterator_t literal_iterator; + lexer_lit_location_t *literal_p; + + parser_list_iterator_init (&scanner_context_p->active_literal_pool_p->literal_pool, &literal_iterator); + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if ((literal_p->type & (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)) + && (literal_p->type & SCANNER_LITERAL_IS_USED)) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + } + /* FALLTHRU */ + } + case SCAN_STACK_PRIVATE_BLOCK: + { + parser_stack_pop_uint8 (context_p); + scanner_pop_literal_pool (context_p, scanner_context_p); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_TRY_STATEMENT @@ -1515,6 +2136,15 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ parser_stack_pop_uint8 (context_p); lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + scanner_pop_literal_pool (context_p, scanner_context_p); +#else /* !ENABLED (JERRY_ES2015) */ + if (stack_top == SCAN_STACK_CATCH_STATEMENT) + { + scanner_pop_literal_pool (context_p, scanner_context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + /* A finally statement is optional after a try or catch statement. */ if (context_p->token.type == LEXER_KEYW_FINALLY) { @@ -1525,6 +2155,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } +#if ENABLED (JERRY_ES2015) + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, + scanner_context_p, + SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; return SCAN_NEXT_TOKEN; @@ -1549,7 +2187,30 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p; + lexer_next_token (context_p); + parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT); + +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_CATCH, false); + + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context_p->mode = SCAN_MODE_BINDING; + return SCAN_NEXT_TOKEN; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) @@ -1557,6 +2218,9 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } + lexer_lit_location_t *lit_location_p = scanner_add_literal (context_p, scanner_context_p); + lit_location_p->type |= SCANNER_LITERAL_IS_LOCAL; + lexer_next_token (context_p); if (context_p->token.type != LEXER_RIGHT_PAREN) @@ -1571,7 +2235,6 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT); scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; return SCAN_NEXT_TOKEN; } @@ -1599,7 +2262,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ /** * Scan the whole source code. */ -void +void JERRY_ATTR_NOINLINE scanner_scan_all (parser_context_t *context_p, /**< context */ const uint8_t *arg_list_p, /**< function argument list */ const uint8_t *arg_list_end_p, /**< end of argument list */ @@ -1615,7 +2278,27 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + scanner_context.context_status_flags = context_p->status_flags; + scanner_context.status_flags = SCANNER_CONTEXT_NO_FLAGS; +#if ENABLED (JERRY_DEBUGGER) + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + { + scanner_context.status_flags |= SCANNER_CONTEXT_DEBUGGER_ENABLED; + } +#endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015) + scanner_context.binding_type = SCANNER_BINDING_NONE; + scanner_context.active_binding_list_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + scanner_context.active_literal_pool_p = NULL; scanner_context.active_switch_statement.last_case_p = NULL; + scanner_context.end_arguments_p = NULL; +#if ENABLED (JERRY_ES2015) + scanner_context.async_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + + /* This assignment must be here because of Apple compilers. */ + context_p->u.scanner_context_p = &scanner_context; parser_stack_init (context_p); @@ -1629,17 +2312,43 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ context_p->source_p = source_p; context_p->source_end_p = source_end_p; - scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_CAN_EVAL; + + if (context_p->status_flags & PARSER_IS_STRICT) + { + status_flags |= SCANNER_LITERAL_POOL_IS_STRICT; + } + + scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, &scanner_context, status_flags); + literal_pool_p->source_p = source_p; + parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT); lexer_next_token (context_p); + scanner_check_directives (context_p, &scanner_context); } else { context_p->source_p = arg_list_p; context_p->source_end_p = arg_list_end_p; + + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; + + if (context_p->status_flags & PARSER_IS_STRICT) + { + status_flags |= SCANNER_LITERAL_POOL_IS_STRICT; + } + +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + status_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_push_literal_pool (context_p, &scanner_context, status_flags); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; - parser_stack_push_uint8 (context_p, SCAN_STACK_EVAL_FUNCTION); + parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT_FUNCTION); /* Faking the first token. */ context_p->token.type = LEXER_LEFT_PAREN; @@ -1670,14 +2379,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } break; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case SCAN_MODE_CLASS_DECLARATION: { - if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - lexer_next_token (context_p); - } - if (context_p->token.type == LEXER_KEYW_EXTENDS) { parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS); @@ -1694,13 +2398,28 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_CLASS_METHOD: { - JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); + JERRY_ASSERT (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR + || stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR); lexer_skip_empty_statements (context_p); - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY); + + lexer_scan_identifier (context_p); if (context_p->token.type == LEXER_RIGHT_BRACE) { + scanner_source_start_t source_start; + + parser_stack_pop_uint8 (context_p); + + if (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) + { + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + } + + stack_top = context_p->stack_top_uint8; + + JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); + if (stack_top == SCAN_STACK_CLASS_STATEMENT) { /* The token is kept to disallow consuming a semicolon after it. */ @@ -1713,44 +2432,96 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ break; } - if (lexer_compare_literal_to_identifier (context_p, "static", 6)) + if (context_p->token.type == LEXER_LITERAL + && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type) + && lexer_compare_literal_to_string (context_p, "constructor", 11)) { - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY); + if (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) + { + scanner_source_start_t source_start; + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_CLASS_CONSTRUCTOR; + parser_stack_push_uint8 (context_p, SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR); + } + } + + if (lexer_token_is_identifier (context_p, "static", 6)) + { + lexer_scan_identifier (context_p); } parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; - if (lexer_compare_literal_to_identifier (context_p, "get", 3) - || lexer_compare_literal_to_identifier (context_p, "set", 3)) + uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION; + + if (lexer_token_is_identifier (context_p, "get", 3) + || lexer_token_is_identifier (context_p, "set", 3)) { - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY | LEXER_SCAN_CLASS_LEFT_PAREN); + lexer_scan_identifier (context_p); if (context_p->token.type == LEXER_LEFT_PAREN) { + scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); continue; } } + else if (lexer_token_is_identifier (context_p, "async", 5)) + { + lexer_scan_identifier (context_p); + + if (context_p->token.type == LEXER_LEFT_PAREN) + { + scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); + continue; + } + + literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC; + + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_scan_identifier (context_p); + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } + } + else if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_scan_identifier (context_p); + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + if (context_p->token.type != LEXER_LITERAL) + { + scanner_raise_error (context_p); + } + + if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } + + scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags); lexer_next_token (context_p); continue; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ case SCAN_MODE_POST_PRIMARY_EXPRESSION: { - if (scanner_scan_post_primary_expression (context_p, &scanner_context, type)) + if (scanner_scan_post_primary_expression (context_p, &scanner_context, type, stack_top)) { break; } + type = (lexer_token_type_t) context_p->token.type; /* FALLTHRU */ } case SCAN_MODE_PRIMARY_EXPRESSION_END: @@ -1794,13 +2565,105 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_VAR_STATEMENT: { +#if ENABLED (JERRY_ES2015) + if (type == LEXER_LEFT_SQUARE || type == LEXER_LEFT_BRACE) + { + uint8_t binding_type = SCANNER_BINDING_VAR; + + if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_FOR_LET_START) + { + binding_type = SCANNER_BINDING_LET; + } + else if (stack_top == SCAN_STACK_CONST || stack_top == SCAN_STACK_FOR_CONST_START) + { + binding_type = SCANNER_BINDING_CONST; + } + + scanner_push_destructuring_pattern (context_p, &scanner_context, binding_type, false); + + if (type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context.mode = SCAN_MODE_BINDING; + break; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context.mode = SCAN_MODE_PROPERTY_NAME; + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { scanner_raise_error (context_p); } + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context); + +#if ENABLED (JERRY_ES2015) + if (stack_top != SCAN_STACK_VAR && stack_top != SCAN_STACK_FOR_VAR_START) + { + scanner_detect_invalid_let (context_p, literal_p); + + if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_FOR_LET_START) + { + literal_p->type |= SCANNER_LITERAL_IS_LET; + } + else + { + JERRY_ASSERT (stack_top == SCAN_STACK_CONST || stack_top == SCAN_STACK_FOR_CONST_START); + literal_p->type |= SCANNER_LITERAL_IS_CONST; + } + + lexer_next_token (context_p); + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + else if (context_p->token.type == LEXER_ASSIGN) + { + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + } + } + else + { + if (!(literal_p->type & SCANNER_LITERAL_IS_VAR)) + { + scanner_detect_invalid_var (context_p, &scanner_context, literal_p); + literal_p->type |= SCANNER_LITERAL_IS_VAR; + + if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } + } + + lexer_next_token (context_p); + } +#else /* !ENABLED (JERRY_ES2015) */ + literal_p->type |= SCANNER_LITERAL_IS_VAR; + + if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } + lexer_next_token (context_p); +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ switch (context_p->token.type) { @@ -1818,6 +2681,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (SCANNER_IS_FOR_START (stack_top)) { +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + JERRY_ASSERT (!(scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT)); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + if (context_p->token.type != LEXER_SEMICOLON && context_p->token.type != LEXER_KEYW_IN && !SCANNER_IDENTIFIER_IS_OF ()) @@ -1829,7 +2696,15 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ continue; } +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (stack_top == SCAN_STACK_VAR || stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_CONST); +#else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (stack_top == SCAN_STACK_VAR); +#endif /* ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + scanner_context.active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT; +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ scanner_context.mode = SCAN_MODE_STATEMENT_END; parser_stack_pop_uint8 (context_p); @@ -1837,40 +2712,73 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_FUNCTION_ARGUMENTS: { - JERRY_ASSERT (stack_top == SCAN_STACK_EVAL_FUNCTION + JERRY_ASSERT (stack_top == SCAN_STACK_SCRIPT_FUNCTION || stack_top == SCAN_STACK_FUNCTION_STATEMENT || stack_top == SCAN_STACK_FUNCTION_EXPRESSION || stack_top == SCAN_STACK_FUNCTION_PROPERTY); + scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p; + + JERRY_ASSERT (literal_pool_p != NULL && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION)); + + literal_pool_p->source_p = context_p->source_p; + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (scanner_context.async_source_p != NULL)) + { + literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ASYNC; + literal_pool_p->source_p = scanner_context.async_source_p; + scanner_context.async_source_p = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (type != LEXER_LEFT_PAREN) { scanner_raise_error (context_p); } lexer_next_token (context_p); -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) +#if ENABLED (JERRY_ES2015) /* FALLTHRU */ } case SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS: { -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS) { +#if ENABLED (JERRY_ES2015) + lexer_lit_location_t *argument_literal_p; +#endif /* ENABLED (JERRY_ES2015) */ + while (true) { -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_THREE_DOTS) { + scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; + lexer_next_token (context_p); } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ + + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + argument_literal_p = NULL; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { scanner_raise_error (context_p); } + +#if ENABLED (JERRY_ES2015) + argument_literal_p = scanner_append_argument (context_p, &scanner_context); +#else /* !ENABLED (JERRY_ES2015) */ + scanner_append_argument (context_p, &scanner_context); +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); if (context_p->token.type != LEXER_COMMA) @@ -1879,24 +2787,59 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); } + +#if ENABLED (JERRY_ES2015) + if (argument_literal_p == NULL) + { + scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; + + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); + scanner_append_hole (context_p, &scanner_context); + scanner_push_destructuring_pattern (context_p, &scanner_context, SCANNER_BINDING_ARG, false); + + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context.mode = SCAN_MODE_BINDING; + break; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context.mode = SCAN_MODE_PROPERTY_NAME; + continue; + } + + if (context_p->token.type == LEXER_ASSIGN) + { + scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; + + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + + if (argument_literal_p->type & SCANNER_LITERAL_IS_USED) + { + JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE); + break; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = argument_literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - if (context_p->token.type == LEXER_ASSIGN) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); - scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - - if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_EVAL_FUNCTION) + if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_SCRIPT_FUNCTION) { /* End of argument parsing. */ scanner_info_t *scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, sizeof (scanner_info_t)); scanner_info_p->next_p = context_p->next_scanner_info_p; scanner_info_p->source_p = NULL; scanner_info_p->type = SCANNER_TYPE_END_ARGUMENTS; + scanner_context.end_arguments_p = scanner_info_p; context_p->next_scanner_info_p = scanner_info_p; context_p->source_p = source_p; @@ -1904,8 +2847,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ context_p->line = 1; context_p->column = 1; - scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; + scanner_filter_arguments (context_p, &scanner_context); lexer_next_token (context_p); + scanner_check_directives (context_p, &scanner_context); continue; } @@ -1920,76 +2864,110 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { scanner_raise_error (context_p); } - scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; - break; + + scanner_filter_arguments (context_p, &scanner_context); + lexer_next_token (context_p); + scanner_check_directives (context_p, &scanner_context); + continue; } case SCAN_MODE_PROPERTY_NAME: { JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY); + if (lexer_scan_identifier (context_p)) + { + lexer_check_property_modifier (context_p); + } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) { parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type == LEXER_RIGHT_BRACE) { - parser_stack_pop_uint8 (context_p); - scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + continue; } if (context_p->token.type == LEXER_PROPERTY_GETTER +#if ENABLED (JERRY_ES2015) + || context_p->token.type == LEXER_KEYW_ASYNC + || context_p->token.type == LEXER_MULTIPLY +#endif /* ENABLED (JERRY_ES2015) */ || context_p->token.type == LEXER_PROPERTY_SETTER) { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY | LEXER_SCAN_IDENT_NO_KEYW); + uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION; + +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_MULTIPLY) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } + else if (context_p->token.type == LEXER_KEYW_ASYNC) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC; + + if (lexer_consume_generator (context_p)) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } + } +#endif /* ENABLED (JERRY_ES2015) */ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); + lexer_scan_identifier (context_p); -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL) { scanner_raise_error (context_p); } + scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; break; } - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL); + if (context_p->token.type != LEXER_LITERAL) + { + scanner_raise_error (context_p); + } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) parser_line_counter_t start_line = context_p->token.line; parser_line_counter_t start_column = context_p->token.column; bool is_ident = (context_p->token.lit_location.type == LEXER_IDENT_LITERAL); -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_PAREN) { + scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; continue; } if (is_ident - && (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_BRACE)) + && (context_p->token.type == LEXER_COMMA + || context_p->token.type == LEXER_RIGHT_BRACE + || context_p->token.type == LEXER_ASSIGN)) { context_p->source_p = context_p->token.lit_location.char_p; context_p->line = start_line; @@ -2005,20 +2983,26 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_COMMA) + if (scanner_context.binding_type != SCANNER_BINDING_NONE) { + scanner_context.mode = SCAN_MODE_BINDING; continue; } - JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE); + scanner_add_reference (context_p, &scanner_context); - parser_stack_pop_uint8 (context_p); - scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_ASSIGN) + { + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + continue; } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_COLON) { @@ -2026,8 +3010,139 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + +#if ENABLED (JERRY_ES2015) + if (scanner_context.binding_type != SCANNER_BINDING_NONE) + { + scanner_context.mode = SCAN_MODE_BINDING; + } +#endif /* ENABLED (JERRY_ES2015) */ break; } +#if ENABLED (JERRY_ES2015) + case SCAN_MODE_BINDING: + { + JERRY_ASSERT (scanner_context.binding_type == SCANNER_BINDING_VAR + || scanner_context.binding_type == SCANNER_BINDING_LET + || scanner_context.binding_type == SCANNER_BINDING_CATCH + || scanner_context.binding_type == SCANNER_BINDING_CONST + || scanner_context.binding_type == SCANNER_BINDING_ARG + || scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG); + + if (type == LEXER_THREE_DOTS) + { + lexer_next_token (context_p); + type = (lexer_token_type_t) context_p->token.type; + } + + if (type == LEXER_LEFT_SQUARE || type == LEXER_LEFT_BRACE) + { + scanner_push_destructuring_pattern (context_p, &scanner_context, scanner_context.binding_type, true); + + if (type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + break; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context.mode = SCAN_MODE_PROPERTY_NAME; + continue; + } + + if (type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + continue; + } + + lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context); + + scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + + if (scanner_context.binding_type == SCANNER_BINDING_VAR) + { + if (!(literal_p->type & SCANNER_LITERAL_IS_VAR)) + { + scanner_detect_invalid_var (context_p, &scanner_context, literal_p); + literal_p->type |= SCANNER_LITERAL_IS_VAR; + + if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } + } + break; + } + + if (scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG) + { + literal_p->type |= SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG; + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + break; + } + } + else + { + scanner_detect_invalid_let (context_p, literal_p); + + if (scanner_context.binding_type <= SCANNER_BINDING_CATCH) + { + JERRY_ASSERT ((scanner_context.binding_type == SCANNER_BINDING_LET) + || (scanner_context.binding_type == SCANNER_BINDING_CATCH)); + + literal_p->type |= SCANNER_LITERAL_IS_LET; + } + else + { + literal_p->type |= SCANNER_LITERAL_IS_CONST; + + if (scanner_context.binding_type == SCANNER_BINDING_ARG) + { + literal_p->type |= SCANNER_LITERAL_IS_ARG; + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + break; + } + } + } + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + break; + } + } + + scanner_binding_item_t *binding_item_p; + binding_item_p = (scanner_binding_item_t *) scanner_malloc (context_p, sizeof (scanner_binding_item_t)); + + binding_item_p->next_p = scanner_context.active_binding_list_p->items_p; + binding_item_p->literal_p = literal_p; + + scanner_context.active_binding_list_p->items_p = binding_item_p; + + lexer_next_token (context_p); + if (context_p->token.type != LEXER_ASSIGN) + { + continue; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } lexer_next_token (context_p); @@ -2035,25 +3150,83 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scan_completed: if (context_p->stack_top_uint8 != SCAN_STACK_SCRIPT - && context_p->stack_top_uint8 != SCAN_STACK_EVAL_FUNCTION) + && context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION) { scanner_raise_error (context_p); } + scanner_pop_literal_pool (context_p, &scanner_context); + +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT (scanner_context.active_binding_list_p == NULL); +#endif /* ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (scanner_context.active_literal_pool_p == NULL); + #ifndef JERRY_NDEBUG - context_p->status_flags |= PARSER_SCANNING_SUCCESSFUL; + scanner_context.context_status_flags |= PARSER_SCANNING_SUCCESSFUL; #endif /* !JERRY_NDEBUG */ } PARSER_CATCH { - /* Ignore the errors thrown by the lexer. */ - if (context_p->error != PARSER_ERR_OUT_OF_MEMORY) +#if ENABLED (JERRY_ES2015) + while (scanner_context.active_binding_list_p != NULL) { + scanner_pop_binding_list (&scanner_context); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (JERRY_UNLIKELY (context_p->error != PARSER_ERR_OUT_OF_MEMORY)) + { + /* Ignore the errors thrown by the lexer. */ context_p->error = PARSER_ERR_NO_ERROR; + + /* The following code may allocate memory, so it is enclosed in a try/catch. */ + PARSER_TRY (context_p->try_buffer) + { + #if ENABLED (JERRY_ES2015) + if (scanner_context.status_flags & SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION) + { + JERRY_ASSERT (scanner_context.async_source_p != NULL); + + scanner_info_t *info_p; + info_p = scanner_insert_info (context_p, scanner_context.async_source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_ERR_ASYNC_FUNCTION; + } + #endif /* ENABLED (JERRY_ES2015) */ + + while (scanner_context.active_literal_pool_p != NULL) + { + scanner_pop_literal_pool (context_p, &scanner_context); + } + } + PARSER_CATCH + { + JERRY_ASSERT (context_p->error == PARSER_ERR_OUT_OF_MEMORY); + } + PARSER_TRY_END + } + + JERRY_ASSERT (context_p->error == PARSER_ERR_NO_ERROR || context_p->error == PARSER_ERR_OUT_OF_MEMORY); + + if (context_p->error == PARSER_ERR_OUT_OF_MEMORY) + { + while (scanner_context.active_literal_pool_p != NULL) + { + scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p; + + scanner_context.active_literal_pool_p = literal_pool_p->prev_p; + + parser_list_free (&literal_pool_p->literal_pool); + scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t)); + } + + parser_stack_free (context_p); + return; } } PARSER_TRY_END + context_p->status_flags = scanner_context.context_status_flags; scanner_reverse_info_list (context_p); #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) @@ -2075,6 +3248,157 @@ scan_completed: source_start_p = source_p; break; } + case SCANNER_TYPE_FUNCTION: + case SCANNER_TYPE_BLOCK: + { + const uint8_t *prev_source_p = info_p->source_p - 1; + const uint8_t *data_p; + + if (info_p->type == SCANNER_TYPE_FUNCTION) + { + data_p = (const uint8_t *) (info_p + 1); + + JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d", + (int) info_p->u8_arg, + (int) info_p->u16_arg); + } + else + { + data_p = (const uint8_t *) (info_p + 1); + + JERRY_DEBUG_MSG (" BLOCK:"); + } + + JERRY_DEBUG_MSG (" source:%d\n", (int) (info_p->source_p - source_start_p)); + + while (data_p[0] != SCANNER_STREAM_TYPE_END) + { + switch (data_p[0] & SCANNER_STREAM_TYPE_MASK) + { + case SCANNER_STREAM_TYPE_VAR: + { + JERRY_DEBUG_MSG (" VAR "); + break; + } +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_LET: + { + JERRY_DEBUG_MSG (" LET "); + break; + } + case SCANNER_STREAM_TYPE_CONST: + { + JERRY_DEBUG_MSG (" CONST "); + break; + } + case SCANNER_STREAM_TYPE_LOCAL: + { + JERRY_DEBUG_MSG (" LOCAL "); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + case SCANNER_STREAM_TYPE_IMPORT: + { + JERRY_DEBUG_MSG (" IMPORT "); + break; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + case SCANNER_STREAM_TYPE_ARG: + { + JERRY_DEBUG_MSG (" ARG "); + break; + } +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_ARG_VAR: + { + JERRY_DEBUG_MSG (" ARG_VAR "); + break; + } + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + { + JERRY_DEBUG_MSG (" DESTRUCTURED_ARG "); + break; + } + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR: + { + JERRY_DEBUG_MSG (" DESTRUCTURED_ARG_VAR "); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + case SCANNER_STREAM_TYPE_ARG_FUNC: + { + JERRY_DEBUG_MSG (" ARG_FUNC "); + break; + } +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: + { + JERRY_DEBUG_MSG (" DESTRUCTURED_ARG_FUNC "); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + case SCANNER_STREAM_TYPE_FUNC: + { + JERRY_DEBUG_MSG (" FUNC "); + break; + } + default: + { + JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE); + JERRY_DEBUG_MSG (" HOLE\n"); + data_p++; + continue; + } + } + + size_t length; + + if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF)) + { + if (data_p[2] != 0) + { + prev_source_p += data_p[2]; + length = 2 + 1; + } + else + { + memcpy (&prev_source_p, data_p + 2 + 1, sizeof (const uint8_t *)); + length = 2 + 1 + sizeof (const uint8_t *); + } + } + else + { + int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8; + + if (diff <= UINT8_MAX) + { + diff = -diff; + } + + prev_source_p += diff; + length = 2 + 2; + } + +#if ENABLED (JERRY_ES2015) + if (data_p[0] & SCANNER_STREAM_EARLY_CREATE) + { + JERRY_ASSERT (data_p[0] & SCANNER_STREAM_NO_REG); + JERRY_DEBUG_MSG ("*"); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (data_p[0] & SCANNER_STREAM_NO_REG) + { + JERRY_DEBUG_MSG ("* "); + } + + JERRY_DEBUG_MSG ("'%.*s'\n", data_p[1], (char *) prev_source_p); + prev_source_p += data_p[1]; + data_p += length; + } + break; + } case SCANNER_TYPE_WHILE: { name_p = "WHILE"; @@ -2100,14 +3424,14 @@ scan_completed: print_location = true; break; } -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case SCANNER_TYPE_FOR_OF: { name_p = "FOR-OF"; print_location = true; break; } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ case SCANNER_TYPE_SWITCH: { JERRY_DEBUG_MSG (" SWITCH: source:%d\n", @@ -2132,13 +3456,39 @@ scan_completed: print_location = true; break; } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case SCANNER_TYPE_ARROW: +#if ENABLED (JERRY_ES2015) + case SCANNER_TYPE_INITIALIZER: { - JERRY_DEBUG_MSG (" ARROW: source:%d\n", (int) (info_p->source_p - source_start_p)); + name_p = "INITIALIZER"; + print_location = true; break; } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + case SCANNER_TYPE_CLASS_CONSTRUCTOR: + { + JERRY_DEBUG_MSG (" CLASS-CONSTRUCTOR: source:%d\n", + (int) (info_p->source_p - source_start_p)); + print_location = false; + break; + } + case SCANNER_TYPE_LET_EXPRESSION: + { + JERRY_DEBUG_MSG (" LET_EXPRESSION: source:%d\n", + (int) (info_p->source_p - source_start_p)); + break; + } + case SCANNER_TYPE_ERR_REDECLARED: + { + JERRY_DEBUG_MSG (" ERR_REDECLARED: source:%d\n", + (int) (info_p->source_p - source_start_p)); + break; + } + case SCANNER_TYPE_ERR_ASYNC_FUNCTION: + { + JERRY_DEBUG_MSG (" ERR_ASYNC_FUNCTION: source:%d\n", + (int) (info_p->source_p - source_start_p)); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } if (print_location) diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index b44d0ebb..c2b08e17 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -34,17 +34,23 @@ typedef enum SCANNER_TYPE_END, /**< mark the last info block */ SCANNER_TYPE_END_ARGUMENTS, /**< mark the end of function arguments * (only present if a function script is parsed) */ + SCANNER_TYPE_FUNCTION, /**< declarations in a function */ + SCANNER_TYPE_BLOCK, /**< declarations in a code block (usually enclosed in {}) */ SCANNER_TYPE_WHILE, /**< while statement */ SCANNER_TYPE_FOR, /**< for statement */ SCANNER_TYPE_FOR_IN, /**< for-in statement */ -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) SCANNER_TYPE_FOR_OF, /**< for-of statement */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ SCANNER_TYPE_SWITCH, /**< switch statement */ SCANNER_TYPE_CASE, /**< case statement */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - SCANNER_TYPE_ARROW, /**< arrow function */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#if ENABLED (JERRY_ES2015) + SCANNER_TYPE_INITIALIZER, /**< destructuring binding or assignment pattern with initializer */ + SCANNER_TYPE_CLASS_CONSTRUCTOR, /**< class constructor */ + SCANNER_TYPE_LET_EXPRESSION, /**< let expression */ + SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ + SCANNER_TYPE_ERR_ASYNC_FUNCTION, /**< an invalid async function follows */ +#endif /* ENABLED (JERRY_ES2015) */ } scanner_info_type_t; /** @@ -65,6 +71,8 @@ typedef struct scanner_info_t struct scanner_info_t *next_p; /**< next info structure */ const uint8_t *source_p; /**< triggering position of this scanner info */ uint8_t type; /**< type of the scanner info */ + uint8_t u8_arg; /**< custom 8-bit value */ + uint16_t u16_arg; /**< custom 16-bit value */ } scanner_info_t; /** @@ -104,6 +112,131 @@ typedef struct scanner_case_info_t *case_p; /**< list of switch cases */ } scanner_switch_info_t; +/* + * Description of compressed streams. + * + * The stream is a sequence of commands which encoded as bytes. The first byte + * contains the type of the command (see scanner_function_compressed_stream_types_t). + * + * The variable declaration commands has two arguments: + * - The first represents the length of the declared identifier + * - The second contains the relative distance from the end of the previous declaration + * Usually the distance is between 1 and 255, and represented as a single byte + * Distances between -256 and 65535 are encoded as two bytes + * Larger distances are encoded as pointers + */ + +/** + * Constants for compressed streams. + */ +typedef enum +{ + SCANNER_STREAM_UINT16_DIFF = (1 << 7), /**< relative distance is between -256 and 65535 */ + SCANNER_STREAM_HAS_ESCAPE = (1 << 6), /**< binding has escape */ + SCANNER_STREAM_NO_REG = (1 << 5), /**< binding cannot be stored in register */ + SCANNER_STREAM_EARLY_CREATE = (1 << 4), /**< binding must be created with ECMA_VALUE_UNINITIALIZED */ + /* Update SCANNER_STREAM_TYPE_MASK macro if more bits are added. */ +} scanner_compressed_stream_flags_t; + +/** + * Types for compressed streams. + */ +typedef enum +{ + SCANNER_STREAM_TYPE_END, /**< end of scanner data */ + SCANNER_STREAM_TYPE_HOLE, /**< no name is assigned to this argument */ + SCANNER_STREAM_TYPE_VAR, /**< var declaration */ +#if ENABLED (JERRY_ES2015) + SCANNER_STREAM_TYPE_LET, /**< let declaration */ + SCANNER_STREAM_TYPE_CONST, /**< const declaration */ + SCANNER_STREAM_TYPE_LOCAL, /**< local declaration (e.g. catch block) */ +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + SCANNER_STREAM_TYPE_IMPORT, /**< module import */ +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + /* The next four types must be in this order (see SCANNER_STREAM_TYPE_IS_ARG). */ + SCANNER_STREAM_TYPE_ARG, /**< argument declaration */ +#if ENABLED (JERRY_ES2015) + SCANNER_STREAM_TYPE_ARG_VAR, /**< argument declaration which is later copied + * into a variable declared by var statement */ + SCANNER_STREAM_TYPE_DESTRUCTURED_ARG, /**< destructuring argument declaration */ + SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR, /**< destructuring argument declaration which is later + * copied into a variable declared by var statement */ +#endif /* ENABLED (JERRY_ES2015) */ + /* Function types should be at the end. See the SCANNER_STREAM_TYPE_IS_FUNCTION macro. */ + SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which + * is later initialized with a function */ +#if ENABLED (JERRY_ES2015) + SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC, /**< destructuring argument declaration which + * is later initialized with a function */ +#endif /* ENABLED (JERRY_ES2015) */ + SCANNER_STREAM_TYPE_FUNC, /**< function declaration */ +} scanner_compressed_stream_types_t; + +/** + * Mask for decoding the type from the compressed stream. + */ +#define SCANNER_STREAM_TYPE_MASK 0xf + +/** + * Checks whether the decoded type represents a function declaration. + */ +#define SCANNER_STREAM_TYPE_IS_FUNCTION(type) ((type) >= SCANNER_STREAM_TYPE_ARG_FUNC) + +#if ENABLED (JERRY_ES2015) + +/** + * Checks whether the decoded type represents a function argument. + */ +#define SCANNER_STREAM_TYPE_IS_ARG(type) \ + ((type) >= SCANNER_STREAM_TYPE_ARG && (type) <= SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_VAR) + +/** + * Checks whether the decoded type represents both a function argument and a function declaration. + */ +#define SCANNER_STREAM_TYPE_IS_ARG_FUNC(type) \ + ((type) == SCANNER_STREAM_TYPE_ARG_FUNC || (type) == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC) + +#else /* !ENABLED (JERRY_ES2015) */ + +/** + * Checks whether the decoded type represents a function argument. + */ +#define SCANNER_STREAM_TYPE_IS_ARG(type) ((type) == SCANNER_STREAM_TYPE_ARG) + +/** + * Checks whether the decoded type represents both a function argument and a function declaration. + */ +#define SCANNER_STREAM_TYPE_IS_ARG_FUNC(type) ((type) == SCANNER_STREAM_TYPE_ARG_FUNC) + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Constants for u8_arg flags in scanner_function_info_t. + */ +typedef enum +{ + SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */ + SCANNER_FUNCTION_MAPPED_ARGUMENTS = (1 << 1), /**< arguments object should be mapped */ +#if ENABLED (JERRY_ES2015) + SCANNER_FUNCTION_LEXICAL_ENV_NEEDED = (1 << 2), /**< lexical environment is needed for the function body */ + SCANNER_FUNCTION_STATEMENT = (1 << 3), /**< function is function statement (not arrow expression) + * this flag must be combined with the type of function (e.g. async) */ + SCANNER_FUNCTION_ASYNC = (1 << 4), /**< function is async function */ +#endif /* ENABLED (JERRY_ES2015) */ +} scanner_function_flags_t; + +/** + * Option bits for scanner_create_variables function. + */ +typedef enum +{ + SCANNER_CREATE_VARS_NO_OPTS = 0, /**< no options */ + SCANNER_CREATE_VARS_IS_SCRIPT = (1 << 0), /**< create variables for script or direct eval */ + SCANNER_CREATE_VARS_IS_FUNCTION_ARGS = (1 << 1), /**< create variables for function arguments */ + SCANNER_CREATE_VARS_IS_FUNCTION_BODY = (1 << 2), /**< create variables for function body */ +} scanner_create_variables_flags_t; + /** * @} * @} diff --git a/jerry-core/parser/regexp/re-bytecode.c b/jerry-core/parser/regexp/re-bytecode.c index 7d7028aa..151d1baa 100644 --- a/jerry-core/parser/regexp/re-bytecode.c +++ b/jerry-core/parser/regexp/re-bytecode.c @@ -14,6 +14,8 @@ */ #include "ecma-globals.h" +#include "ecma-regexp-object.h" +#include "lit-strings.h" #include "re-bytecode.h" #if ENABLED (JERRY_BUILTIN_REGEXP) @@ -28,134 +30,103 @@ * @{ */ -/** - * Size of block of RegExp bytecode. Used for allocation - * - * @return pointer to the RegExp compiled code header - */ -#define REGEXP_BYTECODE_BLOCK_SIZE 64UL - void -re_initialize_regexp_bytecode (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */ +re_initialize_regexp_bytecode (re_compiler_ctx_t *re_ctx_p) /**< RegExp bytecode context */ { - bc_ctx_p->block_start_p = jmem_heap_alloc_block (REGEXP_BYTECODE_BLOCK_SIZE); - bc_ctx_p->block_end_p = bc_ctx_p->block_start_p + REGEXP_BYTECODE_BLOCK_SIZE; - bc_ctx_p->current_p = bc_ctx_p->block_start_p + sizeof (re_compiled_code_t); + const size_t initial_size = sizeof (re_compiled_code_t); + re_ctx_p->bytecode_start_p = jmem_heap_alloc_block (initial_size); + re_ctx_p->bytecode_size = initial_size; } /* re_initialize_regexp_bytecode */ -/** - * Realloc the bytecode container - * - * @return current position in RegExp bytecode - */ -static uint8_t * -re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */ +inline uint32_t JERRY_ATTR_ALWAYS_INLINE +re_bytecode_size (re_compiler_ctx_t *re_ctx_p) /**< RegExp bytecode context */ { - JERRY_ASSERT (bc_ctx_p->block_end_p >= bc_ctx_p->block_start_p); - const size_t old_size = (size_t) (bc_ctx_p->block_end_p - bc_ctx_p->block_start_p); - - /* If one of the members of RegExp bytecode context is NULL, then all member should be NULL - * (it means first allocation), otherwise all of the members should be a non NULL pointer. */ - JERRY_ASSERT ((!bc_ctx_p->current_p && !bc_ctx_p->block_end_p && !bc_ctx_p->block_start_p) - || (bc_ctx_p->current_p && bc_ctx_p->block_end_p && bc_ctx_p->block_start_p)); - - const size_t new_size = old_size + REGEXP_BYTECODE_BLOCK_SIZE; - JERRY_ASSERT (bc_ctx_p->current_p >= bc_ctx_p->block_start_p); - const size_t current_ptr_offset = (size_t) (bc_ctx_p->current_p - bc_ctx_p->block_start_p); - - bc_ctx_p->block_start_p = jmem_heap_realloc_block (bc_ctx_p->block_start_p, - old_size, - new_size); - bc_ctx_p->block_end_p = bc_ctx_p->block_start_p + new_size; - bc_ctx_p->current_p = bc_ctx_p->block_start_p + current_ptr_offset; - - return bc_ctx_p->current_p; -} /* re_realloc_regexp_bytecode_block */ + return (uint32_t) re_ctx_p->bytecode_size; +} /* re_bytecode_size */ /** * Append a new bytecode to the and of the bytecode container */ static uint8_t * -re_bytecode_reserve (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ +re_bytecode_reserve (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ const size_t size) /**< size */ { - JERRY_ASSERT (size <= REGEXP_BYTECODE_BLOCK_SIZE); - - uint8_t *current_p = bc_ctx_p->current_p; - if (current_p + size > bc_ctx_p->block_end_p) - { - current_p = re_realloc_regexp_bytecode_block (bc_ctx_p); - } - - bc_ctx_p->current_p += size; - return current_p; + const size_t old_size = re_ctx_p->bytecode_size; + const size_t new_size = old_size + size; + re_ctx_p->bytecode_start_p = jmem_heap_realloc_block (re_ctx_p->bytecode_start_p, old_size, new_size); + re_ctx_p->bytecode_size = new_size; + return re_ctx_p->bytecode_start_p + old_size; } /* re_bytecode_reserve */ /** * Insert a new bytecode to the bytecode container */ -static void -re_bytecode_insert (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ +static uint8_t * +re_bytecode_insert (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ const size_t offset, /**< distance from the start of the container */ const size_t size) /**< size */ { - JERRY_ASSERT (size <= REGEXP_BYTECODE_BLOCK_SIZE); + const size_t tail_size = re_ctx_p->bytecode_size - offset; + re_bytecode_reserve (re_ctx_p, size); - uint8_t *current_p = bc_ctx_p->current_p; - if (current_p + size > bc_ctx_p->block_end_p) - { - re_realloc_regexp_bytecode_block (bc_ctx_p); - } + uint8_t *dest_p = re_ctx_p->bytecode_start_p + offset; + memmove (dest_p + size, dest_p, tail_size); - uint8_t *dest_p = bc_ctx_p->block_start_p + offset; - const size_t bytecode_length = re_get_bytecode_length (bc_ctx_p); - if (bytecode_length - offset > 0) - { - memmove (dest_p + size, dest_p, bytecode_length - offset); - } - - bc_ctx_p->current_p += size; + return dest_p; } /* re_bytecode_insert */ /** - * Encode ecma_char_t into bytecode + * Append a byte */ -static void -re_encode_char (uint8_t *dest_p, /**< destination */ - const ecma_char_t c) /**< character */ +void +re_append_byte (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint8_t byte) /**< byte value */ { - *dest_p++ = (uint8_t) ((c >> 8) & 0xFF); - *dest_p = (uint8_t) (c & 0xFF); -} /* re_encode_char */ + uint8_t *dest_p = re_bytecode_reserve (re_ctx_p, sizeof (uint8_t)); + *dest_p = byte; +} /* re_append_byte */ /** - * Encode uint32_t into bytecode + * Insert a byte value */ -static void -re_encode_u32 (uint8_t *dest_p, /**< destination */ - const uint32_t u) /**< uint32 value */ +void +re_insert_byte (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint32_t offset, /**< distance from the start of the container */ + const uint8_t byte) /**< byte value */ { - *dest_p++ = (uint8_t) ((u >> 24) & 0xFF); - *dest_p++ = (uint8_t) ((u >> 16) & 0xFF); - *dest_p++ = (uint8_t) ((u >> 8) & 0xFF); - *dest_p = (uint8_t) (u & 0xFF); -} /* re_encode_u32 */ + uint8_t *dest_p = re_bytecode_insert (re_ctx_p, offset, sizeof (uint8_t)); + *dest_p = byte; +} /* re_insert_byte */ /** - * Get a character from the RegExp bytecode and increase the bytecode position - * - * @return ecma character + * Get a single byte and icnrease bytecode position. */ -inline ecma_char_t JERRY_ATTR_ALWAYS_INLINE -re_get_char (const uint8_t **bc_p) /**< pointer to bytecode start */ +inline uint8_t JERRY_ATTR_ALWAYS_INLINE +re_get_byte (const uint8_t **bc_p) /**< pointer to bytecode start */ { - const uint8_t *src_p = *bc_p; - ecma_char_t chr = (ecma_char_t) *src_p++; - chr = (ecma_char_t) (chr << 8); - chr = (ecma_char_t) (chr | *src_p); - (*bc_p) += sizeof (ecma_char_t); - return chr; -} /* re_get_char */ + return *((*bc_p)++); +} /* re_get_byte */ + +/** + * Append a RegExp opcode + */ +inline void JERRY_ATTR_ALWAYS_INLINE +re_append_opcode (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const re_opcode_t opcode) /**< input opcode */ +{ + re_append_byte (re_ctx_p, (uint8_t) opcode); +} /* re_append_opcode */ + +/** + * Insert a RegExp opcode + */ +inline void JERRY_ATTR_ALWAYS_INLINE +re_insert_opcode (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint32_t offset, /**< distance from the start of the container */ + const re_opcode_t opcode) /**< input opcode */ +{ + re_insert_byte (re_ctx_p, offset, (uint8_t) opcode); +} /* re_insert_opcode */ /** * Get a RegExp opcode and increase the bytecode position @@ -165,310 +136,497 @@ re_get_char (const uint8_t **bc_p) /**< pointer to bytecode start */ inline re_opcode_t JERRY_ATTR_ALWAYS_INLINE re_get_opcode (const uint8_t **bc_p) /**< pointer to bytecode start */ { - return (re_opcode_t) *((*bc_p)++); + return (re_opcode_t) re_get_byte (bc_p); } /* re_get_opcode */ /** - * Get a parameter of a RegExp opcode and increase the bytecode position - * - * @return opcode parameter + * Encode 2 byte unsigned integer into the bytecode */ -inline uint32_t JERRY_ATTR_ALWAYS_INLINE -re_get_value (const uint8_t **bc_p) /**< pointer to bytecode start */ +static void +re_encode_u16 (uint8_t *dest_p, /**< destination */ + const uint16_t value) /**< value */ { - const uint8_t *src_p = *bc_p; - uint32_t value = (uint32_t) (*src_p++); - value <<= 8; - value |= ((uint32_t) (*src_p++)); - value <<= 8; - value |= ((uint32_t) (*src_p++)); - value <<= 8; - value |= ((uint32_t) (*src_p++)); + *dest_p++ = (uint8_t) ((value >> 8) & 0xFF); + *dest_p = (uint8_t) (value & 0xFF); +} /* re_encode_u16 */ - (*bc_p) += sizeof (uint32_t); +/** + * Encode 4 byte unsigned integer into the bytecode + */ +static void +re_encode_u32 (uint8_t *dest_p, /**< destination */ + const uint32_t value) /**< value */ +{ + *dest_p++ = (uint8_t) ((value >> 24) & 0xFF); + *dest_p++ = (uint8_t) ((value >> 16) & 0xFF); + *dest_p++ = (uint8_t) ((value >> 8) & 0xFF); + *dest_p = (uint8_t) (value & 0xFF); +} /* re_encode_u32 */ + +/** + * Decode 2 byte unsigned integer from bytecode + * + * @return uint16_t value + */ +static uint16_t +re_decode_u16 (const uint8_t *src_p) /**< source */ +{ + uint16_t value = (uint16_t) (((uint16_t) *src_p++) << 8); + value = (uint16_t) (value + *src_p++); + return value; +} /* re_decode_u16 */ + +/** + * Decode 4 byte unsigned integer from bytecode + * + * @return uint32_t value + */ +static uint32_t JERRY_ATTR_NOINLINE +re_decode_u32 (const uint8_t *src_p) /**< source */ +{ + uint32_t value = (uint32_t) (((uint32_t) *src_p++) << 24); + value += (uint32_t) (((uint32_t) *src_p++) << 16); + value += (uint32_t) (((uint32_t) *src_p++) << 8); + value += (uint32_t) (*src_p++); + return value; +} /* re_decode_u32 */ + +/** + * Get the encoded size of an uint32_t value. + * + * @return encoded value size + */ +inline static size_t JERRY_ATTR_ALWAYS_INLINE +re_get_encoded_value_size (uint32_t value) /**< value */ +{ + if (JERRY_LIKELY (value <= RE_VALUE_1BYTE_MAX)) + { + return 1; + } + + return 5; +} /* re_get_encoded_value_size */ + +/* + * Encode a value to the specified position in the bytecode. + */ +static void +re_encode_value (uint8_t *dest_p, /**< position in bytecode */ + const uint32_t value) /**< value */ +{ + if (JERRY_LIKELY (value <= RE_VALUE_1BYTE_MAX)) + { + *dest_p = (uint8_t) value; + return; + } + + *dest_p++ = (uint8_t) (RE_VALUE_4BYTE_MARKER); + re_encode_u32 (dest_p, value); +} /* re_encode_value */ + +/** + * Append a value to the end of the bytecode. + */ +void +re_append_value (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint32_t value) /**< value */ +{ + const size_t size = re_get_encoded_value_size (value); + uint8_t *dest_p = re_bytecode_reserve (re_ctx_p, size); + re_encode_value (dest_p, value); +} /* re_append_value */ + +/** + * Insert a value into the bytecode at a specific offset. + */ +void +re_insert_value (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint32_t offset, /**< bytecode offset */ + const uint32_t value) /**< value */ +{ + const size_t size = re_get_encoded_value_size (value); + uint8_t *dest_p = re_bytecode_insert (re_ctx_p, offset, size); + re_encode_value (dest_p, value); +} /* re_insert_value */ + +/** + * Read an encoded value from the bytecode. + * + * @return decoded value + */ +uint32_t JERRY_ATTR_ALWAYS_INLINE +re_get_value (const uint8_t **bc_p) /** refence to bytecode pointer */ +{ + uint32_t value = *(*bc_p)++; + if (JERRY_LIKELY (value <= RE_VALUE_1BYTE_MAX)) + { + return value; + } + + value = re_decode_u32 (*bc_p); + *bc_p += sizeof (uint32_t); return value; } /* re_get_value */ -/** - * Get length of bytecode - * - * @return bytecode length (unsigned integer) - */ -inline uint32_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE -re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */ -{ - return ((uint32_t) (bc_ctx_p->current_p - bc_ctx_p->block_start_p)); -} /* re_get_bytecode_length */ - -/** - * Append a RegExp opcode - */ -void -re_append_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - const re_opcode_t opcode) /**< input opcode */ -{ - uint8_t *dest_p = re_bytecode_reserve (bc_ctx_p, sizeof (uint8_t)); - *dest_p = (uint8_t) opcode; -} /* re_append_opcode */ - -/** - * Append a parameter of a RegExp opcode - */ -void -re_append_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - const uint32_t value) /**< input value */ -{ - uint8_t *dest_p = re_bytecode_reserve (bc_ctx_p, sizeof (uint32_t)); - re_encode_u32 (dest_p, value); -} /* re_append_u32 */ - /** * Append a character to the RegExp bytecode */ void -re_append_char (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - const ecma_char_t input_char) /**< input char */ +re_append_char (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const lit_code_point_t cp) /**< code point */ { - uint8_t *dest_p = re_bytecode_reserve (bc_ctx_p, sizeof (ecma_char_t)); - re_encode_char (dest_p, input_char); +#if ENABLED (JERRY_ES2015) + const size_t size = (re_ctx_p->flags & RE_FLAG_UNICODE) ? sizeof (lit_code_point_t) : sizeof (ecma_char_t); +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (re_ctx_p); + const size_t size = sizeof (ecma_char_t); +#endif /* !ENABLED (JERRY_ES2015) */ + + uint8_t *dest_p = re_bytecode_reserve (re_ctx_p, size); + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + re_encode_u32 (dest_p, cp); + return; + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (cp <= LIT_UTF16_CODE_UNIT_MAX); + re_encode_u16 (dest_p, (ecma_char_t) cp); } /* re_append_char */ /** - * Append a jump offset parameter of a RegExp opcode + * Append a character to the RegExp bytecode */ void -re_append_jump_offset (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - uint32_t value) /**< input value */ +re_insert_char (re_compiler_ctx_t *re_ctx_p, /**< RegExp bytecode context */ + const uint32_t offset, /**< bytecode offset */ + const lit_code_point_t cp) /**< code point*/ { - value += (uint32_t) (sizeof (uint32_t)); - re_append_u32 (bc_ctx_p, value); -} /* re_append_jump_offset */ +#if ENABLED (JERRY_ES2015) + const size_t size = (re_ctx_p->flags & RE_FLAG_UNICODE) ? sizeof (lit_code_point_t) : sizeof (ecma_char_t); +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (re_ctx_p); + const size_t size = sizeof (ecma_char_t); +#endif /* !ENABLED (JERRY_ES2015) */ + + uint8_t *dest_p = re_bytecode_insert (re_ctx_p, offset, size); + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + re_encode_u32 (dest_p, cp); + return; + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (cp <= LIT_UTF16_CODE_UNIT_MAX); + re_encode_u16 (dest_p, (ecma_char_t) cp); +} /* re_insert_char */ /** - * Insert a RegExp opcode + * Decode a character from the bytecode. + * + * @return decoded character */ -void -re_insert_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - const uint32_t offset, /**< distance from the start of the container */ - const re_opcode_t opcode) /**< input opcode */ +inline lit_code_point_t JERRY_ATTR_ALWAYS_INLINE +re_get_char (const uint8_t **bc_p, /**< reference to bytecode pointer */ + bool unicode) /**< full unicode mode */ { - re_bytecode_insert (bc_ctx_p, offset, sizeof (uint8_t)); - *(bc_ctx_p->block_start_p + offset) = (uint8_t) opcode; -} /* re_insert_opcode */ + lit_code_point_t cp; -/** - * Insert a parameter of a RegExp opcode - */ -void -re_insert_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */ - uint32_t offset, /**< distance from the start of the container */ - uint32_t value) /**< input value */ -{ - re_bytecode_insert (bc_ctx_p, offset, sizeof (uint32_t)); - re_encode_u32 (bc_ctx_p->block_start_p + offset, value); -} /* re_insert_u32 */ +#if !ENABLED (JERRY_ES2015) + JERRY_UNUSED (unicode); +#else /* ENABLED (JERRY_ES2015) */ + if (unicode) + { + cp = re_decode_u32 (*bc_p); + *bc_p += sizeof (lit_code_point_t); + } + else +#endif /* ENABLED (JERRY_ES2015) */ + { + cp = re_decode_u16 (*bc_p); + *bc_p += sizeof (ecma_char_t); + } + + return cp; +} /* re_get_char */ #if ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) +static uint32_t +re_get_bytecode_offset (const uint8_t *start_p, /**< bytecode start pointer */ + const uint8_t *current_p) /**< current bytecode pointer */ +{ + return (uint32_t) ((uintptr_t) current_p - (uintptr_t) start_p); +} /* re_get_bytecode_offset */ + /** * RegExp bytecode dumper */ void -re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */ +re_dump_bytecode (re_compiler_ctx_t *re_ctx_p) /**< RegExp bytecode context */ { - re_compiled_code_t *compiled_code_p = (re_compiled_code_t *) bc_ctx_p->block_start_p; - JERRY_DEBUG_MSG ("%d ", compiled_code_p->header.status_flags); - JERRY_DEBUG_MSG ("%d ", compiled_code_p->captures_count); - JERRY_DEBUG_MSG ("%d | ", compiled_code_p->non_captures_count); + static const char escape_chars[] = {'d', 'D', 'w', 'W', 's', 'S'}; - const uint8_t *bytecode_p = (const uint8_t *) (compiled_code_p + 1); + re_compiled_code_t *compiled_code_p = (re_compiled_code_t *) re_ctx_p->bytecode_start_p; + JERRY_DEBUG_MSG ("Flags: 0x%x ", compiled_code_p->header.status_flags); + JERRY_DEBUG_MSG ("Capturing groups: %d ", compiled_code_p->captures_count); + JERRY_DEBUG_MSG ("Non-capturing groups: %d\n", compiled_code_p->non_captures_count); - re_opcode_t op; - while ((op = re_get_opcode (&bytecode_p))) + const uint8_t *bytecode_start_p = (const uint8_t *) (compiled_code_p + 1); + const uint8_t *bytecode_p = bytecode_start_p; + + while (true) { + JERRY_DEBUG_MSG ("[%3u] ", (uint32_t) ((uintptr_t) bytecode_p - (uintptr_t) bytecode_start_p)); + re_opcode_t op = *bytecode_p++; switch (op) { - case RE_OP_MATCH: + case RE_OP_ALTERNATIVE_START: { - JERRY_DEBUG_MSG ("MATCH, "); + JERRY_DEBUG_MSG ("ALTERNATIVE_START "); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); break; } - case RE_OP_CHAR: + case RE_OP_ALTERNATIVE_NEXT: { - JERRY_DEBUG_MSG ("CHAR "); - JERRY_DEBUG_MSG ("%c, ", (char) re_get_char (&bytecode_p)); + JERRY_DEBUG_MSG ("ALTERNATIVE_NEXT "); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); break; } - case RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START: + case RE_OP_NO_ALTERNATIVE: { - JERRY_DEBUG_MSG ("N"); - /* FALLTHRU */ - } - case RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START: - { - JERRY_DEBUG_MSG ("GZ_START "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("NO_ALTERNATIVES\n"); break; } - case RE_OP_CAPTURE_GROUP_START: + case RE_OP_CAPTURING_GROUP_START: { - JERRY_DEBUG_MSG ("START "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("CAPTURING_GROUP_START "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("capture count: %u, ", re_get_value (&bytecode_p)); + + const uint32_t qmin = re_get_value (&bytecode_p); + JERRY_DEBUG_MSG ("qmin: %u", qmin); + if (qmin == 0) + { + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG (", tail offset: [%3u]\n", offset); + } + else + { + JERRY_DEBUG_MSG ("\n"); + } + break; } - case RE_OP_CAPTURE_NON_GREEDY_GROUP_END: + case RE_OP_NON_CAPTURING_GROUP_START: { - JERRY_DEBUG_MSG ("N"); - /* FALLTHRU */ - } - case RE_OP_CAPTURE_GREEDY_GROUP_END: - { - JERRY_DEBUG_MSG ("G_END "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("NON_CAPTURING_GROUP_START "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("capture start: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("capture count: %u, ", re_get_value (&bytecode_p)); + + const uint32_t qmin = re_get_value (&bytecode_p); + JERRY_DEBUG_MSG ("qmin: %u", qmin); + if (qmin == 0) + { + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG (", tail offset: [%3u]\n", offset); + } + else + { + JERRY_DEBUG_MSG ("\n"); + } + break; } - case RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START: + case RE_OP_GREEDY_CAPTURING_GROUP_END: { - JERRY_DEBUG_MSG ("N"); - /* FALLTHRU */ - } - case RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START: - { - JERRY_DEBUG_MSG ("GZ_NC_START "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("GREEDY_CAPTURING_GROUP_END "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u\n", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); break; } - case RE_OP_NON_CAPTURE_GROUP_START: + case RE_OP_LAZY_CAPTURING_GROUP_END: { - JERRY_DEBUG_MSG ("NC_START "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("LAZY_CAPTURING_GROUP_END "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u\n", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); break; } - case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END: + case RE_OP_GREEDY_NON_CAPTURING_GROUP_END: { - JERRY_DEBUG_MSG ("N"); - /* FALLTHRU */ - } - case RE_OP_NON_CAPTURE_GREEDY_GROUP_END: - { - JERRY_DEBUG_MSG ("G_NC_END "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("GREEDY_NON_CAPTURING_GROUP_END "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u\n", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); break; } - case RE_OP_SAVE_AT_START: + case RE_OP_LAZY_NON_CAPTURING_GROUP_END: { - JERRY_DEBUG_MSG ("RE_START "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); - break; - } - case RE_OP_SAVE_AND_MATCH: - { - JERRY_DEBUG_MSG ("RE_END, "); + JERRY_DEBUG_MSG ("LAZY_NON_CAPTURING_GROUP_END "); + JERRY_DEBUG_MSG ("idx: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u\n", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); break; } case RE_OP_GREEDY_ITERATOR: { JERRY_DEBUG_MSG ("GREEDY_ITERATOR "); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u, ", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); break; } - case RE_OP_NON_GREEDY_ITERATOR: + case RE_OP_LAZY_ITERATOR: { - JERRY_DEBUG_MSG ("NON_GREEDY_ITERATOR "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("LAZY_ITERATOR "); + JERRY_DEBUG_MSG ("qmin: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("qmax: %u, ", re_get_value (&bytecode_p) - RE_QMAX_OFFSET); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); break; } - case RE_OP_PERIOD: + case RE_OP_ITERATOR_END: { - JERRY_DEBUG_MSG ("PERIOD "); - break; - } - case RE_OP_ALTERNATIVE: - { - JERRY_DEBUG_MSG ("ALTERNATIVE "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); - break; - } - case RE_OP_ASSERT_START: - { - JERRY_DEBUG_MSG ("ASSERT_START "); - break; - } - case RE_OP_ASSERT_END: - { - JERRY_DEBUG_MSG ("ASSERT_END "); - break; - } - case RE_OP_ASSERT_WORD_BOUNDARY: - { - JERRY_DEBUG_MSG ("ASSERT_WORD_BOUNDARY "); - break; - } - case RE_OP_ASSERT_NOT_WORD_BOUNDARY: - { - JERRY_DEBUG_MSG ("ASSERT_NOT_WORD_BOUNDARY "); - break; - } - case RE_OP_LOOKAHEAD_POS: - { - JERRY_DEBUG_MSG ("LOOKAHEAD_POS "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); - break; - } - case RE_OP_LOOKAHEAD_NEG: - { - JERRY_DEBUG_MSG ("LOOKAHEAD_NEG "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("ITERATOR_END\n"); break; } case RE_OP_BACKREFERENCE: { JERRY_DEBUG_MSG ("BACKREFERENCE "); - JERRY_DEBUG_MSG ("%d, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("idx: %d\n", re_get_value (&bytecode_p)); break; } - case RE_OP_INV_CHAR_CLASS: + case RE_OP_ASSERT_LINE_START: { - JERRY_DEBUG_MSG ("INV_"); - /* FALLTHRU */ + JERRY_DEBUG_MSG ("ASSERT_LINE_START\n"); + break; + } + case RE_OP_ASSERT_LINE_END: + { + JERRY_DEBUG_MSG ("ASSERT_LINE_END\n"); + break; + } + case RE_OP_ASSERT_LOOKAHEAD_POS: + { + JERRY_DEBUG_MSG ("ASSERT_LOOKAHEAD_POS "); + JERRY_DEBUG_MSG ("qmin: %u, ", *bytecode_p++); + JERRY_DEBUG_MSG ("capture start: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("capture count: %u, ", re_get_value (&bytecode_p)); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); + break; + } + case RE_OP_ASSERT_LOOKAHEAD_NEG: + { + JERRY_DEBUG_MSG ("ASSERT_LOOKAHEAD_NEG "); + JERRY_DEBUG_MSG ("qmin: %u, ", *bytecode_p++); + JERRY_DEBUG_MSG ("capture start: %u, ", re_get_value (&bytecode_p)); + JERRY_DEBUG_MSG ("capture count: %u, ", re_get_value (&bytecode_p)); + const uint32_t offset = re_get_value (&bytecode_p) + re_get_bytecode_offset (bytecode_start_p, bytecode_p); + JERRY_DEBUG_MSG ("tail offset: [%3u]\n", offset); + break; + } + case RE_OP_ASSERT_END: + { + JERRY_DEBUG_MSG ("ASSERT_END\n"); + break; + } + case RE_OP_ASSERT_WORD_BOUNDARY: + { + JERRY_DEBUG_MSG ("ASSERT_WORD_BOUNDARY\n"); + break; + } + case RE_OP_ASSERT_NOT_WORD_BOUNDARY: + { + JERRY_DEBUG_MSG ("ASSERT_NOT_WORD_BOUNDARY\n"); + break; + } + case RE_OP_CLASS_ESCAPE: + { + ecma_class_escape_t escape = (ecma_class_escape_t) *bytecode_p++; + JERRY_DEBUG_MSG ("CLASS_ESCAPE \\%c\n", escape_chars[escape]); + break; } case RE_OP_CHAR_CLASS: { JERRY_DEBUG_MSG ("CHAR_CLASS "); - uint32_t num_of_class = re_get_value (&bytecode_p); - JERRY_DEBUG_MSG ("%d", num_of_class); - while (num_of_class) + uint8_t flags = *bytecode_p++; + uint32_t char_count = (flags & RE_CLASS_HAS_CHARS) ? re_get_value (&bytecode_p) : 0; + uint32_t range_count = (flags & RE_CLASS_HAS_RANGES) ? re_get_value (&bytecode_p) : 0; + + if (flags & RE_CLASS_INVERT) { - JERRY_DEBUG_MSG (" %d", re_get_char (&bytecode_p)); - JERRY_DEBUG_MSG ("-%d", re_get_char (&bytecode_p)); - num_of_class--; + JERRY_DEBUG_MSG ("inverted "); } - JERRY_DEBUG_MSG (", "); + + JERRY_DEBUG_MSG ("escapes: "); + uint8_t escape_count = flags & RE_CLASS_ESCAPE_COUNT_MASK; + while (escape_count--) + { + JERRY_DEBUG_MSG ("\\%c, ", escape_chars[*bytecode_p++]); + } + + JERRY_DEBUG_MSG ("chars: "); + while (char_count--) + { + JERRY_DEBUG_MSG ("\\u%04x, ", re_get_char (&bytecode_p, re_ctx_p->flags & RE_FLAG_UNICODE)); + } + + JERRY_DEBUG_MSG ("ranges: "); + while (range_count--) + { + const lit_code_point_t begin = re_get_char (&bytecode_p, re_ctx_p->flags & RE_FLAG_UNICODE); + const lit_code_point_t end = re_get_char (&bytecode_p, re_ctx_p->flags & RE_FLAG_UNICODE); + JERRY_DEBUG_MSG ("\\u%04x-\\u%04x, ", begin, end); + } + + JERRY_DEBUG_MSG ("\n"); break; } +#if ENABLED (JERRY_ES2015) + case RE_OP_UNICODE_PERIOD: + { + JERRY_DEBUG_MSG ("UNICODE_PERIOD\n"); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + case RE_OP_PERIOD: + { + JERRY_DEBUG_MSG ("PERIOD\n"); + break; + } + case RE_OP_CHAR: + { + JERRY_DEBUG_MSG ("CHAR \\u%04x\n", re_get_char (&bytecode_p, re_ctx_p->flags & RE_FLAG_UNICODE)); + break; + } + case RE_OP_BYTE: + { + const uint8_t ch = *bytecode_p++; + JERRY_DEBUG_MSG ("BYTE \\u%04x '%c'\n", ch, (char) ch); + break; + } + case RE_OP_EOF: + { + JERRY_DEBUG_MSG ("EOF\n"); + return; + } default: { - JERRY_DEBUG_MSG ("UNKNOWN(%d), ", (uint32_t) op); + JERRY_DEBUG_MSG ("UNKNOWN(%d)\n", (uint32_t) op); break; } } } - JERRY_DEBUG_MSG ("EOF\n"); } /* re_dump_bytecode */ #endif /* ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) */ diff --git a/jerry-core/parser/regexp/re-bytecode.h b/jerry-core/parser/regexp/re-bytecode.h index 715170bb..2a293a19 100644 --- a/jerry-core/parser/regexp/re-bytecode.h +++ b/jerry-core/parser/regexp/re-bytecode.h @@ -19,6 +19,7 @@ #if ENABLED (JERRY_BUILTIN_REGEXP) #include "ecma-globals.h" +#include "re-compiler-context.h" /** \addtogroup parser Parser * @{ @@ -40,43 +41,57 @@ */ #define RE_FLAGS_MASK 0x3F +/** + * Maximum value that can be encoded in the RegExp bytecode as a single byte. + */ +#define RE_VALUE_1BYTE_MAX 0xFE + +/** + * Marker that signals that the actual value is enocded in the following 4 bytes in the bytecode. + */ +#define RE_VALUE_4BYTE_MARKER 0xFF + /** * RegExp opcodes */ typedef enum { - RE_OP_EOF, - /* Group opcode order is important, because RE_IS_CAPTURE_GROUP is based on it. - * Change it carefully. Capture opcodes should be at first. - */ - RE_OP_CAPTURE_GROUP_START, /**< group start */ - RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START, /**< greedy zero group start */ - RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-greedy zero group start */ - RE_OP_CAPTURE_GREEDY_GROUP_END, /**< greedy group end */ - RE_OP_CAPTURE_NON_GREEDY_GROUP_END, /**< non-greedy group end */ - RE_OP_NON_CAPTURE_GROUP_START, /**< non-capture group start */ - RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START, /**< non-capture greedy zero group start */ - RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-capture non-greedy zero group start */ - RE_OP_NON_CAPTURE_GREEDY_GROUP_END, /**< non-capture greedy group end */ - RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END, /**< non-capture non-greedy group end */ + RE_OP_EOF, /**< end of pattern */ + + RE_OP_ALTERNATIVE_START, /**< start of alternatives */ + RE_OP_ALTERNATIVE_NEXT, /**< next alternative */ + RE_OP_NO_ALTERNATIVE, /**< no alternative */ + + RE_OP_CAPTURING_GROUP_START, /**< start of a capturing group */ + RE_OP_NON_CAPTURING_GROUP_START, /**< start of a non-capturing group */ + + RE_OP_GREEDY_CAPTURING_GROUP_END, /**< end of a greedy capturing group */ + RE_OP_GREEDY_NON_CAPTURING_GROUP_END, /**< end of a greedy non-capturing group */ + RE_OP_LAZY_CAPTURING_GROUP_END, /**< end of a lazy capturing group */ + RE_OP_LAZY_NON_CAPTURING_GROUP_END, /**< end of a lazy non-capturing group */ - RE_OP_MATCH, /**< match */ - RE_OP_CHAR, /**< any character */ - RE_OP_SAVE_AT_START, /**< save at start */ - RE_OP_SAVE_AND_MATCH, /**< save and match */ - RE_OP_PERIOD, /**< "." */ - RE_OP_ALTERNATIVE, /**< "|" */ RE_OP_GREEDY_ITERATOR, /**< greedy iterator */ - RE_OP_NON_GREEDY_ITERATOR, /**< non-greedy iterator */ - RE_OP_ASSERT_START, /**< "^" */ - RE_OP_ASSERT_END, /**< "$" */ - RE_OP_ASSERT_WORD_BOUNDARY, /**< "\b" */ - RE_OP_ASSERT_NOT_WORD_BOUNDARY, /**< "\B" */ - RE_OP_LOOKAHEAD_POS, /**< lookahead pos */ - RE_OP_LOOKAHEAD_NEG, /**< lookahead neg */ - RE_OP_BACKREFERENCE, /**< "\[0..9]" */ - RE_OP_CHAR_CLASS, /**< "[ ]" */ - RE_OP_INV_CHAR_CLASS /**< "[^ ]" */ + RE_OP_LAZY_ITERATOR, /**< lazy iterator */ + RE_OP_ITERATOR_END, /*** end of an iterator */ + + RE_OP_BACKREFERENCE, /**< backreference */ + + RE_OP_ASSERT_LINE_START, /**< line start assertion */ + RE_OP_ASSERT_LINE_END, /**< line end assertion */ + RE_OP_ASSERT_WORD_BOUNDARY, /**< word boundary assertion */ + RE_OP_ASSERT_NOT_WORD_BOUNDARY, /**< not word boundary assertion */ + RE_OP_ASSERT_LOOKAHEAD_POS, /**< positive lookahead assertion */ + RE_OP_ASSERT_LOOKAHEAD_NEG, /**< negative lookahead assertion */ + RE_OP_ASSERT_END, /**< end of an assertion */ + + RE_OP_CLASS_ESCAPE, /**< class escape */ + RE_OP_CHAR_CLASS, /**< character class */ +#if ENABLED (JERRY_ES2015) + RE_OP_UNICODE_PERIOD, /**< period in full unicode mode */ +#endif /* ENABLED (JERRY_ES2015) */ + RE_OP_PERIOD, /**< period in non-unicode mode */ + RE_OP_CHAR, /**< any code point */ + RE_OP_BYTE, /**< 1-byte utf8 character */ } re_opcode_t; /** @@ -85,42 +100,31 @@ typedef enum typedef struct { ecma_compiled_code_t header; /**< compiled code header */ + uint32_t captures_count; /**< number of capturing groups */ + uint32_t non_captures_count; /**< number of non-capturing groups */ ecma_value_t source; /**< original RegExp pattern */ - uint32_t captures_count; /**< number of capturing brackets */ - uint32_t non_captures_count; /**< number of non capturing brackets */ } re_compiled_code_t; -/** - * Context of RegExp bytecode container - */ -typedef struct -{ - uint8_t *block_start_p; /**< start of bytecode block */ - uint8_t *block_end_p; /**< end of bytecode block */ - uint8_t *current_p; /**< current position in bytecode */ -} re_bytecode_ctx_t; +void re_initialize_regexp_bytecode (re_compiler_ctx_t *re_ctx_p); +uint32_t re_bytecode_size (re_compiler_ctx_t *re_ctx_p); + +void re_append_opcode (re_compiler_ctx_t *re_ctx_p, const re_opcode_t opcode); +void re_append_byte (re_compiler_ctx_t *re_ctx_p, const uint8_t byte); +void re_append_char (re_compiler_ctx_t *re_ctx_p, const lit_code_point_t cp); +void re_append_value (re_compiler_ctx_t *re_ctx_p, const uint32_t value); + +void re_insert_opcode (re_compiler_ctx_t *re_ctx_p, const uint32_t offset, const re_opcode_t opcode); +void re_insert_byte (re_compiler_ctx_t *re_ctx_p, const uint32_t offset, const uint8_t byte); +void re_insert_char (re_compiler_ctx_t *re_ctx_p, const uint32_t offset, const lit_code_point_t cp); +void re_insert_value (re_compiler_ctx_t *re_ctx_p, const uint32_t offset, const uint32_t value); re_opcode_t re_get_opcode (const uint8_t **bc_p); -ecma_char_t re_get_char (const uint8_t **bc_p); +uint8_t re_get_byte (const uint8_t **bc_p); +lit_code_point_t re_get_char (const uint8_t **bc_p, bool unicode); uint32_t re_get_value (const uint8_t **bc_p); -uint32_t JERRY_ATTR_PURE re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p); - -void re_initialize_regexp_bytecode (re_bytecode_ctx_t *bc_ctx_p); - -void re_append_opcode (re_bytecode_ctx_t *bc_ctx_p, const re_opcode_t opcode); -void re_append_u32 (re_bytecode_ctx_t *bc_ctx_p, const uint32_t value); -void re_append_char (re_bytecode_ctx_t *bc_ctx_p, const ecma_char_t input_char); -void re_append_jump_offset (re_bytecode_ctx_t *bc_ctx_p, uint32_t value); - -void re_insert_opcode (re_bytecode_ctx_t *bc_ctx_p, const uint32_t offset, const re_opcode_t opcode); -void re_insert_u32 (re_bytecode_ctx_t *bc_ctx_p, const uint32_t offset, const uint32_t value); -void re_bytecode_list_insert (re_bytecode_ctx_t *bc_ctx_p, - const size_t offset, - const uint8_t *bytecode_p, - const size_t length); #if ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) -void re_dump_bytecode (re_bytecode_ctx_t *bc_ctx); +void re_dump_bytecode (re_compiler_ctx_t *bc_ctx); #endif /* ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) */ /** diff --git a/jerry-core/parser/regexp/re-compiler-context.h b/jerry-core/parser/regexp/re-compiler-context.h new file mode 100644 index 00000000..6d7b7537 --- /dev/null +++ b/jerry-core/parser/regexp/re-compiler-context.h @@ -0,0 +1,60 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RE_COMPILER_CONTEXT_H +#define RE_COMPILER_CONTEXT_H + +#if ENABLED (JERRY_BUILTIN_REGEXP) + +#include "re-token.h" + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup regexparser Regular expression + * @{ + * + * \addtogroup regexparser_compiler Compiler + * @{ + */ + +/** + * RegExp compiler context + */ +typedef struct +{ + const lit_utf8_byte_t *input_start_p; /**< start of input pattern */ + const lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */ + const lit_utf8_byte_t *input_end_p; /**< end of input pattern */ + + uint8_t *bytecode_start_p; /**< start of bytecode block */ + size_t bytecode_size; /**< size of bytecode */ + + uint32_t captures_count; /**< number of capture groups */ + uint32_t non_captures_count; /**< number of non-capture groups */ + + int groups_count; /**< number of groups */ + uint16_t flags; /**< RegExp flags */ + re_token_t token; /**< current token */ +} re_compiler_ctx_t; + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#endif /* !RE_COMPILER_CONTEXT_H */ diff --git a/jerry-core/parser/regexp/re-compiler.c b/jerry-core/parser/regexp/re-compiler.c index 45f89c51..c28fd170 100644 --- a/jerry-core/parser/regexp/re-compiler.c +++ b/jerry-core/parser/regexp/re-compiler.c @@ -23,6 +23,7 @@ #include "jmem.h" #include "re-bytecode.h" #include "re-compiler.h" +#include "re-compiler-context.h" #include "re-parser.h" #if ENABLED (JERRY_BUILTIN_REGEXP) @@ -38,865 +39,140 @@ */ /** - * Insert simple atom iterator + * Search for the given pattern in the RegExp cache. * - * @return empty ecma value - if inserted successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value + * @return pointer to bytecode if found + * NULL - otherwise */ -static ecma_value_t -re_insert_simple_iterator (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - uint32_t new_atom_start_offset) /**< atom start offset */ +static re_compiled_code_t * +re_cache_lookup (ecma_string_t *pattern_str_p, /**< pattern string */ + uint16_t flags) /**< flags */ { - uint32_t atom_code_length; - uint32_t offset; - uint32_t qmin, qmax; - - qmin = re_ctx_p->current_token.qmin; - qmax = re_ctx_p->current_token.qmax; - - if (qmin == 1 && qmax == 1) - { - return ECMA_VALUE_EMPTY; - } - else if (qmin > qmax) - { - /* ECMA-262 v5.1 15.10.2.5 */ - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: min > max.")); - } - - /* TODO: optimize bytecode length. Store 0 rather than INF */ - - re_append_opcode (re_ctx_p->bytecode_ctx_p, RE_OP_MATCH); /* complete 'sub atom' */ - uint32_t bytecode_length = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - atom_code_length = (uint32_t) (bytecode_length - new_atom_start_offset); - - offset = new_atom_start_offset; - re_insert_u32 (re_ctx_p->bytecode_ctx_p, offset, atom_code_length); - re_insert_u32 (re_ctx_p->bytecode_ctx_p, offset, qmax); - re_insert_u32 (re_ctx_p->bytecode_ctx_p, offset, qmin); - if (re_ctx_p->current_token.greedy) - { - re_insert_opcode (re_ctx_p->bytecode_ctx_p, offset, RE_OP_GREEDY_ITERATOR); - } - else - { - re_insert_opcode (re_ctx_p->bytecode_ctx_p, offset, RE_OP_NON_GREEDY_ITERATOR); - } - - return ECMA_VALUE_EMPTY; -} /* re_insert_simple_iterator */ - -/** - * Get the type of a group start - * - * @return RegExp opcode - */ -static re_opcode_t -re_get_start_opcode_type (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - bool is_capturable) /**< is capturable group */ -{ - if (is_capturable) - { - if (re_ctx_p->current_token.qmin == 0) - { - if (re_ctx_p->current_token.greedy) - { - return RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START; - } - - return RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START; - } - - return RE_OP_CAPTURE_GROUP_START; - } - - if (re_ctx_p->current_token.qmin == 0) - { - if (re_ctx_p->current_token.greedy) - { - return RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START; - } - - return RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START; - } - - return RE_OP_NON_CAPTURE_GROUP_START; -} /* re_get_start_opcode_type */ - -/** - * Get the type of a group end - * - * @return RegExp opcode - */ -static re_opcode_t -re_get_end_opcode_type (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - bool is_capturable) /**< is capturable group */ -{ - if (is_capturable) - { - if (re_ctx_p->current_token.greedy) - { - return RE_OP_CAPTURE_GREEDY_GROUP_END; - } - - return RE_OP_CAPTURE_NON_GREEDY_GROUP_END; - } - - if (re_ctx_p->current_token.greedy) - { - return RE_OP_NON_CAPTURE_GREEDY_GROUP_END; - } - - return RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END; -} /* re_get_end_opcode_type */ - -/** - * Enclose the given bytecode to a group - * - * @return empty ecma value - if inserted successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -re_insert_into_group (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - uint32_t group_start_offset, /**< offset of group start */ - uint32_t idx, /**< index of group */ - bool is_capturable) /**< is capturable group */ -{ - uint32_t qmin = re_ctx_p->current_token.qmin; - uint32_t qmax = re_ctx_p->current_token.qmax; - - if (qmin > qmax) - { - /* ECMA-262 v5.1 15.10.2.5 */ - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: min > max.")); - } - - re_opcode_t start_opcode = re_get_start_opcode_type (re_ctx_p, is_capturable); - re_opcode_t end_opcode = re_get_end_opcode_type (re_ctx_p, is_capturable); - - uint32_t start_head_offset_len = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - re_insert_u32 (re_ctx_p->bytecode_ctx_p, group_start_offset, idx); - re_insert_opcode (re_ctx_p->bytecode_ctx_p, group_start_offset, start_opcode); - start_head_offset_len = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - start_head_offset_len; - re_append_opcode (re_ctx_p->bytecode_ctx_p, end_opcode); - re_append_u32 (re_ctx_p->bytecode_ctx_p, idx); - re_append_u32 (re_ctx_p->bytecode_ctx_p, qmin); - re_append_u32 (re_ctx_p->bytecode_ctx_p, qmax); - - group_start_offset += start_head_offset_len; - re_append_jump_offset (re_ctx_p->bytecode_ctx_p, - re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - group_start_offset); - - if (start_opcode != RE_OP_CAPTURE_GROUP_START && start_opcode != RE_OP_NON_CAPTURE_GROUP_START) - { - re_insert_u32 (re_ctx_p->bytecode_ctx_p, - group_start_offset, - re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - group_start_offset); - } - - return ECMA_VALUE_EMPTY; -} /* re_insert_into_group */ - -/** - * Enclose the given bytecode to a group and inster jump value - * - * @return empty ecma value - if inserted successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -re_insert_into_group_with_jump (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - uint32_t group_start_offset, /**< offset of group start */ - uint32_t idx, /**< index of group */ - bool is_capturable) /**< is capturable group */ -{ - re_insert_u32 (re_ctx_p->bytecode_ctx_p, - group_start_offset, - re_get_bytecode_length (re_ctx_p->bytecode_ctx_p) - group_start_offset); - return re_insert_into_group (re_ctx_p, group_start_offset, idx, is_capturable); -} /* re_insert_into_group_with_jump */ - -/** - * Append a character class range to the bytecode - */ -static void -re_append_char_class (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - ecma_char_t start, /**< character class range from */ - ecma_char_t end) /**< character class range to */ -{ - re_append_char (re_ctx_p->bytecode_ctx_p, ecma_regexp_canonicalize (start, re_ctx_p->flags & RE_FLAG_IGNORE_CASE)); - re_append_char (re_ctx_p->bytecode_ctx_p, ecma_regexp_canonicalize (end, re_ctx_p->flags & RE_FLAG_IGNORE_CASE)); - re_ctx_p->parser_ctx_p->classes_count++; -} /* re_append_char_class */ - -/** - * Read the input pattern and parse the range of character class - * - * @return empty ecma value - if parsed successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -re_parse_char_class (re_compiler_ctx_t *re_ctx_p, /**< number of classes */ - re_token_t *out_token_p) /**< [out] output token */ -{ - re_parser_ctx_t *const parser_ctx_p = re_ctx_p->parser_ctx_p; - out_token_p->qmax = out_token_p->qmin = 1; - parser_ctx_p->classes_count = 0; - - ecma_char_t start = LIT_CHAR_UNDEF; - bool is_range = false; - const bool is_char_class = (re_ctx_p->current_token.type == RE_TOK_START_CHAR_CLASS - || re_ctx_p->current_token.type == RE_TOK_START_INV_CHAR_CLASS); - - const ecma_char_t prev_char = lit_utf8_peek_prev (parser_ctx_p->input_curr_p); - if (prev_char != LIT_CHAR_LEFT_SQUARE && prev_char != LIT_CHAR_CIRCUMFLEX) - { - lit_utf8_decr (&parser_ctx_p->input_curr_p); - lit_utf8_decr (&parser_ctx_p->input_curr_p); - } - - do - { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, end of string")); - } - - ecma_char_t ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); - - if (ch == LIT_CHAR_RIGHT_SQUARE) - { - if (start != LIT_CHAR_UNDEF) - { - re_append_char_class (re_ctx_p, start, start); - } - break; - } - else if (ch == LIT_CHAR_MINUS) - { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, end of string after '-'")); - } - - if (start != LIT_CHAR_UNDEF - && !is_range - && *parser_ctx_p->input_curr_p != LIT_CHAR_RIGHT_SQUARE) - { - is_range = true; - continue; - } - } - else if (ch == LIT_CHAR_BACKSLASH) - { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, end of string after '\\'")); - } - - ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); - - if (ch == LIT_CHAR_LOWERCASE_B) - { - ch = LIT_CHAR_BS; - } - else if (ch == LIT_CHAR_LOWERCASE_F) - { - ch = LIT_CHAR_FF; - } - else if (ch == LIT_CHAR_LOWERCASE_N) - { - ch = LIT_CHAR_LF; - } - else if (ch == LIT_CHAR_LOWERCASE_T) - { - ch = LIT_CHAR_TAB; - } - else if (ch == LIT_CHAR_LOWERCASE_R) - { - ch = LIT_CHAR_CR; - } - else if (ch == LIT_CHAR_LOWERCASE_V) - { - ch = LIT_CHAR_VTAB; - } - else if (ch == LIT_CHAR_LOWERCASE_C) - { - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p) - { - ch = *parser_ctx_p->input_curr_p; - - if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) - || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END) - || (ch >= LIT_CHAR_0 && ch <= LIT_CHAR_9)) - { - /* See ECMA-262 v5, 15.10.2.10 (Point 3) */ - ch = (ch % 32); - parser_ctx_p->input_curr_p++; - } - else - { - ch = LIT_CHAR_LOWERCASE_C; - } - } - } - else if (ch == LIT_CHAR_LOWERCASE_X && re_hex_lookup (parser_ctx_p, 2)) - { - ecma_char_t code_unit; - - if (!lit_read_code_unit_from_hex (parser_ctx_p->input_curr_p, 2, &code_unit)) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, end of string after '\\x'")); - } - - parser_ctx_p->input_curr_p += 2; - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p - && is_range == false - && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS) - { - start = code_unit; - continue; - } - - ch = code_unit; - } - else if (ch == LIT_CHAR_LOWERCASE_U && re_hex_lookup (parser_ctx_p, 4)) - { - ecma_char_t code_unit; - - if (!lit_read_code_unit_from_hex (parser_ctx_p->input_curr_p, 4, &code_unit)) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, end of string after '\\u'")); - } - - parser_ctx_p->input_curr_p += 4; - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p - && is_range == false - && lit_utf8_peek_next (parser_ctx_p->input_curr_p) == LIT_CHAR_MINUS) - { - start = code_unit; - continue; - } - - ch = code_unit; - } - else if (ch == LIT_CHAR_LOWERCASE_D) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_BEGIN, LIT_CHAR_ASCII_DIGITS_END); - ch = LIT_CHAR_UNDEF; - } - else if (ch == LIT_CHAR_UPPERCASE_D) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_ASCII_DIGITS_BEGIN - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_END + 1, LIT_UTF16_CODE_UNIT_MAX); - ch = LIT_CHAR_UNDEF; - } - else if (ch == LIT_CHAR_LOWERCASE_S) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_TAB, LIT_CHAR_CR); - re_append_char_class (re_ctx_p, LIT_CHAR_SP, LIT_CHAR_SP); - re_append_char_class (re_ctx_p, LIT_CHAR_NBSP, LIT_CHAR_NBSP); - re_append_char_class (re_ctx_p, 0x1680UL, 0x1680UL); /* Ogham Space Mark */ - re_append_char_class (re_ctx_p, 0x180EUL, 0x180EUL); /* Mongolian Vowel Separator */ - re_append_char_class (re_ctx_p, 0x2000UL, 0x200AUL); /* En Quad - Hair Space */ - re_append_char_class (re_ctx_p, LIT_CHAR_LS, LIT_CHAR_PS); - re_append_char_class (re_ctx_p, 0x202FUL, 0x202FUL); /* Narrow No-Break Space */ - re_append_char_class (re_ctx_p, 0x205FUL, 0x205FUL); /* Medium Mathematical Space */ - re_append_char_class (re_ctx_p, 0x3000UL, 0x3000UL); /* Ideographic Space */ - re_append_char_class (re_ctx_p, LIT_CHAR_BOM, LIT_CHAR_BOM); - ch = LIT_CHAR_UNDEF; - } - else if (ch == LIT_CHAR_UPPERCASE_S) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_TAB - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_CR + 1, LIT_CHAR_SP - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_SP + 1, LIT_CHAR_NBSP - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_NBSP + 1, 0x167FUL); - re_append_char_class (re_ctx_p, 0x1681UL, 0x180DUL); - re_append_char_class (re_ctx_p, 0x180FUL, 0x1FFFUL); - re_append_char_class (re_ctx_p, 0x200BUL, LIT_CHAR_LS - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_PS + 1, 0x202EUL); - re_append_char_class (re_ctx_p, 0x2030UL, 0x205EUL); - re_append_char_class (re_ctx_p, 0x2060UL, 0x2FFFUL); - re_append_char_class (re_ctx_p, 0x3001UL, LIT_CHAR_BOM - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_BOM + 1, LIT_UTF16_CODE_UNIT_MAX); - ch = LIT_CHAR_UNDEF; - } - else if (ch == LIT_CHAR_LOWERCASE_W) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_0, LIT_CHAR_9); - re_append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_A, LIT_CHAR_UPPERCASE_Z); - re_append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE, LIT_CHAR_UNDERSCORE); - re_append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_A, LIT_CHAR_LOWERCASE_Z); - ch = LIT_CHAR_UNDEF; - } - else if (ch == LIT_CHAR_UPPERCASE_W) - { - /* See ECMA-262 v5, 15.10.2.12 */ - re_append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_0 - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_9 + 1, LIT_CHAR_UPPERCASE_A - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_Z + 1, LIT_CHAR_UNDERSCORE - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE + 1, LIT_CHAR_LOWERCASE_A - 1); - re_append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_Z + 1, LIT_UTF16_CODE_UNIT_MAX); - ch = LIT_CHAR_UNDEF; - } - else if (lit_char_is_octal_digit ((ecma_char_t) ch)) - { - lit_utf8_decr (&parser_ctx_p->input_curr_p); - ch = (ecma_char_t) re_parse_octal (parser_ctx_p); - } - } /* ch == LIT_CHAR_BACKSLASH */ - - if (start != LIT_CHAR_UNDEF) - { - if (is_range) - { - if (start > ch) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class, wrong order")); - } - else - { - re_append_char_class (re_ctx_p, start, ch); - start = LIT_CHAR_UNDEF; - is_range = false; - } - } - else - { - re_append_char_class (re_ctx_p, start, start); - start = ch; - } - } - else - { - start = ch; - } - } - while (is_char_class); - - return re_parse_iterator (parser_ctx_p, out_token_p); -} /* re_parse_char_class */ - -/** - * Parse alternatives - * - * @return empty ecma value - if alternative was successfully parsed - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ - bool expect_eof) /**< expect end of file */ -{ - ECMA_CHECK_STACK_USAGE (); - uint32_t idx; - re_bytecode_ctx_t *bc_ctx_p = re_ctx_p->bytecode_ctx_p; - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - uint32_t alternative_offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - - while (ecma_is_value_empty (ret_value)) - { - ecma_value_t next_token_result = re_parse_next_token (re_ctx_p->parser_ctx_p, - &(re_ctx_p->current_token)); - if (ECMA_IS_VALUE_ERROR (next_token_result)) - { - return next_token_result; - } - - JERRY_ASSERT (ecma_is_value_empty (next_token_result)); - - uint32_t new_atom_start_offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - - switch (re_ctx_p->current_token.type) - { - case RE_TOK_START_CAPTURE_GROUP: - { - idx = re_ctx_p->captures_count++; - JERRY_TRACE_MSG ("Compile a capture group start (idx: %u)\n", (unsigned int) idx); - - ret_value = re_parse_alternative (re_ctx_p, false); - - if (ecma_is_value_empty (ret_value)) - { - ret_value = re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, true); - } - - break; - } - case RE_TOK_START_NON_CAPTURE_GROUP: - { - idx = re_ctx_p->non_captures_count++; - JERRY_TRACE_MSG ("Compile a non-capture group start (idx: %u)\n", (unsigned int) idx); - - ret_value = re_parse_alternative (re_ctx_p, false); - - if (ecma_is_value_empty (ret_value)) - { - ret_value = re_insert_into_group (re_ctx_p, new_atom_start_offset, idx, false); - } - - break; - } - case RE_TOK_CHAR: - { - JERRY_TRACE_MSG ("Compile character token: %c, qmin: %u, qmax: %u\n", - (char) re_ctx_p->current_token.value, (unsigned int) re_ctx_p->current_token.qmin, - (unsigned int) re_ctx_p->current_token.qmax); - - re_append_opcode (bc_ctx_p, RE_OP_CHAR); - re_append_char (bc_ctx_p, ecma_regexp_canonicalize ((ecma_char_t) re_ctx_p->current_token.value, - re_ctx_p->flags & RE_FLAG_IGNORE_CASE)); - - ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); - break; - } - case RE_TOK_PERIOD: - { - JERRY_TRACE_MSG ("Compile a period\n"); - re_append_opcode (bc_ctx_p, RE_OP_PERIOD); - - ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); - break; - } - case RE_TOK_ALTERNATIVE: - { - JERRY_TRACE_MSG ("Compile an alternative\n"); - re_insert_u32 (bc_ctx_p, alternative_offset, re_get_bytecode_length (bc_ctx_p) - alternative_offset); - re_append_opcode (bc_ctx_p, RE_OP_ALTERNATIVE); - alternative_offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - break; - } - case RE_TOK_ASSERT_START: - { - JERRY_TRACE_MSG ("Compile a start assertion\n"); - re_append_opcode (bc_ctx_p, RE_OP_ASSERT_START); - break; - } - case RE_TOK_ASSERT_END: - { - JERRY_TRACE_MSG ("Compile an end assertion\n"); - re_append_opcode (bc_ctx_p, RE_OP_ASSERT_END); - break; - } - case RE_TOK_ASSERT_WORD_BOUNDARY: - { - JERRY_TRACE_MSG ("Compile a word boundary assertion\n"); - re_append_opcode (bc_ctx_p, RE_OP_ASSERT_WORD_BOUNDARY); - break; - } - case RE_TOK_ASSERT_NOT_WORD_BOUNDARY: - { - JERRY_TRACE_MSG ("Compile a not word boundary assertion\n"); - re_append_opcode (bc_ctx_p, RE_OP_ASSERT_NOT_WORD_BOUNDARY); - break; - } - case RE_TOK_ASSERT_START_POS_LOOKAHEAD: - { - JERRY_TRACE_MSG ("Compile a positive lookahead assertion\n"); - idx = re_ctx_p->non_captures_count++; - re_append_opcode (bc_ctx_p, RE_OP_LOOKAHEAD_POS); - - ret_value = re_parse_alternative (re_ctx_p, false); - - if (ecma_is_value_empty (ret_value)) - { - re_append_opcode (bc_ctx_p, RE_OP_MATCH); - - ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false); - } - - break; - } - case RE_TOK_ASSERT_START_NEG_LOOKAHEAD: - { - JERRY_TRACE_MSG ("Compile a negative lookahead assertion\n"); - idx = re_ctx_p->non_captures_count++; - re_append_opcode (bc_ctx_p, RE_OP_LOOKAHEAD_NEG); - - ret_value = re_parse_alternative (re_ctx_p, false); - - if (ecma_is_value_empty (ret_value)) - { - re_append_opcode (bc_ctx_p, RE_OP_MATCH); - - ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false); - } - - break; - } - case RE_TOK_BACKREFERENCE: - { - uint32_t backref = (uint32_t) re_ctx_p->current_token.value; - idx = re_ctx_p->non_captures_count++; - - if (backref > re_ctx_p->highest_backref) - { - re_ctx_p->highest_backref = backref; - } - - JERRY_TRACE_MSG ("Compile a backreference: %u\n", (unsigned int) backref); - re_append_opcode (bc_ctx_p, RE_OP_BACKREFERENCE); - re_append_u32 (bc_ctx_p, backref); - - ret_value = re_insert_into_group_with_jump (re_ctx_p, new_atom_start_offset, idx, false); - break; - } - case RE_TOK_DIGIT: - case RE_TOK_NOT_DIGIT: - case RE_TOK_WHITE: - case RE_TOK_NOT_WHITE: - case RE_TOK_WORD_CHAR: - case RE_TOK_NOT_WORD_CHAR: - case RE_TOK_START_CHAR_CLASS: - case RE_TOK_START_INV_CHAR_CLASS: - { - JERRY_TRACE_MSG ("Compile a character class\n"); - re_append_opcode (bc_ctx_p, - re_ctx_p->current_token.type == RE_TOK_START_INV_CHAR_CLASS - ? RE_OP_INV_CHAR_CLASS - : RE_OP_CHAR_CLASS); - uint32_t offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - - ret_value = re_parse_char_class (re_ctx_p, - &(re_ctx_p->current_token)); - - if (!ECMA_IS_VALUE_ERROR (ret_value)) - { - re_insert_u32 (bc_ctx_p, offset, re_ctx_p->parser_ctx_p->classes_count); - ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); - } - - break; - } - case RE_TOK_END_GROUP: - { - JERRY_TRACE_MSG ("Compile a group end\n"); - - if (expect_eof) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexpected end of paren.")); - } - - re_insert_u32 (bc_ctx_p, alternative_offset, re_get_bytecode_length (bc_ctx_p) - alternative_offset); - return ECMA_VALUE_EMPTY; - } - case RE_TOK_EOF: - { - if (!expect_eof) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexpected end of pattern.")); - } - - re_insert_u32 (bc_ctx_p, alternative_offset, re_get_bytecode_length (bc_ctx_p) - alternative_offset); - return ECMA_VALUE_EMPTY; - } - default: - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexpected RegExp token.")); - } - } - } - - return ret_value; -} /* re_parse_alternative */ - -/** - * Search for the given pattern in the RegExp cache - * - * @return index of bytecode in cache - if found - * RE_CACHE_SIZE - otherwise - */ -static uint8_t -re_find_bytecode_in_cache (ecma_string_t *pattern_str_p, /**< pattern string */ - uint16_t flags) /**< flags */ -{ - uint8_t free_idx = RE_CACHE_SIZE; + re_compiled_code_t **cache_p = JERRY_CONTEXT (re_cache); for (uint8_t idx = 0u; idx < RE_CACHE_SIZE; idx++) { - const re_compiled_code_t *cached_bytecode_p = JERRY_CONTEXT (re_cache)[idx]; + re_compiled_code_t *cached_bytecode_p = cache_p[idx]; - if (cached_bytecode_p != NULL) + if (cached_bytecode_p == NULL) { - ecma_string_t *cached_pattern_str_p = ecma_get_string_from_value (cached_bytecode_p->source); - - if ((cached_bytecode_p->header.status_flags & RE_FLAGS_MASK) == flags - && ecma_compare_ecma_strings (cached_pattern_str_p, pattern_str_p)) - { - JERRY_TRACE_MSG ("RegExp is found in cache\n"); - return idx; - } + break; } - else + + ecma_string_t *cached_pattern_str_p = ecma_get_string_from_value (cached_bytecode_p->source); + + if ((cached_bytecode_p->header.status_flags & RE_FLAGS_MASK) == flags + && ecma_compare_ecma_strings (cached_pattern_str_p, pattern_str_p)) { - /* mark as free, so it can be overridden if the cache is full */ - free_idx = idx; + return cached_bytecode_p; } } - JERRY_TRACE_MSG ("RegExp is NOT found in cache\n"); - return free_idx; -} /* re_find_bytecode_in_cache */ + return NULL; +} /* re_cache_lookup */ /** - * Run gerbage collection in RegExp cache + * Run garbage collection in RegExp cache. */ void -re_cache_gc_run (void) +re_cache_gc (void) { + re_compiled_code_t **cache_p = JERRY_CONTEXT (re_cache); + for (uint32_t i = 0u; i < RE_CACHE_SIZE; i++) { - const re_compiled_code_t *cached_bytecode_p = JERRY_CONTEXT (re_cache)[i]; + const re_compiled_code_t *cached_bytecode_p = cache_p[i]; - if (cached_bytecode_p != NULL - && cached_bytecode_p->header.refs == 1) + if (cached_bytecode_p == NULL) { - /* Only the cache has reference for the bytecode */ - ecma_bytecode_deref ((ecma_compiled_code_t *) cached_bytecode_p); - JERRY_CONTEXT (re_cache)[i] = NULL; + break; } + + ecma_bytecode_deref ((ecma_compiled_code_t *) cached_bytecode_p); + cache_p[i] = NULL; } -} /* re_cache_gc_run */ + + JERRY_CONTEXT (re_cache_idx) = 0; +} /* re_cache_gc */ /** * Compilation of RegExp bytecode * - * @return empty ecma value - if bytecode was compiled successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value + * @return pointer to bytecode if compilation was successful + * NULL - otherwise */ -ecma_value_t -re_compile_bytecode (const re_compiled_code_t **out_bytecode_p, /**< [out] pointer to bytecode */ - ecma_string_t *pattern_str_p, /**< pattern */ +re_compiled_code_t * +re_compile_bytecode (ecma_string_t *pattern_str_p, /**< pattern */ uint16_t flags) /**< flags */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - uint8_t cache_idx = re_find_bytecode_in_cache (pattern_str_p, flags); + re_compiled_code_t *cached_bytecode_p = re_cache_lookup (pattern_str_p, flags); - if (cache_idx < RE_CACHE_SIZE) + if (cached_bytecode_p != NULL) { - *out_bytecode_p = JERRY_CONTEXT (re_cache)[cache_idx]; - - if (*out_bytecode_p != NULL) - { - ecma_bytecode_ref ((ecma_compiled_code_t *) *out_bytecode_p); - return ret_value; - } + ecma_bytecode_ref ((ecma_compiled_code_t *) cached_bytecode_p); + return cached_bytecode_p; } - /* not in the RegExp cache, so compile it */ re_compiler_ctx_t re_ctx; re_ctx.flags = flags; - re_ctx.highest_backref = 0; + re_ctx.captures_count = 1; re_ctx.non_captures_count = 0; - re_bytecode_ctx_t bc_ctx; - re_ctx.bytecode_ctx_p = &bc_ctx; - re_initialize_regexp_bytecode (&bc_ctx); + re_initialize_regexp_bytecode (&re_ctx); ECMA_STRING_TO_UTF8_STRING (pattern_str_p, pattern_start_p, pattern_start_size); - re_parser_ctx_t parser_ctx; - parser_ctx.input_start_p = pattern_start_p; - parser_ctx.input_curr_p = (lit_utf8_byte_t *) pattern_start_p; - parser_ctx.input_end_p = pattern_start_p + pattern_start_size; - parser_ctx.groups_count = -1; - re_ctx.parser_ctx_p = &parser_ctx; + re_ctx.input_start_p = pattern_start_p; + re_ctx.input_curr_p = (lit_utf8_byte_t *) pattern_start_p; + re_ctx.input_end_p = pattern_start_p + pattern_start_size; + re_ctx.groups_count = -1; /* Parse RegExp pattern */ - re_ctx.captures_count = 1; - re_append_opcode (&bc_ctx, RE_OP_SAVE_AT_START); - ecma_value_t result = re_parse_alternative (&re_ctx, true); ECMA_FINALIZE_UTF8_STRING (pattern_start_p, pattern_start_size); if (ECMA_IS_VALUE_ERROR (result)) - { - ret_value = result; - } - /* Check for invalid backreference */ - else if (re_ctx.highest_backref >= re_ctx.captures_count) - { - ret_value = ecma_raise_syntax_error ("Invalid backreference.\n"); - } - else - { - re_append_opcode (&bc_ctx, RE_OP_SAVE_AND_MATCH); - re_append_opcode (&bc_ctx, RE_OP_EOF); - - /* Initialize bytecode header */ - re_compiled_code_t *re_compiled_code_p = (re_compiled_code_t *) bc_ctx.block_start_p; - re_compiled_code_p->header.refs = 1; - re_compiled_code_p->header.status_flags = re_ctx.flags; - ecma_ref_ecma_string (pattern_str_p); - re_compiled_code_p->source = ecma_make_string_value (pattern_str_p); - re_compiled_code_p->captures_count = re_ctx.captures_count; - re_compiled_code_p->non_captures_count = re_ctx.non_captures_count; - } - - size_t byte_code_size = (size_t) (bc_ctx.block_end_p - bc_ctx.block_start_p); - - if (!ecma_is_value_empty (ret_value)) { /* Compilation failed, free bytecode. */ - JERRY_TRACE_MSG ("RegExp compilation failed!\n"); - jmem_heap_free_block (bc_ctx.block_start_p, byte_code_size); - *out_bytecode_p = NULL; + jmem_heap_free_block (re_ctx.bytecode_start_p, re_ctx.bytecode_size); + return NULL; } - else - { + + /* Align bytecode size to JMEM_ALIGNMENT so that it can be stored in the bytecode header. */ + const uint32_t final_size = JERRY_ALIGNUP (re_ctx.bytecode_size, JMEM_ALIGNMENT); + re_compiled_code_t *re_compiled_code_p = (re_compiled_code_t *) jmem_heap_realloc_block (re_ctx.bytecode_start_p, + re_ctx.bytecode_size, + final_size); + + /* Bytecoded will be inserted into the cache and returned to the caller, so refcount is implicitly set to 2. */ + re_compiled_code_p->header.refs = 2; + re_compiled_code_p->header.size = (uint16_t) (final_size >> JMEM_ALIGNMENT_LOG); + re_compiled_code_p->header.status_flags = re_ctx.flags; + + ecma_ref_ecma_string (pattern_str_p); + re_compiled_code_p->source = ecma_make_string_value (pattern_str_p); + re_compiled_code_p->captures_count = re_ctx.captures_count; + re_compiled_code_p->non_captures_count = re_ctx.non_captures_count; + #if ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) - if (JERRY_CONTEXT (jerry_init_flags) & ECMA_INIT_SHOW_REGEXP_OPCODES) - { - re_dump_bytecode (&bc_ctx); - } + if (JERRY_CONTEXT (jerry_init_flags) & ECMA_INIT_SHOW_REGEXP_OPCODES) + { + re_dump_bytecode (&re_ctx); + } #endif /* ENABLED (JERRY_REGEXP_DUMP_BYTE_CODE) */ - *out_bytecode_p = (re_compiled_code_t *) bc_ctx.block_start_p; - ((re_compiled_code_t *) bc_ctx.block_start_p)->header.size = (uint16_t) (byte_code_size >> JMEM_ALIGNMENT_LOG); + uint8_t cache_idx = JERRY_CONTEXT (re_cache_idx); - if (cache_idx == RE_CACHE_SIZE) - { - if (JERRY_CONTEXT (re_cache_idx) == RE_CACHE_SIZE) - { - JERRY_CONTEXT (re_cache_idx) = 0; - } - - JERRY_TRACE_MSG ("RegExp cache is full! Remove the element on idx: %d\n", JERRY_CONTEXT (re_cache_idx)); - - cache_idx = JERRY_CONTEXT (re_cache_idx)++; - - /* The garbage collector might run during the byte code - * allocations above and it may free this entry. */ - if (JERRY_CONTEXT (re_cache)[cache_idx] != NULL) - { - ecma_bytecode_deref ((ecma_compiled_code_t *) JERRY_CONTEXT (re_cache)[cache_idx]); - } - } - - JERRY_TRACE_MSG ("Insert bytecode into RegExp cache (idx: %d).\n", cache_idx); - ecma_bytecode_ref ((ecma_compiled_code_t *) *out_bytecode_p); - JERRY_CONTEXT (re_cache)[cache_idx] = *out_bytecode_p; + if (JERRY_CONTEXT (re_cache)[cache_idx] != NULL) + { + ecma_bytecode_deref ((ecma_compiled_code_t *) JERRY_CONTEXT (re_cache)[cache_idx]); } - return ret_value; + JERRY_CONTEXT (re_cache)[cache_idx] = re_compiled_code_p; + JERRY_CONTEXT (re_cache_idx) = (uint8_t) (cache_idx + 1) % RE_CACHE_SIZE; + + return re_compiled_code_p; } /* re_compile_bytecode */ /** diff --git a/jerry-core/parser/regexp/re-compiler.h b/jerry-core/parser/regexp/re-compiler.h index 8dd2a72e..b5f1e8a7 100644 --- a/jerry-core/parser/regexp/re-compiler.h +++ b/jerry-core/parser/regexp/re-compiler.h @@ -20,7 +20,6 @@ #include "ecma-globals.h" #include "re-bytecode.h" -#include "re-parser.h" /** \addtogroup parser Parser * @{ @@ -32,24 +31,10 @@ * @{ */ -/** - * Context of RegExp compiler - */ -typedef struct -{ - uint16_t flags; /**< RegExp flags */ - uint32_t captures_count; /**< number of capture groups */ - uint32_t non_captures_count; /**< number of non-capture groups */ - uint32_t highest_backref; /**< highest backreference */ - re_bytecode_ctx_t *bytecode_ctx_p; /**< pointer of RegExp bytecode context */ - re_token_t current_token; /**< current token */ - re_parser_ctx_t *parser_ctx_p; /**< pointer of RegExp parser context */ -} re_compiler_ctx_t; +re_compiled_code_t * +re_compile_bytecode (ecma_string_t *pattern_str_p, uint16_t flags); -ecma_value_t -re_compile_bytecode (const re_compiled_code_t **out_bytecode_p, ecma_string_t *pattern_str_p, uint16_t flags); - -void re_cache_gc_run (void); +void re_cache_gc (void); /** * @} diff --git a/jerry-core/parser/regexp/re-parser.c b/jerry-core/parser/regexp/re-parser.c index c766fd45..22d07d7f 100644 --- a/jerry-core/parser/regexp/re-parser.c +++ b/jerry-core/parser/regexp/re-parser.c @@ -35,234 +35,336 @@ */ /** - * Lookup a character in the input string. + * Get the start opcode for the current group. * - * @return true - if lookup number of characters ahead are hex digits - * false - otherwise + * @return RegExp opcode */ -bool -re_hex_lookup (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context */ - uint32_t lookup) /**< size of lookup */ +static re_opcode_t +re_get_group_start_opcode (bool is_capturing) /**< is capturing group */ { - const lit_utf8_byte_t *curr_p = parser_ctx_p->input_curr_p; + return (is_capturing) ? RE_OP_CAPTURING_GROUP_START : RE_OP_NON_CAPTURING_GROUP_START; +} /* re_get_group_start_opcode*/ - if (JERRY_UNLIKELY (curr_p + lookup > parser_ctx_p->input_end_p)) +/** + * Get the end opcode for the current group. + * + * @return RegExp opcode + */ +static re_opcode_t +re_get_group_end_opcode (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + bool is_capturing) /**< is capturing group */ +{ + if (is_capturing) { - return false; - } - - for (uint32_t i = 0; i < lookup; i++) - { - if (!lit_char_is_hex_digit (*curr_p++)) + if (re_ctx_p->token.greedy) { - return false; + return RE_OP_GREEDY_CAPTURING_GROUP_END; } + + return RE_OP_LAZY_CAPTURING_GROUP_END; } - return true; -} /* re_hex_lookup */ + if (re_ctx_p->token.greedy) + { + return RE_OP_GREEDY_NON_CAPTURING_GROUP_END; + } + + return RE_OP_LAZY_NON_CAPTURING_GROUP_END; +} /* re_get_group_end_opcode */ + +/** + * Enclose the given bytecode to a group. + */ +static void +re_insert_into_group (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + uint32_t group_start_offset, /**< offset of group start */ + uint32_t idx, /**< index of group */ + uint32_t capture_start, /**< index of first nested capture */ + bool is_capturing) /**< is capturing group */ +{ + uint32_t qmin = re_ctx_p->token.qmin; + uint32_t qmax = re_ctx_p->token.qmax; + + if (JERRY_UNLIKELY (!is_capturing && re_bytecode_size (re_ctx_p) == group_start_offset)) + { + return; + } + + if (qmin == 0) + { + re_insert_value (re_ctx_p, + group_start_offset, + re_bytecode_size (re_ctx_p) - group_start_offset); + } + + re_insert_value (re_ctx_p, group_start_offset, qmin); + re_insert_value (re_ctx_p, group_start_offset, re_ctx_p->captures_count - capture_start); + + if (!is_capturing) + { + re_insert_value (re_ctx_p, group_start_offset, capture_start); + } + else + { + JERRY_ASSERT (idx == capture_start); + } + + re_insert_value (re_ctx_p, group_start_offset, idx); + re_insert_opcode (re_ctx_p, group_start_offset, re_get_group_start_opcode (is_capturing)); + + re_append_opcode (re_ctx_p, re_get_group_end_opcode (re_ctx_p, is_capturing)); + re_append_value (re_ctx_p, idx); + re_append_value (re_ctx_p, qmin); + re_append_value (re_ctx_p, qmax + RE_QMAX_OFFSET); +} /* re_insert_into_group */ + +/** + * Insert simple atom iterator. + */ +static void +re_insert_atom_iterator (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + uint32_t start_offset) /**< atom start offset */ +{ + const uint32_t qmin = re_ctx_p->token.qmin; + const uint32_t qmax = re_ctx_p->token.qmax; + + if (qmin == 1 && qmax == 1) + { + return; + } + + re_append_opcode (re_ctx_p, RE_OP_ITERATOR_END); + re_insert_value (re_ctx_p, start_offset, re_bytecode_size (re_ctx_p) - start_offset); + re_insert_value (re_ctx_p, start_offset, qmax + RE_QMAX_OFFSET); + re_insert_value (re_ctx_p, start_offset, qmin); + re_insert_opcode (re_ctx_p, start_offset, re_ctx_p->token.greedy ? RE_OP_GREEDY_ITERATOR : RE_OP_LAZY_ITERATOR); +} /* re_insert_atom_iterator */ + +/** + * Insert a lookahead assertion. + */ +static void +re_insert_assertion_lookahead (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + uint32_t start_offset, /**< atom start offset */ + uint32_t capture_start, /**< index of first nested capture */ + bool negative) /** lookahead type */ +{ + const uint32_t qmin = re_ctx_p->token.qmin; + + re_append_opcode (re_ctx_p, RE_OP_ASSERT_END); + re_insert_value (re_ctx_p, start_offset, re_bytecode_size (re_ctx_p) - start_offset); + + /* We need to clear nested capturing group results when a negative assertion or the tail after a positive assertion + * does not match, so we store the begin and end index of nested capturing groups. */ + re_insert_value (re_ctx_p, start_offset, re_ctx_p->captures_count - capture_start); + re_insert_value (re_ctx_p, start_offset, capture_start); + + /* Lookaheads always result in zero length matches, which means iterations will always stop on the first match. + * This allows us to not have to deal with iterations beyond one. Either qmin == 0 which will implicitly match, + * or qmin > 0, in which case the first iteration will decide whether the assertion matches depending on whether + * the iteration matched or not. This also allows us to ignore qmax entirely. */ + re_insert_byte (re_ctx_p, start_offset, (uint8_t) JERRY_MIN (qmin, 1)); + + const re_opcode_t opcode = (negative) ? RE_OP_ASSERT_LOOKAHEAD_NEG : RE_OP_ASSERT_LOOKAHEAD_POS; + re_insert_opcode (re_ctx_p, start_offset, opcode); +} /* re_insert_assertion_lookahead */ /** * Consume non greedy (question mark) character if present. - * - * @return true - if non-greedy character found - * false - otherwise */ -static inline bool JERRY_ATTR_ALWAYS_INLINE -re_parse_non_greedy_char (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser context */ +static void +re_parse_lazy_char (re_compiler_ctx_t *re_ctx_p) /**< RegExp parser context */ { - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p - && *parser_ctx_p->input_curr_p == LIT_CHAR_QUESTION) + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p + && *re_ctx_p->input_curr_p == LIT_CHAR_QUESTION) { - parser_ctx_p->input_curr_p++; - return true; + re_ctx_p->input_curr_p++; + re_ctx_p->token.greedy = false; + return; } - return false; -} /* re_parse_non_greedy_char */ + re_ctx_p->token.greedy = true; +} /* re_parse_lazy_char */ /** - * Parse a max 3 digit long octal number from input string iterator. + * Parse a max 3 digit long octal number from the input string, with a decimal value less than 256. * - * @return uint32_t - parsed octal number + * @return value of the octal number */ -uint32_t -re_parse_octal (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser context */ +static uint32_t +re_parse_octal (re_compiler_ctx_t *re_ctx_p) /**< RegExp parser context */ { - uint32_t number = 0; - for (int index = 0; - index < 3 - && parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p - && lit_char_is_octal_digit (*parser_ctx_p->input_curr_p); - index++) + JERRY_ASSERT (re_ctx_p->input_curr_p < re_ctx_p->input_end_p); + JERRY_ASSERT (lit_char_is_octal_digit (*re_ctx_p->input_curr_p)); + + uint32_t value = (uint32_t) (*re_ctx_p->input_curr_p++) - LIT_CHAR_0; + + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p + && lit_char_is_octal_digit (*re_ctx_p->input_curr_p)) { - number = number * 8 + lit_char_hex_to_int (*parser_ctx_p->input_curr_p++); + value = value * 8 + (*re_ctx_p->input_curr_p++) - LIT_CHAR_0; } - return number; + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p + && lit_char_is_octal_digit (*re_ctx_p->input_curr_p)) + { + const uint32_t new_value = value * 8 + (*re_ctx_p->input_curr_p) - LIT_CHAR_0; + + if (new_value <= RE_MAX_OCTAL_VALUE) + { + value = new_value; + re_ctx_p->input_curr_p++; + } + } + + return value; } /* re_parse_octal */ /** - * Parse RegExp iterators + * Check that the currently parsed quantifier is valid. * - * @return empty ecma value - if parsed successfully - * error ecma value - otherwise - * - * Returned value must be freed with ecma_free_value + * @return ECMA_VALUE_ERROR, if quantifier is invalid + * ECMA_VALUE_EMPTY, otherwise */ -ecma_value_t -re_parse_iterator (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context */ - re_token_t *re_token_p) /**< [out] output token */ +static ecma_value_t +re_check_quantifier (re_compiler_ctx_t *re_ctx_p) { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - re_token_p->qmin = 1; - re_token_p->qmax = 1; - re_token_p->greedy = true; - - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + if (re_ctx_p->token.qmin > re_ctx_p->token.qmax) { - return ret_value; + /* ECMA-262 v5.1 15.10.2.5 */ + return ecma_raise_syntax_error (ECMA_ERR_MSG ("quantifier error: min > max.")); } - ecma_char_t ch = *parser_ctx_p->input_curr_p; + return ECMA_VALUE_EMPTY; +} /* re_check_quantifier */ - switch (ch) +/** + * Parse RegExp quantifier. + * + * @return ECMA_VALUE_TRUE - if parsed successfully + * ECMA_VALUE_FALSE - otherwise + */ +static ecma_value_t +re_parse_quantifier (re_compiler_ctx_t *re_ctx_p) /**< RegExp compiler context */ +{ + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p) { - case LIT_CHAR_QUESTION: + switch (*re_ctx_p->input_curr_p) { - parser_ctx_p->input_curr_p++; - re_token_p->qmin = 0; - re_token_p->qmax = 1; - re_token_p->greedy = !re_parse_non_greedy_char (parser_ctx_p); - break; - } - case LIT_CHAR_ASTERISK: - { - parser_ctx_p->input_curr_p++; - re_token_p->qmin = 0; - re_token_p->qmax = RE_ITERATOR_INFINITE; - re_token_p->greedy = !re_parse_non_greedy_char (parser_ctx_p); - break; - } - case LIT_CHAR_PLUS: - { - parser_ctx_p->input_curr_p++; - re_token_p->qmin = 1; - re_token_p->qmax = RE_ITERATOR_INFINITE; - re_token_p->greedy = !re_parse_non_greedy_char (parser_ctx_p); - break; - } - case LIT_CHAR_LEFT_BRACE: - { - parser_ctx_p->input_curr_p++; - uint32_t qmin = 0; - uint32_t qmax = RE_ITERATOR_INFINITE; - uint32_t digits = 0; - - while (true) + case LIT_CHAR_QUESTION: { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + re_ctx_p->input_curr_p++; + re_ctx_p->token.qmin = 0; + re_ctx_p->token.qmax = 1; + + re_parse_lazy_char (re_ctx_p); + return ECMA_VALUE_TRUE; + } + case LIT_CHAR_ASTERISK: + { + re_ctx_p->input_curr_p++; + re_ctx_p->token.qmin = 0; + re_ctx_p->token.qmax = RE_INFINITY; + + re_parse_lazy_char (re_ctx_p); + return ECMA_VALUE_TRUE; + } + case LIT_CHAR_PLUS: + { + re_ctx_p->input_curr_p++; + re_ctx_p->token.qmin = 1; + re_ctx_p->token.qmax = RE_INFINITY; + + re_parse_lazy_char (re_ctx_p); + return ECMA_VALUE_TRUE; + } + case LIT_CHAR_LEFT_BRACE: + { + const lit_utf8_byte_t *current_p = re_ctx_p->input_curr_p + 1; + uint32_t qmin = 0; + uint32_t qmax = RE_INFINITY; + + if (current_p >= re_ctx_p->input_end_p) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid quantifier")); + break; } - ch = *parser_ctx_p->input_curr_p++; - - if (lit_char_is_decimal_digit (ch)) + if (!lit_char_is_decimal_digit (*current_p)) { - if (digits >= ECMA_NUMBER_MAX_DIGITS) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: too many digits.")); - } - digits++; - qmin = qmin * 10 + lit_char_hex_to_int (ch); + break; + } + + qmin = lit_parse_decimal (¤t_p, re_ctx_p->input_end_p); + + if (current_p >= re_ctx_p->input_end_p) + { + break; + } + + lit_utf8_byte_t ch = *current_p++; + if (ch == LIT_CHAR_RIGHT_BRACE) + { + qmax = qmin; } else if (ch == LIT_CHAR_COMMA) { - if (qmax != RE_ITERATOR_INFINITE) + if (current_p >= re_ctx_p->input_end_p) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: double comma.")); - } - - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid quantifier")); - } - - if (*parser_ctx_p->input_curr_p == LIT_CHAR_RIGHT_BRACE) - { - if (digits == 0) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: missing digits.")); - } - - parser_ctx_p->input_curr_p++; - re_token_p->qmin = qmin; - re_token_p->qmax = RE_ITERATOR_INFINITE; break; } - qmax = qmin; - qmin = 0; - digits = 0; - } - else if (ch == LIT_CHAR_RIGHT_BRACE) - { - if (digits == 0) + + if (lit_char_is_decimal_digit (*current_p)) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: missing digits.")); + qmax = lit_parse_decimal (¤t_p, re_ctx_p->input_end_p); } - if (qmax != RE_ITERATOR_INFINITE) + if (current_p >= re_ctx_p->input_end_p || *current_p++ != LIT_CHAR_RIGHT_BRACE) { - re_token_p->qmin = qmax; + break; } - else - { - re_token_p->qmin = qmin; - } - - re_token_p->qmax = qmin; - - break; } else { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: unknown char.")); + break; } - } - re_token_p->greedy = !re_parse_non_greedy_char (parser_ctx_p); - break; - } - default: - { - break; + re_ctx_p->token.qmin = qmin; + re_ctx_p->token.qmax = qmax; + re_ctx_p->input_curr_p = current_p; + re_parse_lazy_char (re_ctx_p); + return ECMA_VALUE_TRUE; + } + default: + { + break; + } } } - JERRY_ASSERT (ecma_is_value_empty (ret_value)); + re_ctx_p->token.qmin = 1; + re_ctx_p->token.qmax = 1; + re_ctx_p->token.greedy = true; - return ret_value; -} /* re_parse_iterator */ + return ECMA_VALUE_FALSE; +} /* re_parse_quantifier */ /** - * Count the number of groups in pattern + * Count the number of groups in the current pattern. */ static void -re_count_num_of_groups (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser context */ +re_count_groups (re_compiler_ctx_t *re_ctx_p) /**< RegExp compiler context */ { - int char_class_in = 0; - parser_ctx_p->groups_count = 0; - const lit_utf8_byte_t *curr_p = parser_ctx_p->input_start_p; + bool is_char_class = 0; + re_ctx_p->groups_count = 0; + const lit_utf8_byte_t *curr_p = re_ctx_p->input_start_p; - while (curr_p < parser_ctx_p->input_end_p) + while (curr_p < re_ctx_p->input_end_p) { switch (*curr_p++) { case LIT_CHAR_BACKSLASH: { - if (curr_p < parser_ctx_p->input_end_p) + if (curr_p < re_ctx_p->input_end_p) { lit_utf8_incr (&curr_p); } @@ -270,30 +372,296 @@ re_count_num_of_groups (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser contex } case LIT_CHAR_LEFT_SQUARE: { - char_class_in++; + is_char_class = true; break; } case LIT_CHAR_RIGHT_SQUARE: { - if (char_class_in) - { - char_class_in--; - } + is_char_class = false; break; } case LIT_CHAR_LEFT_PAREN: { - if (curr_p < parser_ctx_p->input_end_p + if (curr_p < re_ctx_p->input_end_p && *curr_p != LIT_CHAR_QUESTION - && !char_class_in) + && !is_char_class) { - parser_ctx_p->groups_count++; + re_ctx_p->groups_count++; } break; } } } -} /* re_count_num_of_groups */ +} /* re_count_groups */ + +#if ENABLED (JERRY_ES2015) +/** + * Check if a code point is a Syntax character + * + * @return true, if syntax character + * false, otherwise + */ +static bool +re_is_syntax_char (lit_code_point_t cp) /**< code point */ +{ + return (cp == LIT_CHAR_CIRCUMFLEX + || cp == LIT_CHAR_DOLLAR_SIGN + || cp == LIT_CHAR_BACKSLASH + || cp == LIT_CHAR_DOT + || cp == LIT_CHAR_ASTERISK + || cp == LIT_CHAR_PLUS + || cp == LIT_CHAR_QUESTION + || cp == LIT_CHAR_LEFT_PAREN + || cp == LIT_CHAR_RIGHT_PAREN + || cp == LIT_CHAR_LEFT_SQUARE + || cp == LIT_CHAR_RIGHT_SQUARE + || cp == LIT_CHAR_LEFT_BRACE + || cp == LIT_CHAR_RIGHT_BRACE + || cp == LIT_CHAR_VLINE); +} /* re_is_syntax_char */ +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * Parse a Character Escape or a Character Class Escape. + * + * @return ECMA_VALUE_EMPTY, if parsed successfully + * ECMA_VALUE_ERROR, otherwise + */ +static ecma_value_t +re_parse_char_escape (re_compiler_ctx_t *re_ctx_p) /**< RegExp compiler context */ +{ + JERRY_ASSERT (re_ctx_p->input_curr_p < re_ctx_p->input_end_p); + re_ctx_p->token.type = RE_TOK_CHAR; + + if (lit_char_is_decimal_digit (*re_ctx_p->input_curr_p)) + { + /* NULL code point escape, only valid if there are no following digits. */ + if (*re_ctx_p->input_curr_p == LIT_CHAR_0 + && (re_ctx_p->input_curr_p + 1 >= re_ctx_p->input_end_p + || !lit_char_is_decimal_digit (re_ctx_p->input_curr_p[1]))) + { + re_ctx_p->input_curr_p++; + re_ctx_p->token.value = LIT_UNICODE_CODE_POINT_NULL; + return ECMA_VALUE_EMPTY; + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid escape sequence")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + /* Legacy octal escape sequence */ + if (lit_char_is_octal_digit (*re_ctx_p->input_curr_p)) + { + re_ctx_p->token.value = re_parse_octal (re_ctx_p); + return ECMA_VALUE_EMPTY; + } + + /* Identity escape */ + re_ctx_p->token.value = *re_ctx_p->input_curr_p++; + return ECMA_VALUE_EMPTY; + } + + lit_code_point_t ch = lit_cesu8_read_next (&re_ctx_p->input_curr_p); + switch (ch) + { + /* Character Class escapes */ + case LIT_CHAR_LOWERCASE_D: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_DIGIT; + break; + } + case LIT_CHAR_UPPERCASE_D: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_NOT_DIGIT; + break; + } + case LIT_CHAR_LOWERCASE_S: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_WHITESPACE; + break; + } + case LIT_CHAR_UPPERCASE_S: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_NOT_WHITESPACE; + break; + } + case LIT_CHAR_LOWERCASE_W: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_WORD_CHAR; + break; + } + case LIT_CHAR_UPPERCASE_W: + { + re_ctx_p->token.type = RE_TOK_CLASS_ESCAPE; + re_ctx_p->token.value = RE_ESCAPE_NOT_WORD_CHAR; + break; + } + /* Control escapes */ + case LIT_CHAR_LOWERCASE_F: + { + re_ctx_p->token.value = LIT_CHAR_FF; + break; + } + case LIT_CHAR_LOWERCASE_N: + { + re_ctx_p->token.value = LIT_CHAR_LF; + break; + } + case LIT_CHAR_LOWERCASE_R: + { + re_ctx_p->token.value = LIT_CHAR_CR; + break; + } + case LIT_CHAR_LOWERCASE_T: + { + re_ctx_p->token.value = LIT_CHAR_TAB; + break; + } + case LIT_CHAR_LOWERCASE_V: + { + re_ctx_p->token.value = LIT_CHAR_VTAB; + break; + } + /* Control letter */ + case LIT_CHAR_LOWERCASE_C: + { + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p) + { + ch = *re_ctx_p->input_curr_p; + + if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) + || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END)) + { + re_ctx_p->token.value = (ch % 32); + re_ctx_p->input_curr_p++; + + break; + } + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid control escape sequence")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + re_ctx_p->token.value = LIT_CHAR_BACKSLASH; + re_ctx_p->input_curr_p--; + + break; + } + /* Hex escape */ + case LIT_CHAR_LOWERCASE_X: + { + uint32_t hex_value = lit_char_hex_lookup (re_ctx_p->input_curr_p, re_ctx_p->input_end_p, 2); + if (hex_value != UINT32_MAX) + { + re_ctx_p->token.value = hex_value; + re_ctx_p->input_curr_p += 2; + break; + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid hex escape sequence")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + re_ctx_p->token.value = LIT_CHAR_LOWERCASE_X; + break; + } + /* Unicode escape */ + case LIT_CHAR_LOWERCASE_U: + { + uint32_t hex_value = lit_char_hex_lookup (re_ctx_p->input_curr_p, re_ctx_p->input_end_p, 4); + if (hex_value != UINT32_MAX) + { + re_ctx_p->token.value = hex_value; + re_ctx_p->input_curr_p += 4; + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE + && lit_is_code_point_utf16_high_surrogate (re_ctx_p->token.value) + && re_ctx_p->input_curr_p + 6 <= re_ctx_p->input_end_p + && re_ctx_p->input_curr_p[0] == '\\' + && re_ctx_p->input_curr_p[1] == 'u') + { + hex_value = lit_char_hex_lookup (re_ctx_p->input_curr_p + 2, re_ctx_p->input_end_p, 4); + if (lit_is_code_point_utf16_low_surrogate (hex_value)) + { + re_ctx_p->token.value = lit_convert_surrogate_pair_to_code_point ((ecma_char_t) re_ctx_p->token.value, + (ecma_char_t) hex_value); + re_ctx_p->input_curr_p += 6; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + break; + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + if (re_ctx_p->input_curr_p + 1 < re_ctx_p->input_end_p + && re_ctx_p->input_curr_p[0] == LIT_CHAR_LEFT_BRACE + && lit_char_is_hex_digit (re_ctx_p->input_curr_p[1])) + { + lit_code_point_t cp = lit_char_hex_to_int (re_ctx_p->input_curr_p[1]); + re_ctx_p->input_curr_p += 2; + + while (re_ctx_p->input_curr_p < re_ctx_p->input_end_p && lit_char_is_hex_digit (*re_ctx_p->input_curr_p)) + { + cp = cp * 16 + lit_char_hex_to_int (*re_ctx_p->input_curr_p++); + + if (JERRY_UNLIKELY (cp > LIT_UNICODE_CODE_POINT_MAX)) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid unicode escape sequence")); + } + } + + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p && *re_ctx_p->input_curr_p == LIT_CHAR_RIGHT_BRACE) + { + re_ctx_p->input_curr_p++; + re_ctx_p->token.value = cp; + break; + } + } + + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid unicode escape sequence")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + re_ctx_p->token.value = LIT_CHAR_LOWERCASE_U; + break; + } + /* Identity escape */ + default: + { +#if ENABLED (JERRY_ES2015) + /* Must be '/', or one of SyntaxCharacter */ + if (re_ctx_p->flags & RE_FLAG_UNICODE + && ch != LIT_CHAR_SLASH + && !re_is_syntax_char (ch)) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid escape")); + } +#endif /* ENABLED (JERRY_ES2015) */ + re_ctx_p->token.value = ch; + } + } + + return ECMA_VALUE_EMPTY; +} /* re_parse_char_escape */ /** * Read the input pattern and parse the next token for the RegExp compiler @@ -303,291 +671,123 @@ re_count_num_of_groups (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser contex * * Returned value must be freed with ecma_free_value */ -ecma_value_t -re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context */ - re_token_t *out_token_p) /**< [out] output token */ +static ecma_value_t +re_parse_next_token (re_compiler_ctx_t *re_ctx_p) /**< RegExp compiler context */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) { - out_token_p->type = RE_TOK_EOF; - return ret_value; + re_ctx_p->token.type = RE_TOK_EOF; + return ECMA_VALUE_EMPTY; } - ecma_char_t ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); + ecma_char_t ch = lit_cesu8_read_next (&re_ctx_p->input_curr_p); switch (ch) { - case LIT_CHAR_VLINE: - { - out_token_p->type = RE_TOK_ALTERNATIVE; - break; - } case LIT_CHAR_CIRCUMFLEX: { - out_token_p->type = RE_TOK_ASSERT_START; - break; + re_ctx_p->token.type = RE_TOK_ASSERT_START; + return ECMA_VALUE_EMPTY; } case LIT_CHAR_DOLLAR_SIGN: { - out_token_p->type = RE_TOK_ASSERT_END; - break; + re_ctx_p->token.type = RE_TOK_ASSERT_END; + return ECMA_VALUE_EMPTY; + } + case LIT_CHAR_VLINE: + { + re_ctx_p->token.type = RE_TOK_ALTERNATIVE; + return ECMA_VALUE_EMPTY; } case LIT_CHAR_DOT: { - out_token_p->type = RE_TOK_PERIOD; - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); + re_ctx_p->token.type = RE_TOK_PERIOD; + /* Check quantifier */ break; } case LIT_CHAR_BACKSLASH: { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid regular experssion")); + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid escape")); } - out_token_p->type = RE_TOK_CHAR; - ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); + /* DecimalEscape, Backreferences cannot start with a zero digit. */ + if (*re_ctx_p->input_curr_p > LIT_CHAR_0 && *re_ctx_p->input_curr_p <= LIT_CHAR_9) + { + const lit_utf8_byte_t *digits_p = re_ctx_p->input_curr_p; + const uint32_t value = lit_parse_decimal (&digits_p, re_ctx_p->input_end_p); - if (ch == LIT_CHAR_LOWERCASE_B) - { - out_token_p->type = RE_TOK_ASSERT_WORD_BOUNDARY; - } - else if (ch == LIT_CHAR_UPPERCASE_B) - { - out_token_p->type = RE_TOK_ASSERT_NOT_WORD_BOUNDARY; - } - else if (ch == LIT_CHAR_LOWERCASE_F) - { - out_token_p->value = LIT_CHAR_FF; - } - else if (ch == LIT_CHAR_LOWERCASE_N) - { - out_token_p->value = LIT_CHAR_LF; - } - else if (ch == LIT_CHAR_LOWERCASE_T) - { - out_token_p->value = LIT_CHAR_TAB; - } - else if (ch == LIT_CHAR_LOWERCASE_R) - { - out_token_p->value = LIT_CHAR_CR; - } - else if (ch == LIT_CHAR_LOWERCASE_V) - { - out_token_p->value = LIT_CHAR_VTAB; - } - else if (ch == LIT_CHAR_LOWERCASE_C) - { - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p) + if (re_ctx_p->groups_count < 0) { - ch = *parser_ctx_p->input_curr_p; - - if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) - || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END)) - { - out_token_p->value = (ch % 32); - parser_ctx_p->input_curr_p++; - } - else - { - out_token_p->value = LIT_CHAR_BACKSLASH; - parser_ctx_p->input_curr_p--; - } - } - else - { - out_token_p->value = LIT_CHAR_BACKSLASH; - parser_ctx_p->input_curr_p--; - } - } - else if (ch == LIT_CHAR_LOWERCASE_X - && re_hex_lookup (parser_ctx_p, 2)) - { - ecma_char_t code_unit; - - if (!lit_read_code_unit_from_hex (parser_ctx_p->input_curr_p, 2, &code_unit)) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("decode error")); + re_count_groups (re_ctx_p); } - parser_ctx_p->input_curr_p += 2; - out_token_p->value = code_unit; - } - else if (ch == LIT_CHAR_LOWERCASE_U - && re_hex_lookup (parser_ctx_p, 4)) - { - ecma_char_t code_unit; - - if (!lit_read_code_unit_from_hex (parser_ctx_p->input_curr_p, 4, &code_unit)) + if (value <= (uint32_t) re_ctx_p->groups_count) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("decode error")); - } + /* Valid backreference */ + re_ctx_p->input_curr_p = digits_p; + re_ctx_p->token.type = RE_TOK_BACKREFERENCE; + re_ctx_p->token.value = value; - parser_ctx_p->input_curr_p += 4; - out_token_p->value = code_unit; - } - else if (ch == LIT_CHAR_LOWERCASE_D) - { - out_token_p->type = RE_TOK_DIGIT; - break; - } - else if (ch == LIT_CHAR_UPPERCASE_D) - { - out_token_p->type = RE_TOK_NOT_DIGIT; - break; - } - else if (ch == LIT_CHAR_LOWERCASE_S) - { - out_token_p->type = RE_TOK_WHITE; - break; - } - else if (ch == LIT_CHAR_UPPERCASE_S) - { - out_token_p->type = RE_TOK_NOT_WHITE; - break; - } - else if (ch == LIT_CHAR_LOWERCASE_W) - { - out_token_p->type = RE_TOK_WORD_CHAR; - break; - } - else if (ch == LIT_CHAR_UPPERCASE_W) - { - out_token_p->type = RE_TOK_NOT_WORD_CHAR; - break; - } - else if (lit_char_is_decimal_digit (ch)) - { - if (ch == LIT_CHAR_0) - { - if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p - && lit_char_is_decimal_digit (*parser_ctx_p->input_curr_p)) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp escape pattern error.")); - } - - out_token_p->value = LIT_UNICODE_CODE_POINT_NULL; - } - else - { - if (parser_ctx_p->groups_count == -1) - { - re_count_num_of_groups (parser_ctx_p); - } - - if (parser_ctx_p->groups_count) - { - parser_ctx_p->input_curr_p--; - uint32_t number = 0; - int index = 0; - - do - { - if (index >= RE_MAX_RE_DECESC_DIGITS) - { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp escape error: decimal escape too long.")); - return ret_value; - } - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) - { - break; - } - - ecma_char_t digit = *parser_ctx_p->input_curr_p++; - - if (!lit_char_is_decimal_digit (digit)) - { - parser_ctx_p->input_curr_p--; - break; - } - number = number * 10 + lit_char_hex_to_int (digit); - index++; - } - while (true); - - if ((int) number <= parser_ctx_p->groups_count) - { - out_token_p->type = RE_TOK_BACKREFERENCE; - } - else - /* Invalid backreference, fallback to octal */ - { - /* Rewind to start of number. */ - parser_ctx_p->input_curr_p -= index; - - /* Try to reparse as octal. */ - ecma_char_t digit = *parser_ctx_p->input_curr_p; - - if (!lit_char_is_octal_digit (digit)) - { - /* Not octal, keep digit character value. */ - number = digit; - parser_ctx_p->input_curr_p++; - } - else - { - number = re_parse_octal (parser_ctx_p); - } - } - out_token_p->value = number; - } - else - /* Invalid backreference, fallback to octal if possible */ - { - if (!lit_char_is_octal_digit (ch)) - { - /* Not octal, keep character value. */ - out_token_p->value = ch; - } - else - { - parser_ctx_p->input_curr_p--; - out_token_p->value = re_parse_octal (parser_ctx_p); - } - } + /* Check quantifier */ + break; } } - else + + if (*re_ctx_p->input_curr_p == LIT_CHAR_LOWERCASE_B) { - out_token_p->value = ch; + re_ctx_p->input_curr_p++; + re_ctx_p->token.type = RE_TOK_ASSERT_WORD_BOUNDARY; + return ECMA_VALUE_EMPTY; + } + else if (*re_ctx_p->input_curr_p == LIT_CHAR_UPPERCASE_B) + { + re_ctx_p->input_curr_p++; + re_ctx_p->token.type = RE_TOK_ASSERT_NOT_WORD_BOUNDARY; + return ECMA_VALUE_EMPTY; } - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); + const ecma_value_t parse_result = re_parse_char_escape (re_ctx_p); + + if (ECMA_IS_VALUE_ERROR (parse_result)) + { + return parse_result; + } + + /* Check quantifier */ break; } case LIT_CHAR_LEFT_PAREN: { - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) { return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unterminated group")); } - if (*parser_ctx_p->input_curr_p == LIT_CHAR_QUESTION) + if (*re_ctx_p->input_curr_p == LIT_CHAR_QUESTION) { - parser_ctx_p->input_curr_p++; - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + re_ctx_p->input_curr_p++; + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) { return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid group")); } - ch = *parser_ctx_p->input_curr_p++; + ch = *re_ctx_p->input_curr_p++; if (ch == LIT_CHAR_EQUALS) { - /* (?= */ - out_token_p->type = RE_TOK_ASSERT_START_POS_LOOKAHEAD; + re_ctx_p->token.type = RE_TOK_ASSERT_LOOKAHEAD; + re_ctx_p->token.value = false; } else if (ch == LIT_CHAR_EXCLAMATION) { - /* (?! */ - out_token_p->type = RE_TOK_ASSERT_START_NEG_LOOKAHEAD; + re_ctx_p->token.type = RE_TOK_ASSERT_LOOKAHEAD; + re_ctx_p->token.value = true; } else if (ch == LIT_CHAR_COLON) { - /* (?: */ - out_token_p->type = RE_TOK_START_NON_CAPTURE_GROUP; + re_ctx_p->token.type = RE_TOK_START_NON_CAPTURE_GROUP; } else { @@ -596,89 +796,584 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context * } else { - /* ( */ - out_token_p->type = RE_TOK_START_CAPTURE_GROUP; + re_ctx_p->token.type = RE_TOK_START_CAPTURE_GROUP; } - break; + + return ECMA_VALUE_EMPTY; } case LIT_CHAR_RIGHT_PAREN: { - out_token_p->type = RE_TOK_END_GROUP; - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); - break; + re_ctx_p->token.type = RE_TOK_END_GROUP; + + return ECMA_VALUE_EMPTY; } case LIT_CHAR_LEFT_SQUARE: { - out_token_p->type = RE_TOK_START_CHAR_CLASS; + re_ctx_p->token.type = RE_TOK_CHAR_CLASS; - if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("invalid character class")); + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unterminated character class.")); } - if (*parser_ctx_p->input_curr_p == LIT_CHAR_CIRCUMFLEX) - { - out_token_p->type = RE_TOK_START_INV_CHAR_CLASS; - parser_ctx_p->input_curr_p++; - } - - break; + return ECMA_VALUE_EMPTY; } case LIT_CHAR_QUESTION: case LIT_CHAR_ASTERISK: case LIT_CHAR_PLUS: { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid quantifier.")); } case LIT_CHAR_LEFT_BRACE: { -#if ENABLED (JERRY_REGEXP_STRICT_MODE) - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); -#else /* !ENABLED (JERRY_REGEXP_STRICT_MODE) */ - const lit_utf8_byte_t *input_curr_p = parser_ctx_p->input_curr_p; - - lit_utf8_decr (&parser_ctx_p->input_curr_p); - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); - if (ecma_is_value_empty (ret_value)) + re_ctx_p->input_curr_p--; + if (ecma_is_value_true (re_parse_quantifier (re_ctx_p))) { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Nothing to repeat.")); } - JERRY_ASSERT (ECMA_IS_VALUE_ERROR (ret_value)); - ecma_free_value (JERRY_CONTEXT (error_value)); - - parser_ctx_p->input_curr_p = input_curr_p; - - out_token_p->type = RE_TOK_CHAR; - out_token_p->value = ch; - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); - - if (!ecma_is_value_empty (ret_value)) +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) { - ecma_free_value (JERRY_CONTEXT (error_value)); - parser_ctx_p->input_curr_p = input_curr_p; - ret_value = ECMA_VALUE_EMPTY; + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Lone quantifier bracket.")); } -#endif /* ENABLED (JERRY_REGEXP_STRICT_MODE) */ +#endif /* ENABLED (JERRY_ES2015) */ + + re_ctx_p->input_curr_p++; + re_ctx_p->token.type = RE_TOK_CHAR; + re_ctx_p->token.value = ch; + + /* Check quantifier */ break; } - case LIT_CHAR_NULL: +#if ENABLED (JERRY_ES2015) + case LIT_CHAR_RIGHT_SQUARE: + case LIT_CHAR_RIGHT_BRACE: { - out_token_p->type = RE_TOK_EOF; - break; + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Lone quantifier bracket.")); + } + + /* FALLTHRU */ } +#endif /* ENABLED (JERRY_ES2015) */ default: { - out_token_p->type = RE_TOK_CHAR; - out_token_p->value = ch; - ret_value = re_parse_iterator (parser_ctx_p, out_token_p); + re_ctx_p->token.type = RE_TOK_CHAR; + re_ctx_p->token.value = ch; + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE + && lit_is_code_point_utf16_high_surrogate (ch) + && re_ctx_p->input_curr_p < re_ctx_p->input_end_p) + { + const ecma_char_t next = lit_cesu8_peek_next (re_ctx_p->input_curr_p); + if (lit_is_code_point_utf16_low_surrogate (next)) + { + re_ctx_p->token.value = lit_convert_surrogate_pair_to_code_point (ch, next); + re_ctx_p->input_curr_p += LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + /* Check quantifier */ break; } } - return ret_value; + re_parse_quantifier (re_ctx_p); + return re_check_quantifier (re_ctx_p); } /* re_parse_next_token */ +/** + * Append a character class range to the bytecode. + */ +static void +re_class_add_range (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + lit_code_point_t start, /**< range begin */ + lit_code_point_t end) /**< range end */ +{ + if (re_ctx_p->flags & RE_FLAG_IGNORE_CASE) + { + start = ecma_regexp_canonicalize_char (start, re_ctx_p->flags & RE_FLAG_UNICODE); + end = ecma_regexp_canonicalize_char (end, re_ctx_p->flags & RE_FLAG_UNICODE); + } + + re_append_char (re_ctx_p, start); + re_append_char (re_ctx_p, end); +} /* re_class_add_range */ + +/** + * Add a single character to the character class + */ +static void +re_class_add_char (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + uint32_t class_offset, /**< character class bytecode offset*/ + lit_code_point_t cp) /**< code point */ +{ + if (re_ctx_p->flags & RE_FLAG_IGNORE_CASE) + { + cp = ecma_regexp_canonicalize_char (cp, re_ctx_p->flags & RE_FLAG_UNICODE); + } + + re_insert_char (re_ctx_p, class_offset, cp); +} /* re_class_add_char */ + +/** + * Invalid character code point + */ +#define RE_INVALID_CP 0xFFFFFFFF + +/** + * Read the input pattern and parse the range of character class + * + * @return empty ecma value - if parsed successfully + * error ecma value - otherwise + * + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t +re_parse_char_class (re_compiler_ctx_t *re_ctx_p) /**< RegExp compiler context */ +{ + static const uint8_t escape_flags[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20}; + const uint32_t class_offset = re_bytecode_size (re_ctx_p); + + uint8_t found_escape_flags = 0; + uint8_t out_class_flags = 0; + + uint32_t range_count = 0; + uint32_t char_count = 0; + bool is_range = false; + + JERRY_ASSERT (re_ctx_p->input_curr_p < re_ctx_p->input_end_p); + if (*re_ctx_p->input_curr_p == LIT_CHAR_CIRCUMFLEX) + { + re_ctx_p->input_curr_p++; + out_class_flags |= RE_CLASS_INVERT; + } + + lit_code_point_t start = RE_INVALID_CP; + + while (true) + { + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unterminated character class.")); + } + + if (*re_ctx_p->input_curr_p == LIT_CHAR_RIGHT_SQUARE) + { + if (is_range) + { + if (start != RE_INVALID_CP) + { + re_class_add_char (re_ctx_p, class_offset, start); + char_count++; + } + + re_class_add_char (re_ctx_p, class_offset, LIT_CHAR_MINUS); + char_count++; + } + + re_ctx_p->input_curr_p++; + break; + } + + JERRY_ASSERT (re_ctx_p->input_curr_p < re_ctx_p->input_end_p); + lit_code_point_t current; + + if (*re_ctx_p->input_curr_p == LIT_CHAR_BACKSLASH) + { + re_ctx_p->input_curr_p++; + if (re_ctx_p->input_curr_p >= re_ctx_p->input_end_p) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid escape")); + } + + if (*re_ctx_p->input_curr_p == LIT_CHAR_LOWERCASE_B) + { + re_ctx_p->input_curr_p++; + current = LIT_CHAR_BS; + } +#if ENABLED (JERRY_ES2015) + else if (*re_ctx_p->input_curr_p == LIT_CHAR_MINUS) + { + re_ctx_p->input_curr_p++; + current = LIT_CHAR_MINUS; + } +#endif /* ENABLED (JERRY_ES2015) */ + else if ((re_ctx_p->flags & RE_FLAG_UNICODE) == 0 + && *re_ctx_p->input_curr_p == LIT_CHAR_LOWERCASE_C + && re_ctx_p->input_curr_p + 1 < re_ctx_p->input_end_p + && (lit_char_is_decimal_digit (*(re_ctx_p->input_curr_p + 1)) + || *(re_ctx_p->input_curr_p + 1) == LIT_CHAR_UNDERSCORE)) + { + current = ((uint8_t) *(re_ctx_p->input_curr_p + 1) % 32); + re_ctx_p->input_curr_p += 2; + } + else + { + if (ECMA_IS_VALUE_ERROR (re_parse_char_escape (re_ctx_p))) + { + return ECMA_VALUE_ERROR; + } + + if (re_ctx_p->token.type == RE_TOK_CLASS_ESCAPE) + { + const uint8_t escape = (uint8_t) re_ctx_p->token.value; + found_escape_flags |= escape_flags[escape]; + current = RE_INVALID_CP; + } + else + { + JERRY_ASSERT (re_ctx_p->token.type == RE_TOK_CHAR); + current = re_ctx_p->token.value; + } + } + } +#if ENABLED (JERRY_ES2015) + else if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + current = ecma_regexp_unicode_advance (&re_ctx_p->input_curr_p, re_ctx_p->input_end_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + else + { + current = lit_cesu8_read_next (&re_ctx_p->input_curr_p); + } + + if (is_range) + { + is_range = false; + + if (start != RE_INVALID_CP && current != RE_INVALID_CP) + { + if (start > current) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Range out of order in character class")); + } + + re_class_add_range (re_ctx_p, start, current); + range_count++; + continue; + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid character class")); + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (start != RE_INVALID_CP) + { + re_class_add_char (re_ctx_p, class_offset, start); + char_count++; + } + else if (current != RE_INVALID_CP) + { + re_class_add_char (re_ctx_p, class_offset, current); + char_count++; + } + + re_class_add_char (re_ctx_p, class_offset, LIT_CHAR_MINUS); + char_count++; + continue; + } + + if (re_ctx_p->input_curr_p < re_ctx_p->input_end_p + && *re_ctx_p->input_curr_p == LIT_CHAR_MINUS) + { + re_ctx_p->input_curr_p++; + start = current; + is_range = true; + continue; + } + + if (current != RE_INVALID_CP) + { + re_class_add_char (re_ctx_p, class_offset, current); + char_count++; + } + } + + uint8_t escape_count = 0; + for (ecma_class_escape_t escape = RE_ESCAPE__START; escape < RE_ESCAPE__COUNT; ++escape) + { + if (found_escape_flags & escape_flags[escape]) + { + re_insert_byte (re_ctx_p, class_offset, (uint8_t) escape); + escape_count++; + } + } + + if (range_count > 0) + { + re_insert_value (re_ctx_p, class_offset, range_count); + out_class_flags |= RE_CLASS_HAS_RANGES; + } + + if (char_count > 0) + { + re_insert_value (re_ctx_p, class_offset, char_count); + out_class_flags |= RE_CLASS_HAS_CHARS; + } + + JERRY_ASSERT (escape_count <= RE_CLASS_ESCAPE_COUNT_MASK); + out_class_flags |= escape_count; + + re_insert_byte (re_ctx_p, class_offset, out_class_flags); + re_insert_opcode (re_ctx_p, class_offset, RE_OP_CHAR_CLASS); + + re_parse_quantifier (re_ctx_p); + return re_check_quantifier (re_ctx_p); +} /* re_parse_char_class */ + +/** + * Parse alternatives + * + * @return empty ecma value - if alternative was successfully parsed + * error ecma value - otherwise + * + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ + bool expect_eof) /**< expect end of file */ +{ + ECMA_CHECK_STACK_USAGE (); + uint32_t alternative_offset = re_bytecode_size (re_ctx_p); + bool first_alternative = true; + + while (true) + { + ecma_value_t next_token_result = re_parse_next_token (re_ctx_p); + if (ECMA_IS_VALUE_ERROR (next_token_result)) + { + return next_token_result; + } + + JERRY_ASSERT (ecma_is_value_empty (next_token_result)); + + uint32_t atom_offset = re_bytecode_size (re_ctx_p); + + switch (re_ctx_p->token.type) + { + case RE_TOK_START_CAPTURE_GROUP: + { + const uint32_t idx = re_ctx_p->captures_count++; + const uint32_t capture_start = idx; + + ecma_value_t result = re_parse_alternative (re_ctx_p, false); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + re_parse_quantifier (re_ctx_p); + + if (ECMA_IS_VALUE_ERROR (re_check_quantifier (re_ctx_p))) + { + return ECMA_VALUE_ERROR; + } + + re_insert_into_group (re_ctx_p, atom_offset, idx, capture_start, true); + break; + } + case RE_TOK_START_NON_CAPTURE_GROUP: + { + const uint32_t idx = re_ctx_p->non_captures_count++; + const uint32_t capture_start = re_ctx_p->captures_count; + + ecma_value_t result = re_parse_alternative (re_ctx_p, false); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + re_parse_quantifier (re_ctx_p); + + if (ECMA_IS_VALUE_ERROR (re_check_quantifier (re_ctx_p))) + { + return ECMA_VALUE_ERROR; + } + + re_insert_into_group (re_ctx_p, atom_offset, idx, capture_start, false); + break; + } + case RE_TOK_PERIOD: + { +#if ENABLED (JERRY_ES2015) + re_append_opcode (re_ctx_p, (re_ctx_p->flags & RE_FLAG_UNICODE) ? RE_OP_UNICODE_PERIOD : RE_OP_PERIOD); +#else /* !ENABLED (JERRY_ES2015) */ + re_append_opcode (re_ctx_p, RE_OP_PERIOD); +#endif /* !ENABLED (JERRY_ES2015) */ + + re_insert_atom_iterator (re_ctx_p, atom_offset); + break; + } + case RE_TOK_ALTERNATIVE: + { + re_insert_value (re_ctx_p, alternative_offset, re_bytecode_size (re_ctx_p) - alternative_offset); + re_insert_opcode (re_ctx_p, alternative_offset, first_alternative ? RE_OP_ALTERNATIVE_START + : RE_OP_ALTERNATIVE_NEXT); + + alternative_offset = re_bytecode_size (re_ctx_p); + first_alternative = false; + break; + } + case RE_TOK_ASSERT_START: + { + re_append_opcode (re_ctx_p, RE_OP_ASSERT_LINE_START); + break; + } + case RE_TOK_ASSERT_END: + { + re_append_opcode (re_ctx_p, RE_OP_ASSERT_LINE_END); + break; + } + case RE_TOK_ASSERT_WORD_BOUNDARY: + { + re_append_opcode (re_ctx_p, RE_OP_ASSERT_WORD_BOUNDARY); + break; + } + case RE_TOK_ASSERT_NOT_WORD_BOUNDARY: + { + re_append_opcode (re_ctx_p, RE_OP_ASSERT_NOT_WORD_BOUNDARY); + break; + } + case RE_TOK_ASSERT_LOOKAHEAD: + { + const uint32_t start_capture_count = re_ctx_p->captures_count; + const bool is_negative = !!re_ctx_p->token.value; + + ecma_value_t result = re_parse_alternative (re_ctx_p, false); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + +#if ENABLED (JERRY_ES2015) + if (re_ctx_p->flags & RE_FLAG_UNICODE) + { + re_ctx_p->token.qmin = 1; + re_ctx_p->token.qmax = 1; + re_ctx_p->token.greedy = true; + } + else +#endif /* ENABLED (JERRY_ES2015) */ + { + re_parse_quantifier (re_ctx_p); + + if (ECMA_IS_VALUE_ERROR (re_check_quantifier (re_ctx_p))) + { + return ECMA_VALUE_ERROR; + } + } + + re_insert_assertion_lookahead (re_ctx_p, atom_offset, start_capture_count, is_negative); + break; + } + case RE_TOK_BACKREFERENCE: + { + const uint32_t backref_idx = re_ctx_p->token.value; + re_append_opcode (re_ctx_p, RE_OP_BACKREFERENCE); + re_append_value (re_ctx_p, backref_idx); + + if (re_ctx_p->token.qmin != 1 || re_ctx_p->token.qmax != 1) + { + const uint32_t group_idx = re_ctx_p->non_captures_count++; + re_insert_into_group (re_ctx_p, atom_offset, group_idx, re_ctx_p->captures_count, false); + } + + break; + } + case RE_TOK_CLASS_ESCAPE: + { + const ecma_class_escape_t escape = (ecma_class_escape_t) re_ctx_p->token.value; + re_append_opcode (re_ctx_p, RE_OP_CLASS_ESCAPE); + re_append_byte (re_ctx_p, (uint8_t) escape); + + re_insert_atom_iterator (re_ctx_p, atom_offset); + break; + } + case RE_TOK_CHAR_CLASS: + { + ecma_value_t result = re_parse_char_class (re_ctx_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + re_insert_atom_iterator (re_ctx_p, atom_offset); + break; + } + case RE_TOK_END_GROUP: + { + if (expect_eof) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unmatched ')'")); + } + + if (!first_alternative) + { + re_insert_value (re_ctx_p, alternative_offset, re_bytecode_size (re_ctx_p) - alternative_offset); + re_insert_opcode (re_ctx_p, alternative_offset, RE_OP_ALTERNATIVE_NEXT); + } + + return ECMA_VALUE_EMPTY; + } + case RE_TOK_EOF: + { + if (!expect_eof) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexpected end of pattern.")); + } + + if (!first_alternative) + { + re_insert_value (re_ctx_p, alternative_offset, re_bytecode_size (re_ctx_p) - alternative_offset); + re_insert_opcode (re_ctx_p, alternative_offset, RE_OP_ALTERNATIVE_NEXT); + } + + re_append_opcode (re_ctx_p, RE_OP_EOF); + return ECMA_VALUE_EMPTY; + } + default: + { + JERRY_ASSERT (re_ctx_p->token.type == RE_TOK_CHAR); + + lit_code_point_t ch = re_ctx_p->token.value; + + if (ch <= LIT_UTF8_1_BYTE_CODE_POINT_MAX && (re_ctx_p->flags & RE_FLAG_IGNORE_CASE) == 0) + { + re_append_opcode (re_ctx_p, RE_OP_BYTE); + re_append_byte (re_ctx_p, (uint8_t) ch); + + re_insert_atom_iterator (re_ctx_p, atom_offset); + break; + } + + if (re_ctx_p->flags & RE_FLAG_IGNORE_CASE) + { + ch = ecma_regexp_canonicalize_char (ch, re_ctx_p->flags & RE_FLAG_UNICODE); + } + + re_append_opcode (re_ctx_p, RE_OP_CHAR); + re_append_char (re_ctx_p, ch); + + re_insert_atom_iterator (re_ctx_p, atom_offset); + break; + } + } + } + + return ECMA_VALUE_EMPTY; +} /* re_parse_alternative */ + /** * @} * @} diff --git a/jerry-core/parser/regexp/re-parser.h b/jerry-core/parser/regexp/re-parser.h index 7e3c2e2c..1540968b 100644 --- a/jerry-core/parser/regexp/re-parser.h +++ b/jerry-core/parser/regexp/re-parser.h @@ -18,45 +18,18 @@ #if ENABLED (JERRY_BUILTIN_REGEXP) +#include "re-compiler-context.h" + /** \addtogroup parser Parser * @{ * * \addtogroup regexparser Regular expression * @{ * - * \addtogroup regexparser_bytecode Bytecode + * \addtogroup regexparser_parser Parser * @{ */ -/** - * RegExp token type definitions - */ -typedef enum -{ - RE_TOK_EOF, /**< EOF */ - RE_TOK_BACKREFERENCE, /**< "\[0..9]" */ - RE_TOK_CHAR, /**< any character */ - RE_TOK_ALTERNATIVE, /**< "|" */ - RE_TOK_ASSERT_START, /**< "^" */ - RE_TOK_ASSERT_END, /**< "$" */ - RE_TOK_PERIOD, /**< "." */ - RE_TOK_START_CAPTURE_GROUP, /**< "(" */ - RE_TOK_START_NON_CAPTURE_GROUP, /**< "(?:" */ - RE_TOK_END_GROUP, /**< ")" */ - RE_TOK_ASSERT_START_POS_LOOKAHEAD, /**< "(?=" */ - RE_TOK_ASSERT_START_NEG_LOOKAHEAD, /**< "(?!" */ - RE_TOK_ASSERT_WORD_BOUNDARY, /**< "\b" */ - RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /**< "\B" */ - RE_TOK_DIGIT, /**< "\d" */ - RE_TOK_NOT_DIGIT, /**< "\D" */ - RE_TOK_WHITE, /**< "\s" */ - RE_TOK_NOT_WHITE, /**< "\S" */ - RE_TOK_WORD_CHAR, /**< "\w" */ - RE_TOK_NOT_WORD_CHAR, /**< "\W" */ - RE_TOK_START_CHAR_CLASS, /**< "[ ]" */ - RE_TOK_START_INV_CHAR_CLASS, /**< "[^ ]" */ -} re_token_type_t; - /** * @} * @@ -65,43 +38,16 @@ typedef enum */ /** - * RegExp constant of infinite + * Value used for infinite quantifier. */ -#define RE_ITERATOR_INFINITE ((uint32_t) - 1) +#define RE_INFINITY UINT32_MAX /** - * Maximum number of decimal escape digits + * Maximum decimal value of an octal escape */ -#define RE_MAX_RE_DECESC_DIGITS 9 +#define RE_MAX_OCTAL_VALUE 0xff -/** - * RegExp token type - */ -typedef struct -{ - re_token_type_t type; /**< type of the token */ - uint32_t value; /**< value of the token */ - uint32_t qmin; /**< minimum number of token iterations */ - uint32_t qmax; /**< maximum number of token iterations */ - bool greedy; /**< type of iteration */ -} re_token_t; - -/** - * RegExp parser context - */ -typedef struct -{ - const lit_utf8_byte_t *input_start_p; /**< start of input pattern */ - const lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */ - const lit_utf8_byte_t *input_end_p; /**< end of input pattern */ - int groups_count; /**< number of groups */ - uint32_t classes_count; /**< number of character classes */ -} re_parser_ctx_t; - -bool re_hex_lookup (re_parser_ctx_t *parser_ctx_p, uint32_t lookup); -uint32_t re_parse_octal (re_parser_ctx_t *parser_ctx_p); -ecma_value_t re_parse_iterator (re_parser_ctx_t *parser_ctx_p, re_token_t *re_token_p); -ecma_value_t re_parse_next_token (re_parser_ctx_t *parser_ctx_p, re_token_t *out_token_p); +ecma_value_t re_parse_alternative (re_compiler_ctx_t *re_ctx_p, bool expect_eof); /** * @} diff --git a/jerry-core/parser/regexp/re-token.h b/jerry-core/parser/regexp/re-token.h new file mode 100644 index 00000000..fd203a19 --- /dev/null +++ b/jerry-core/parser/regexp/re-token.h @@ -0,0 +1,72 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RE_TOKEN_H +#define RE_TOKEN_H + +#if ENABLED (JERRY_BUILTIN_REGEXP) + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup regexparser Regular expression + * @{ + * + * \addtogroup regexparser_parser Parser + * @{ + */ + +/** + * RegExp token type definitions + */ +typedef enum +{ + RE_TOK_EOF, /**< EOF */ + RE_TOK_BACKREFERENCE, /**< "\[0..9]" */ + RE_TOK_ALTERNATIVE, /**< "|" */ + RE_TOK_ASSERT_START, /**< "^" */ + RE_TOK_ASSERT_END, /**< "$" */ + RE_TOK_PERIOD, /**< "." */ + RE_TOK_START_CAPTURE_GROUP, /**< "(" */ + RE_TOK_START_NON_CAPTURE_GROUP, /**< "(?:" */ + RE_TOK_END_GROUP, /**< ")" */ + RE_TOK_ASSERT_LOOKAHEAD, /**< "(?=" */ + RE_TOK_ASSERT_WORD_BOUNDARY, /**< "\b" */ + RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /**< "\B" */ + RE_TOK_CLASS_ESCAPE, /**< "\d \D \w \W \s \S" */ + RE_TOK_CHAR_CLASS, /**< "[ ]" */ + RE_TOK_CHAR, /**< any character */ +} re_token_type_t; + +/** + * RegExp token + */ +typedef struct +{ + uint32_t value; /**< value of the token */ + uint32_t qmin; /**< minimum number of token iterations */ + uint32_t qmax; /**< maximum number of token iterations */ + re_token_type_t type; /**< type of the token */ + bool greedy; /**< type of iteration */ +} re_token_t; + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#endif /* !RE_TOKEN_H */ diff --git a/jerry-core/profiles/README.md b/jerry-core/profiles/README.md index 1272fa64..d0be53ee 100644 --- a/jerry-core/profiles/README.md +++ b/jerry-core/profiles/README.md @@ -29,22 +29,12 @@ Alternatively, if you want to use a custom profile at `/absolute/path/to/my.profile`: ``` -# Turn off every ES2015 feature EXCEPT the arrow functions -JERRY_ES2015_BUILTIN=0 +# Turn off every ES2015 feature EXCEPT the module system JERRY_ES2015_BUILTIN_DATAVIEW=0 -JERRY_ES2015_BUILTIN_ITERATOR=0 JERRY_ES2015_BUILTIN_MAP=0 JERRY_ES2015_BUILTIN_PROMISE=0 JERRY_ES2015_BUILTIN_SET=0 -JERRY_ES2015_BUILTIN_SYMBOL=0 JERRY_ES2015_BUILTIN_TYPEDARRAY=0 -JERRY_ES2015_CLASS=0 -JERRY_ES2015_FOR_OF=0 -JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER=0 -JERRY_ES2015_FUNCTION_REST_PARAMETER=0 -JERRY_ES2015_MODULE_SYSTEM=0 -JERRY_ES2015_OBJECT_INITIALIZER=0 -JERRY_ES2015_TEMPLATE_STRINGS=0 ``` Run the build script as follows (assuming that you are in the project root @@ -108,54 +98,38 @@ defined to `1`. #### ES6 (ES 2015) features -* `JERRY_ES2015_ARROW_FUNCTION`: - Enables or disables the [arrow functions](http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions). -* `JERRY_ES2015_BUILTIN`: - Enables or disables the built-in updates of the 5.1 standard. There are some differences in those built-ins which available in both [5.1](http://www.ecma-international.org/ecma-262/5.1/) and [2015](http://www.ecma-international.org/ecma-262/6.0/) versions of the standard. JerryScript uses the latest definition by default. * `JERRY_ES2015_BUILTIN_DATAVIEW`: Enables or disables the [DataView](https://www.ecma-international.org/ecma-262/6.0/#sec-dataview-objects) built-in. -* `JERRY_ES2015_BUILTIN_ITERATOR`: - Enables or disables the [Iterator](https://www.ecma-international.org/ecma-262/6.0/#sec-iterator-interface) built-in. * `JERRY_ES2015_BUILTIN_MAP`: Enables or disables the [Map](http://www.ecma-international.org/ecma-262/6.0/#sec-keyed-collection) built-ins. * `JERRY_ES2015_BUILTIN_SET`: Enables or disables the [SET](https://www.ecma-international.org/ecma-262/6.0/#sec-set-objects) built-in. -* `JERRY_ES2015_BUILTIN_SYMBOL`: - Enables or disables the [Symbol](https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects) built-in. * `JERRY_ES2015_BUILTIN_PROMISE`: Enables or disables the [Promise](http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects) built-in. * `JERRY_ES2015_BUILTIN_TYPEDARRAY`: Enables or disables the [ArrayBuffer](http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-objects) and [TypedArray](http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects) built-ins. -* `JERRY_ES2015_CLASS`: - Enables or disables the [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element. -* `JERRY_ES2015_FOR_OF`: - Enables or disables the [for of](https://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements) language element. -* `JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER`: - Enables or disables the [default value](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) for formal parameters. -* `JERRY_ES2015_FUNCTION_REST_PARAMETER`: - Enables or disables the [rest parameter](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions). * `JERRY_ES2015_MODULE_SYSTEM`: Enables or disable the [module system](http://www.ecma-international.org/ecma-262/6.0/#sec-modules) language element. -* `JERRY_ES2015_OBJECT_INITIALIZER`: - Enables or disables the [enhanced object initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) language element. -* `JERRY_ES2015_TEMPLATE_STRINGS`: - Enables or disables the [template strings](http://www.ecma-international.org/ecma-262/6.0/#sec-static-semantics-templatestrings). * `JERRY_ES2015`: Enables or disable all of the implemented [ECMAScript2015 features](http://www.ecma-international.org/ecma-262/6.0/). + * [arrow functions](http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions) language element. + * [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element. + * [default value](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) for formal parameters. + * [destructuring assignment](http://www.ecma-international.org/ecma-262/6.0/#sec-destructuring-assignment) language element. + * [destructuring binding pattern](http://www.ecma-international.org/ecma-262/6.0/#sec-destructuring-binding-patterns) declarations. + * [enhanced object initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) language element. + * [for-of](https://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements) language element. + * [generator functions](http://www.ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions) language element. + * [iterator](https://www.ecma-international.org/ecma-262/6.0/#sec-iterator-interface) built-in. + * [rest parameter](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) language element. + * [symbol](https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects) language element. + * [template strings](http://www.ecma-international.org/ecma-262/6.0/#sec-static-semantics-templatestrings) language element. + Furthermore all builtins follow the ES2015 specification including those which behave differently in ES5.1. This option is evaulated first, any other `JERRY_ES2015_` defines will override that specific entry. Equivalent with setting the following defines to the `JERRY_ES2015` value: - * `JERRY_ES2015_ARROW_FUNCTION` - * `JERRY_ES2015_BUILTIN` * `JERRY_ES2015_BUILTIN_DATAVIEW` - * `JERRY_ES2015_BUILTIN_ITERATOR` * `JERRY_ES2015_BUILTIN_MAP` * `JERRY_ES2015_BUILTIN_SET` * `JERRY_ES2015_BUILTIN_PROMISE` - * `JERRY_ES2015_BUILTIN_SYMBOL` * `JERRY_ES2015_BUILTIN_TYPEDARRAY` - * `JERRY_ES2015_CLASS` - * `JERRY_ES2015_FOR_OF` - * `JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER` - * `JERRY_ES2015_FUNCTION_REST_PARAMETER` * `JERRY_ES2015_MODULE_SYSTEM` - * `JERRY_ES2015_OBJECT_INITIALIZER` - * `JERRY_ES2015_TEMPLATE_STRINGS` + diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c index 68892768..68c118be 100644 --- a/jerry-core/vm/opcodes-ecma-arithmetics.c +++ b/jerry-core/vm/opcodes-ecma-arithmetics.c @@ -54,7 +54,7 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation switch (op) { - case NUMBER_ARITHMETIC_SUBSTRACTION: + case NUMBER_ARITHMETIC_SUBTRACTION: { result = num_left - num_right; break; @@ -74,6 +74,13 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation result = ecma_op_number_remainder (num_left, num_right); break; } +#if ENABLED (JERRY_ES2015) + case NUMBER_ARITHMETIC_EXPONENTIATION: + { + result = ecma_number_pow (num_left, num_right); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } ret_value = ecma_make_number_value (result); @@ -132,9 +139,9 @@ opfunc_addition (ecma_value_t left_value, /**< left value */ if (ecma_is_value_string (left_value) || ecma_is_value_string (right_value)) { - ecma_value_t str_left_value = ecma_op_to_string (left_value); + ecma_string_t *string1_p = ecma_op_to_string (left_value); - if (ECMA_IS_VALUE_ERROR (str_left_value)) + if (JERRY_UNLIKELY (string1_p == NULL)) { if (free_left_value) { @@ -144,14 +151,12 @@ opfunc_addition (ecma_value_t left_value, /**< left value */ { ecma_free_value (right_value); } - return str_left_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *string1_p = ecma_get_string_from_value (str_left_value); + ecma_string_t *string2_p = ecma_op_to_string (right_value); - ecma_value_t str_right_value = ecma_op_to_string (right_value); - - if (ECMA_IS_VALUE_ERROR (str_right_value)) + if (JERRY_UNLIKELY (string2_p == NULL)) { if (free_right_value) { @@ -162,11 +167,9 @@ opfunc_addition (ecma_value_t left_value, /**< left value */ ecma_free_value (left_value); } ecma_deref_ecma_string (string1_p); - return str_right_value; + return ECMA_VALUE_ERROR; } - ecma_string_t *string2_p = ecma_get_string_from_value (str_right_value); - string1_p = ecma_concat_ecma_strings (string1_p, string2_p); ret_value = ecma_make_string_value (string1_p); diff --git a/jerry-core/vm/opcodes-ecma-relational-equality.c b/jerry-core/vm/opcodes-ecma-relational-equality.c index 93768f40..5fe14577 100644 --- a/jerry-core/vm/opcodes-ecma-relational-equality.c +++ b/jerry-core/vm/opcodes-ecma-relational-equality.c @@ -16,6 +16,7 @@ #include "ecma-comparison.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" +#include "ecma-function-object.h" #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-try-catch-macro.h" @@ -109,6 +110,32 @@ opfunc_instanceof (ecma_value_t left_value, /**< left value */ return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'instanceof' check.")); } +#if ENABLED (JERRY_ES2015) + ecma_value_t has_instance_method = ecma_op_get_method_by_symbol_id (right_value, LIT_GLOBAL_SYMBOL_HAS_INSTANCE); + if (ECMA_IS_VALUE_ERROR (has_instance_method)) + { + return has_instance_method; + } + + if (JERRY_UNLIKELY (!ecma_is_value_undefined (has_instance_method))) + { + ecma_object_t *method_obj_p = ecma_get_object_from_value (has_instance_method); + ecma_value_t has_instance_result = ecma_op_function_call (method_obj_p, right_value, &left_value, 1); + + ecma_free_value (has_instance_method); + + if (ECMA_IS_VALUE_ERROR (has_instance_result)) + { + return has_instance_result; + } + + bool has_instance = ecma_op_to_boolean (has_instance_result); + ecma_free_value (has_instance_result); + + return ecma_make_boolean_value (has_instance); + } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); return ecma_op_object_has_instance (right_value_obj_p, left_value); } /* opfunc_instanceof */ @@ -140,8 +167,7 @@ opfunc_in (ecma_value_t left_value, /**< left value */ } ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); - ecma_value_t result = ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, - property_name_p)); + ecma_value_t result = ecma_op_object_has_property (right_value_obj_p, property_name_p); ecma_deref_ecma_string (property_name_p); return result; } /* opfunc_in */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 485f102b..abecd5e6 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -14,18 +14,25 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-builtins.h" +#include "ecma-builtin-helpers.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "ecma-iterator-object.h" #include "ecma-lex-env.h" #include "ecma-objects.h" +#include "ecma-promise-object.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" +#include "jcontext.h" #include "opcodes.h" #include "vm-defines.h" +#include "vm-stack.h" /** \addtogroup vm Virtual machine * @{ @@ -39,19 +46,26 @@ * * See also: ECMA-262 v5, 10.5 - Declaration binding instantiation (block 8). * - * @return ecma value - * Returned value is simple and so need not be freed. - * However, ecma_free_value may be called for it, but it is a no-op. + * @return ECMA_VALUE_ERROR - if no the operation fails + * ECMA_VALUE_EMPTY - otherwise */ -ecma_value_t -vm_var_decl (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ - ecma_string_t *var_name_str_p) /**< variable name */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +vm_var_decl (ecma_object_t *lex_env_p, /**< target lexical environment */ + ecma_string_t *var_name_str_p, /**< variable name */ + bool is_configurable_bindings) /**< true if the binding can be deleted */ { - if (!ecma_op_has_binding (frame_ctx_p->lex_env_p, var_name_str_p)) - { - const bool is_configurable_bindings = frame_ctx_p->is_eval_code; + ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, var_name_str_p); - ecma_value_t completion_value = ecma_op_create_mutable_binding (frame_ctx_p->lex_env_p, +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_binding)) + { + return has_binding; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (has_binding)) + { + ecma_value_t completion_value = ecma_op_create_mutable_binding (lex_env_p, var_name_str_p, is_configurable_bindings); @@ -60,13 +74,38 @@ vm_var_decl (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ /* Skipping SetMutableBinding as we have already checked that there were not * any binding with specified name in current lexical environment * and CreateMutableBinding sets the created binding's value to undefined */ - JERRY_ASSERT (ecma_is_value_undefined (ecma_op_get_binding_value (frame_ctx_p->lex_env_p, + JERRY_ASSERT (ecma_is_value_undefined (ecma_op_get_binding_value (lex_env_p, var_name_str_p, vm_is_strict_mode ()))); } + return ECMA_VALUE_EMPTY; } /* vm_var_decl */ +/** + * Set var binding to a function literal value. + * + * @return ECMA_VALUE_ERROR - if no the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +vm_set_var (ecma_object_t *lex_env_p, /**< target lexical environment */ + ecma_string_t *var_name_str_p, /**< variable name */ + bool is_strict, /**< true, if the engine is in strict mode */ + ecma_value_t lit_value) /**< function value */ +{ + ecma_value_t put_value_result; + put_value_result = ecma_op_put_value_lex_env_base (lex_env_p, var_name_str_p, is_strict, lit_value); + + JERRY_ASSERT (ecma_is_value_boolean (put_value_result) + || ecma_is_value_empty (put_value_result) + || ECMA_IS_VALUE_ERROR (put_value_result)); + + ecma_free_value (lit_value); + + return put_value_result; +} /* vm_set_var */ + /** * 'typeof' opcode handler. * @@ -92,8 +131,7 @@ opfunc_set_accessor (bool is_getter, /**< is getter accessor */ { ecma_object_t *object_p = ecma_get_object_from_value (object); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p); @@ -154,10 +192,12 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ ecma_value_t property, /**< property name */ bool is_strict) /**< strict mode */ { +#if !ENABLED (JERRY_ES2015) if (ecma_is_value_undefined (object)) { return ECMA_VALUE_TRUE; } +#endif /* !ENABLED (JERRY_ES2015) */ ecma_value_t check_coercible = ecma_op_check_object_coercible (object); if (ECMA_IS_VALUE_ERROR (check_coercible)) @@ -181,7 +221,7 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); ecma_value_t delete_op_ret = ecma_op_object_delete (obj_p, name_string_p, is_strict); - JERRY_ASSERT (ecma_is_value_boolean (delete_op_ret) || (is_strict == true && ECMA_IS_VALUE_ERROR (delete_op_ret))); + JERRY_ASSERT (ecma_is_value_boolean (delete_op_ret) || ECMA_IS_VALUE_ERROR (delete_op_ret)); ecma_deref_object (obj_p); ecma_deref_ecma_string (name_string_p); @@ -204,6 +244,13 @@ vm_op_delete_var (ecma_value_t name_literal, /**< name literal */ ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, var_name_str_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (JERRY_UNLIKELY (ref_base_lex_env_p == ECMA_OBJECT_POINTER_ERROR)) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (ref_base_lex_env_p == NULL) { completion_value = ECMA_VALUE_TRUE; @@ -242,6 +289,9 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */ /* ecma_op_to_object will only raise error on null/undefined values but those are handled above. */ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (obj_expr_value)); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_collection_t *prop_names_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE_PROTOTYPE); if (prop_names_p->item_count != 0) @@ -256,6 +306,1003 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */ return NULL; } /* opfunc_for_in */ +#if ENABLED (JERRY_ES2015) + +/** + * 'VM_OC_APPEND_ARRAY' opcode handler specialized for spread objects + * + * @return ECMA_VALUE_ERROR - if the operation failed + * ECMA_VALUE_EMPTY, otherwise + */ +static ecma_value_t JERRY_ATTR_NOINLINE +opfunc_append_to_spread_array (ecma_value_t *stack_top_p, /**< current stack top */ + uint16_t values_length) /**< number of elements to set */ +{ + JERRY_ASSERT (!(values_length & OPFUNC_HAS_SPREAD_ELEMENT)); + + ecma_object_t *array_obj_p = ecma_get_object_from_value (stack_top_p[-1]); + JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY); + + ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; + uint32_t old_length = ext_array_obj_p->u.array.length; + + for (uint32_t i = 0, idx = old_length; i < values_length; i++, idx++) + { + if (ecma_is_value_array_hole (stack_top_p[i])) + { + continue; + } + + if (stack_top_p[i] == ECMA_VALUE_SPREAD_ELEMENT) + { + i++; + ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_value_t spread_value = stack_top_p[i]; + + ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_EMPTY); + + if (!ECMA_IS_VALUE_ERROR (iterator)) + { + while (true) + { + ecma_value_t next_value = ecma_op_iterator_step (iterator); + + if (ECMA_IS_VALUE_ERROR (next_value)) + { + break; + } + + if (ecma_is_value_false (next_value)) + { + idx--; + ret_value = ECMA_VALUE_EMPTY; + break; + } + + ecma_value_t value = ecma_op_iterator_value (next_value); + + ecma_free_value (next_value); + + if (ECMA_IS_VALUE_ERROR (value)) + { + break; + } + + ecma_value_t put_comp; + put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, + idx++, + value, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + + JERRY_ASSERT (ecma_is_value_true (put_comp)); + ecma_free_value (value); + } + } + + ecma_free_value (iterator); + ecma_free_value (spread_value); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + for (uint32_t k = i + 1; k < values_length; k++) + { + ecma_free_value (stack_top_p[k]); + } + + return ret_value; + } + } + else + { + ecma_value_t put_comp = ecma_builtin_helper_def_prop_by_index (array_obj_p, + idx, + stack_top_p[i], + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); + JERRY_ASSERT (ecma_is_value_true (put_comp)); + ecma_free_value (stack_top_p[i]); + } + } + + return ECMA_VALUE_EMPTY; +} /* opfunc_append_to_spread_array */ + +/** + * Spread function call/construct arguments into an ecma-collection + * + * @return NULL - if the operation failed + * pointer to the ecma-collection with the spreaded arguments, otherwise + */ +JERRY_ATTR_NOINLINE ecma_collection_t * +opfunc_spread_arguments (ecma_value_t *stack_top_p, /**< pointer to the current stack top */ + uint8_t arguments_list_len) /**< number of arguments */ +{ + ecma_collection_t *buff_p = ecma_new_collection (); + + for (uint32_t i = 0; i < arguments_list_len; i++) + { + ecma_value_t arg = *stack_top_p++; + + if (arg != ECMA_VALUE_SPREAD_ELEMENT) + { + ecma_collection_push_back (buff_p, arg); + continue; + } + + ecma_value_t ret_value = ECMA_VALUE_ERROR; + ecma_value_t spread_value = *stack_top_p++; + i++; + + ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_EMPTY); + + if (!ECMA_IS_VALUE_ERROR (iterator)) + { + while (true) + { + ecma_value_t next_value = ecma_op_iterator_step (iterator); + + if (ECMA_IS_VALUE_ERROR (next_value)) + { + break; + } + + if (ecma_is_value_false (next_value)) + { + ret_value = ECMA_VALUE_EMPTY; + break; + } + + ecma_value_t value = ecma_op_iterator_value (next_value); + + ecma_free_value (next_value); + + if (ECMA_IS_VALUE_ERROR (value)) + { + break; + } + + ecma_collection_push_back (buff_p, value); + } + } + + ecma_free_value (iterator); + ecma_free_value (spread_value); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + for (uint32_t k = i + 1; k < arguments_list_len; k++) + { + ecma_free_value (*stack_top_p++); + } + + ecma_collection_free (buff_p); + buff_p = NULL; + break; + } + } + + return buff_p; +} /* opfunc_spread_arguments */ + +#endif /* ENABLED (JERRY_ES2015) */ + +/** + * 'VM_OC_APPEND_ARRAY' opcode handler, for setting array object properties + * + * @return ECMA_VALUE_ERROR - if the operation failed + * ECMA_VALUE_EMPTY, otherwise + */ +ecma_value_t JERRY_ATTR_NOINLINE +opfunc_append_array (ecma_value_t *stack_top_p, /**< current stack top */ + uint16_t values_length) /**< number of elements to set + * with potential OPFUNC_HAS_SPREAD_ELEMENT flag */ +{ +#if ENABLED (JERRY_ES2015) + if (values_length >= OPFUNC_HAS_SPREAD_ELEMENT) + { + return opfunc_append_to_spread_array (stack_top_p, (uint16_t) (values_length & ~OPFUNC_HAS_SPREAD_ELEMENT)); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *array_obj_p = ecma_get_object_from_value (stack_top_p[-1]); + JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY); + + ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; + uint32_t old_length = ext_array_obj_p->u.array.length; + + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_array_obj_p))) + { + uint32_t filled_holes = 0; + ecma_value_t *values_p = ecma_fast_array_extend (array_obj_p, old_length + values_length); + + for (uint32_t i = 0; i < values_length; i++) + { + values_p[old_length + i] = stack_top_p[i]; + + if (!ecma_is_value_array_hole (stack_top_p[i])) + { + filled_holes++; + + if (ecma_is_value_object (stack_top_p[i])) + { + ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); + } + } + } + + ext_array_obj_p->u.array.u.hole_count -= filled_holes * ECMA_FAST_ARRAY_HOLE_ONE; + + if (JERRY_UNLIKELY ((values_length - filled_holes) > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT)) + { + ecma_fast_array_convert_to_normal (array_obj_p); + } + } + else + { + for (uint32_t i = 0; i < values_length; i++) + { + if (!ecma_is_value_array_hole (stack_top_p[i])) + { + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (old_length + i); + + ecma_property_value_t *prop_value_p; + + prop_value_p = ecma_create_named_data_property (array_obj_p, + index_str_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + ecma_deref_ecma_string (index_str_p); + prop_value_p->value = stack_top_p[i]; + + if (ecma_is_value_object (stack_top_p[i])) + { + ecma_free_value (stack_top_p[i]); + } + + } + + ext_array_obj_p->u.array.length = old_length + values_length; + } + } + + return ECMA_VALUE_EMPTY; +} /* opfunc_append_array */ + +#if ENABLED (JERRY_ES2015) + +/** + * Create an executable object using the current frame context + * + * @return executable object + */ +ecma_value_t +opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; + size_t size; + + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_header_p); + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + size = ((size_t) args_p->register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + size = ((size_t) args_p->register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t); + } + + size_t total_size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t)); + + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_function_obj_p), + ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE); + + ecma_object_t *object_p = ecma_create_object (proto_p, + total_size, + ECMA_OBJECT_TYPE_CLASS); + + ecma_deref_object (proto_p); + + vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; + + executable_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_GENERATOR_UL; + executable_object_p->extended_object.u.class_prop.extra_info = 0; + + JERRY_ASSERT (!frame_ctx_p->is_eval_code); + JERRY_ASSERT (frame_ctx_p->context_depth == 0); + + vm_frame_ctx_t *new_frame_ctx_p = &(executable_object_p->frame_ctx); + *new_frame_ctx_p = *frame_ctx_p; + + /* The old register values are discarded. */ + ecma_value_t *new_registers_p = VM_GET_REGISTERS (new_frame_ctx_p); + memcpy (new_registers_p, VM_GET_REGISTERS (frame_ctx_p), size); + + size_t stack_top = (size_t) (frame_ctx_p->stack_top_p - VM_GET_REGISTERS (frame_ctx_p)); + ecma_value_t *new_stack_top_p = new_registers_p + stack_top; + + new_frame_ctx_p->stack_top_p = new_stack_top_p; + + /* Initial state is "not running", so all object references are released. */ + + while (new_registers_p < new_stack_top_p) + { + ecma_deref_if_object (*new_registers_p++); + } + + new_frame_ctx_p->this_binding = ecma_copy_value_if_not_object (new_frame_ctx_p->this_binding); + + JERRY_CONTEXT (vm_top_context_p) = new_frame_ctx_p->prev_context_p; + + return ecma_make_object_value (object_p); +} /* opfunc_create_executable_object */ + +/** + * Resume the execution of an inactive executable object + * + * @return value provided by the execution + */ +ecma_value_t +opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /**< executable object */ + ecma_value_t value) /**< value pushed onto the stack (takes the reference) */ +{ + const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p; + ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); + ecma_value_t *register_end_p; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + register_end_p = register_p + args_p->register_end; + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + register_end_p = register_p + args_p->register_end; + } + + while (register_p < register_end_p) + { + ecma_ref_if_object (*register_p++); + } + + if (executable_object_p->frame_ctx.context_depth > 0) + { + vm_ref_lex_env_chain (executable_object_p->frame_ctx.lex_env_p, + executable_object_p->frame_ctx.context_depth, + register_p, + true); + + register_p += executable_object_p->frame_ctx.context_depth; + } + + ecma_value_t *stack_top_p = executable_object_p->frame_ctx.stack_top_p; + + while (register_p < stack_top_p) + { + ecma_ref_if_object (*register_p++); + } + + *register_p++ = value; + executable_object_p->frame_ctx.stack_top_p = register_p; + + JERRY_ASSERT (ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info)); + + executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_RUNNING; + + executable_object_p->frame_ctx.prev_context_p = JERRY_CONTEXT (vm_top_context_p); + JERRY_CONTEXT (vm_top_context_p) = &executable_object_p->frame_ctx; + + /* inside the generators the "new.target" is always "undefined" as it can't be invoked with "new" */ + ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = NULL; + + ecma_value_t result = vm_execute (&executable_object_p->frame_ctx); + + JERRY_CONTEXT (current_new_target) = old_new_target; + executable_object_p->extended_object.u.class_prop.extra_info &= (uint16_t) ~ECMA_EXECUTABLE_OBJECT_RUNNING; + + if (executable_object_p->frame_ctx.call_operation != VM_EXEC_RETURN) + { + JERRY_ASSERT (executable_object_p->frame_ctx.call_operation == VM_NO_EXEC_OP); + + /* All resources are released. */ + executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_COMPLETED; + return result; + } + + JERRY_CONTEXT (vm_top_context_p) = executable_object_p->frame_ctx.prev_context_p; + + register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx); + + while (register_p < register_end_p) + { + ecma_deref_if_object (*register_p++); + } + + if (executable_object_p->frame_ctx.context_depth > 0) + { + vm_ref_lex_env_chain (executable_object_p->frame_ctx.lex_env_p, + executable_object_p->frame_ctx.context_depth, + register_p, + false); + + register_p += executable_object_p->frame_ctx.context_depth; + } + + stack_top_p = executable_object_p->frame_ctx.stack_top_p; + + while (register_p < stack_top_p) + { + ecma_deref_if_object (*register_p++); + } + + return result; +} /* opfunc_resume_executable_object */ + +/** + * Create a Promise object if needed and resolve it with a value + * + * @return Promise object + */ +ecma_value_t +opfunc_return_promise (ecma_value_t value) /**< value */ +{ + ecma_value_t promise = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE)); + ecma_value_t result = ecma_promise_reject_or_resolve (promise, value, true); + + ecma_free_value (value); + return result; +} /* opfunc_return_promise */ + +/** + * Implicit class constructor handler when the classHeritage is not present. + * + * See also: ECMAScript v6, 14.5.14.10.b.i + * + * @return ECMA_VALUE_ERROR - if the function was invoked without 'new' + * ECMA_VALUE_UNDEFINED - otherwise + */ +static ecma_value_t +ecma_op_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); + + if (JERRY_CONTEXT (current_new_target) == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); + } + + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_implicit_constructor_handler_cb */ + +/** + * Implicit class constructor handler when the classHeritage is present. + * + * See also: ECMAScript v6, 14.5.14.10.a.i + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the super call - otherwise + */ +static ecma_value_t +ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); + + if (JERRY_CONTEXT (current_new_target) == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); + } + + ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj); + ecma_value_t super_ctor = ecma_op_function_get_super_constructor (func_obj_p); + + if (ECMA_IS_VALUE_ERROR (super_ctor)) + { + return super_ctor; + } + + ecma_object_t *super_ctor_p = ecma_get_object_from_value (super_ctor); + + ecma_value_t result = ecma_op_function_construct (super_ctor_p, + JERRY_CONTEXT (current_new_target), + args_p, + args_count); + + if (ecma_is_value_object (result)) + { + ecma_value_t proto_value = ecma_op_object_get_by_magic_id (JERRY_CONTEXT (current_new_target), + LIT_MAGIC_STRING_PROTOTYPE); + if (ECMA_IS_VALUE_ERROR (proto_value)) + { + ecma_free_value (result); + result = ECMA_VALUE_ERROR; + } + else if (ecma_is_value_object (proto_value)) + { + ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp, + ecma_get_object_from_value (proto_value)); + } + ecma_free_value (proto_value); + } + + ecma_deref_object (super_ctor_p); + + return result; +} /* ecma_op_implicit_constructor_handler_heritage_cb */ + +/** + * Create implicit class constructor + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - new external function ecma-object + */ +ecma_value_t +opfunc_create_implicit_class_constructor (uint8_t opcode) /**< current cbc opcode */ +{ + /* 8. */ + ecma_object_t *func_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE), + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; + + /* 10.a.i */ + if (opcode == CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE) + { + ext_func_obj_p->u.external_handler_cb = ecma_op_implicit_constructor_handler_heritage_cb; + } + /* 10.b.i */ + else + { + ext_func_obj_p->u.external_handler_cb = ecma_op_implicit_constructor_handler_cb; + } + + ecma_property_value_t *prop_value_p; + prop_value_p = ecma_create_named_data_property (func_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), + ECMA_PROPERTY_FLAG_CONFIGURABLE, + NULL); + + prop_value_p->value = ecma_make_uint32_value (0); + + return ecma_make_object_value (func_obj_p); +} /* opfunc_create_implicit_class_constructor */ + +/** + * Set the [[HomeObject]] attribute of the given functon object + */ +static inline void JERRY_ATTR_ALWAYS_INLINE +opfunc_set_home_object (ecma_object_t *func_p, /**< function object */ + ecma_object_t *parent_env_p) /**< parent environment */ +{ + if (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + JERRY_ASSERT (!ecma_get_object_is_builtin (func_p)); + + ECMA_SET_NON_NULL_POINTER_TAG (((ecma_extended_object_t *) func_p)->u.function.scope_cp, parent_env_p, 0); + } +} /* opfunc_set_home_object */ + +/** + * ClassDefinitionEvaluation environment initialization part + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +void +opfunc_push_class_environment (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t **vm_stack_top, /**< VM stack top */ + ecma_value_t class_name) /**< class name */ +{ + JERRY_ASSERT (ecma_is_value_undefined (class_name) || ecma_is_value_string (class_name)); + ecma_object_t *class_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); + + /* 4.a */ + if (!ecma_is_value_undefined (class_name)) + { + ecma_op_create_immutable_binding (class_env_p, + ecma_get_string_from_value (class_name), + ECMA_VALUE_UNINITIALIZED); + } + frame_ctx_p->lex_env_p = class_env_p; + + *(*vm_stack_top)++ = ECMA_VALUE_RELEASE_LEX_ENV; +} /* opfunc_push_class_environment */ + +/** + * ClassDefinitionEvaluation object initialization part + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_init_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t *stack_top_p) /**< stack top */ +{ + /* 5.b, 6.e.ii */ + ecma_object_t *ctor_parent_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *proto_parent_p = NULL; + bool free_proto_parent = false; + + ecma_value_t super_class = stack_top_p[-2]; + ecma_object_t *ctor_p = ecma_get_object_from_value (stack_top_p[-1]); + + bool heritage_present = !ecma_is_value_array_hole (super_class); + + /* 5. ClassHeritage opt is not present */ + if (!heritage_present) + { + /* 5.a */ + proto_parent_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + } + else if (!ecma_is_value_null (super_class)) + { + /* 6.f, 6.g.i */ + if (!ecma_is_constructor (super_class) + || ecma_op_function_is_generator (ecma_get_object_from_value (super_class))) + { + return ecma_raise_type_error ("Class extends value is not a constructor or null"); + } + + ecma_object_t *parent_p = ecma_get_object_from_value (super_class); + + /* 6.g.ii */ + ecma_value_t proto_parent = ecma_op_object_get_by_magic_id (parent_p, LIT_MAGIC_STRING_PROTOTYPE); + + /* 6.g.iii */ + if (ECMA_IS_VALUE_ERROR (proto_parent)) + { + return proto_parent; + } + + /* 6.g.iv */ + if (ecma_is_value_object (proto_parent)) + { + proto_parent_p = ecma_get_object_from_value (proto_parent); + free_proto_parent = true; + } + else if (ecma_is_value_null (proto_parent)) + { + proto_parent_p = NULL; + } + else + { + ecma_free_value (proto_parent); + return ecma_raise_type_error ("Property 'prototype' is not an object or null"); + } + + /* 6.g.v */ + ctor_parent_p = parent_p; + } + + /* 7. */ + ecma_object_t *proto_p = ecma_create_object (proto_parent_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_value_t proto = ecma_make_object_value (proto_p); + + ECMA_SET_POINTER (ctor_p->u2.prototype_cp, ctor_parent_p); + + if (free_proto_parent) + { + ecma_deref_object (proto_parent_p); + } + ecma_free_value (super_class); + + /* 16. */ + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (ctor_p, + ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE), + ECMA_PROPERTY_FIXED, + NULL); + property_value_p->value = proto; + + /* 18. */ + property_value_p = ecma_create_named_data_property (proto_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + property_value_p->value = ecma_make_object_value (ctor_p); + + if (ecma_get_object_type (ctor_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + ecma_object_t *proto_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, + proto_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + + ECMA_SET_NON_NULL_POINTER_TAG (((ecma_extended_object_t *) ctor_p)->u.function.scope_cp, proto_env_p, 0); + + /* 15. set F’s [[ConstructorKind]] internal slot to "derived". */ + if (heritage_present) + { + ECMA_SET_THIRD_BIT_TO_POINTER_TAG (((ecma_extended_object_t *) ctor_p)->u.function.scope_cp); + } + + ecma_deref_object (proto_env_p); + } + + stack_top_p[-2] = stack_top_p[-1]; + stack_top_p[-1] = proto; + + return ECMA_VALUE_EMPTY; +} /* opfunc_init_class */ + +/** + * Set [[Enumerable]] and [[HomeObject]] attributes for all class method + */ +static void +opfunc_set_class_attributes (ecma_object_t *obj_p, /**< object */ + ecma_object_t *parent_env_p) /**< parent environment */ +{ + jmem_cpointer_t prop_iter_cp = obj_p->u1.property_list_cp; + +#if ENABLED (JERRY_PROPRETY_HASHMAP) + if (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + { + prop_iter_cp = prop_iter_p->next_property_cp; + } + } +#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ + + while (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + ecma_property_pair_t *property_pair_p = (ecma_property_pair_t *) prop_iter_p; + + for (uint32_t index = 0; index < ECMA_PROPERTY_PAIR_ITEM_COUNT; index++) + { + uint8_t property = property_pair_p->header.types[index]; + + if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA) + { + if (ecma_is_value_object (property_pair_p->values[index].value) + && ecma_is_property_enumerable (property)) + { + property_pair_p->header.types[index] = (uint8_t) (property & ~ECMA_PROPERTY_FLAG_ENUMERABLE); + opfunc_set_home_object (ecma_get_object_from_value (property_pair_p->values[index].value), parent_env_p); + } + } + else if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) + { + ecma_property_value_t *accessor_objs_p = property_pair_p->values + index; + + ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (accessor_objs_p); + + if (get_set_pair_p->getter_cp != JMEM_CP_NULL) + { + opfunc_set_home_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp), parent_env_p); + } + + if (get_set_pair_p->setter_cp != JMEM_CP_NULL) + { + opfunc_set_home_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp), parent_env_p); + } + } + else + { + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL); + + JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP + || property == ECMA_PROPERTY_TYPE_DELETED); + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + } +} /* opfunc_set_class_attributes */ + +/** + * Pop the current lexical environment referenced by the frame context + */ +void +opfunc_pop_lexical_environment (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + ecma_object_t *outer_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, frame_ctx_p->lex_env_p->u2.outer_reference_cp); + ecma_deref_object (frame_ctx_p->lex_env_p); + frame_ctx_p->lex_env_p = outer_env_p; +} /* opfunc_pop_lexical_environment */ + +/** + * ClassDefinitionEvaluation finalization part + * + * See also: ECMAScript v6, 14.5.14 + */ +void +opfunc_finalize_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t **vm_stack_top_p, /**< current vm stack top */ + ecma_value_t class_name) /**< class name */ +{ + JERRY_ASSERT (ecma_is_value_undefined (class_name) || ecma_is_value_string (class_name)); + ecma_value_t *stack_top_p = *vm_stack_top_p; + + ecma_object_t *ctor_p = ecma_get_object_from_value (stack_top_p[-2]); + ecma_object_t *proto_p = ecma_get_object_from_value (stack_top_p[-1]); + + ecma_object_t *class_env_p = frame_ctx_p->lex_env_p; + + /* 23.a */ + if (!ecma_is_value_undefined (class_name)) + { + ecma_op_initialize_binding (class_env_p, ecma_get_string_from_value (class_name), stack_top_p[-2]); + } + + ecma_object_t *ctor_env_p = ecma_create_object_lex_env (class_env_p, + ctor_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + ecma_object_t *proto_env_p = ecma_create_object_lex_env (class_env_p, + proto_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + + opfunc_set_class_attributes (ctor_p, ctor_env_p); + opfunc_set_class_attributes (proto_p, proto_env_p); + + ecma_deref_object (proto_env_p); + ecma_deref_object (ctor_env_p); + + opfunc_pop_lexical_environment (frame_ctx_p); + + ecma_deref_object (proto_p); + + /* only the current class remains on the stack */ + JERRY_ASSERT (stack_top_p[-3] == ECMA_VALUE_RELEASE_LEX_ENV); + stack_top_p[-3] = stack_top_p[-2]; + *vm_stack_top_p -= 2; +} /* opfunc_finalize_class */ + +/** + * MakeSuperPropertyReference operation + * + * See also: ECMAScript v6, 12.3.5.3 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, /**< current vm stack top */ + vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t prop_name, /**< property name to resolve */ + uint8_t opcode) /**< current cbc opcode */ +{ + ecma_value_t parent = ecma_op_resolve_super_base (frame_ctx_p->lex_env_p); + + if (ECMA_IS_VALUE_ERROR (parent)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot invoke nullable super method.")); + } + + if (ECMA_IS_VALUE_ERROR (ecma_op_check_object_coercible (parent))) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t *stack_top_p = *vm_stack_top_p; + + if (opcode >= CBC_EXT_SUPER_PROP_ASSIGNMENT_REFERENCE) + { + JERRY_ASSERT (opcode == CBC_EXT_SUPER_PROP_ASSIGNMENT_REFERENCE + || opcode == CBC_EXT_SUPER_PROP_LITERAL_ASSIGNMENT_REFERENCE); + *stack_top_p++ = parent; + *stack_top_p++ = ecma_copy_value (prop_name); + *vm_stack_top_p = stack_top_p; + + return ECMA_VALUE_EMPTY; + } + + ecma_object_t *parent_p = ecma_get_object_from_value (parent); + ecma_string_t *prop_name_p = ecma_op_to_prop_name (prop_name); + + if (prop_name_p == NULL) + { + ecma_deref_object (parent_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ecma_op_object_get_with_receiver (parent_p, prop_name_p, frame_ctx_p->this_binding); + ecma_deref_ecma_string (prop_name_p); + ecma_deref_object (parent_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + if (opcode == CBC_EXT_SUPER_PROP_LITERAL_REFERENCE || opcode == CBC_EXT_SUPER_PROP_REFERENCE) + { + *stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding); + *stack_top_p++ = ECMA_VALUE_UNDEFINED; + } + + *stack_top_p++ = result; + *vm_stack_top_p = stack_top_p; + + return ECMA_VALUE_EMPTY; +} /* opfunc_form_super_reference */ + +/** + * Assignment operation for SuperRefence base + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_assign_super_reference (ecma_value_t **vm_stack_top_p, /**< vm stack top */ + vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + uint32_t opcode_data) /**< opcode data to store the result */ +{ + ecma_value_t *stack_top_p = *vm_stack_top_p; + + ecma_value_t base_obj = ecma_op_to_object (stack_top_p[-3]); + + if (ECMA_IS_VALUE_ERROR (base_obj)) + { + return base_obj; + } + + ecma_object_t *base_obj_p = ecma_get_object_from_value (base_obj); + ecma_string_t *prop_name_p = ecma_op_to_prop_name (stack_top_p[-2]); + + if (prop_name_p == NULL) + { + ecma_deref_object (base_obj_p); + return ECMA_VALUE_ERROR; + } + + bool is_strict = (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0; + + ecma_value_t result = ecma_op_object_put_with_receiver (base_obj_p, + prop_name_p, + stack_top_p[-1], + frame_ctx_p->this_binding, + is_strict); + + ecma_deref_ecma_string (prop_name_p); + ecma_deref_object (base_obj_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + for (int32_t i = 1; i <= 3; i++) + { + ecma_free_value (stack_top_p[-i]); + } + + stack_top_p -= 3; + + if (opcode_data & VM_OC_PUT_STACK) + { + *stack_top_p++ = result; + } + else if (opcode_data & VM_OC_PUT_BLOCK) + { + ecma_fast_free_value (frame_ctx_p->block_result); + frame_ctx_p->block_result = result; + } + + *vm_stack_top_p = stack_top_p; + + return result; +} /* opfunc_assign_super_reference */ +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index faafba7c..d556370c 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -31,10 +31,13 @@ */ typedef enum { - NUMBER_ARITHMETIC_SUBSTRACTION, /**< substraction */ + NUMBER_ARITHMETIC_SUBTRACTION, /**< subtraction */ NUMBER_ARITHMETIC_MULTIPLICATION, /**< multiplication */ NUMBER_ARITHMETIC_DIVISION, /**< division */ NUMBER_ARITHMETIC_REMAINDER, /**< remainder calculation */ +#if ENABLED (JERRY_ES2015) + NUMBER_ARITHMETIC_EXPONENTIATION, /**< exponentiation */ +#endif /* ENABLED (JERRY_ES2015) */ } number_arithmetic_op; /** @@ -51,8 +54,16 @@ typedef enum NUMBER_BITWISE_NOT, /**< bitwise NOT calculation */ } number_bitwise_logic_op; +/** + * The stack contains spread object during the upcoming APPEND_ARRAY operation + */ +#define OPFUNC_HAS_SPREAD_ELEMENT (1 << 8) + ecma_value_t -vm_var_decl (vm_frame_ctx_t *frame_ctx_p, ecma_string_t *var_name_str_p); +vm_var_decl (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_configurable_bindings); + +ecma_value_t +vm_set_var (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_strict, ecma_value_t lit_value); ecma_value_t opfunc_equality (ecma_value_t left_value, ecma_value_t right_value); @@ -93,6 +104,47 @@ vm_op_delete_var (ecma_value_t name_literal, ecma_object_t *lex_env_p); ecma_collection_t * opfunc_for_in (ecma_value_t left_value, ecma_value_t *result_obj_p); +#if ENABLED (JERRY_ES2015) +ecma_collection_t * +opfunc_spread_arguments (ecma_value_t *stack_top_p, uint8_t argument_list_len); +#endif /* ENABLED (JERRY_ES2015) */ + +ecma_value_t +opfunc_append_array (ecma_value_t *stack_top_p, uint16_t values_length); + +#if ENABLED (JERRY_ES2015) +ecma_value_t +opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p); + +ecma_value_t +opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ecma_value_t value); + +ecma_value_t +opfunc_return_promise (ecma_value_t value); + +ecma_value_t +opfunc_create_implicit_class_constructor (uint8_t opcode); + +void +opfunc_push_class_environment (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top, ecma_value_t class_name); + +ecma_value_t +opfunc_init_class (vm_frame_ctx_t *frame_context_p, ecma_value_t *stack_top_p); + +void +opfunc_pop_lexical_environment (vm_frame_ctx_t *frame_ctx_p); + +void +opfunc_finalize_class (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top_p, ecma_value_t class_name); + +ecma_value_t +opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, vm_frame_ctx_t *frame_ctx_p, ecma_value_t prop_name, + uint8_t opcode); + +ecma_value_t +opfunc_assign_super_reference (ecma_value_t **vm_stack_top_p, vm_frame_ctx_t *frame_ctx_p, uint32_t opcode_data); +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index 421674f6..92b8a4a3 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -41,29 +41,48 @@ typedef struct vm_frame_ctx_t { const ecma_compiled_code_t *bytecode_header_p; /**< currently executed byte-code data */ - uint8_t *byte_code_p; /**< current byte code pointer */ - uint8_t *byte_code_start_p; /**< byte code start pointer */ - ecma_value_t *registers_p; /**< register start pointer */ + const uint8_t *byte_code_p; /**< current byte code pointer */ + const uint8_t *byte_code_start_p; /**< byte code start pointer */ ecma_value_t *stack_top_p; /**< stack top pointer */ ecma_value_t *literal_start_p; /**< literal list start pointer */ ecma_object_t *lex_env_p; /**< current lexical environment */ -#if defined (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) struct vm_frame_ctx_t *prev_context_p; /**< previous context */ -#endif /* defined (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) */ ecma_value_t this_binding; /**< this binding */ ecma_value_t block_result; /**< block result */ #if defined(JERRY_FUNCTION_BACKTRACE) && !defined(__APPLE__) ecma_value_t callee_value; #endif -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) ecma_value_t resource_name; /**< current resource name (usually a file name) */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) uint32_t current_line; /**< currently executed line */ #endif /* ENABLED (JERRY_LINE_INFO) */ uint16_t context_depth; /**< current context depth */ uint8_t is_eval_code; /**< eval mode flag */ uint8_t call_operation; /**< perform a call or construct operation */ + /* Registers start immediately after the frame context. */ } vm_frame_ctx_t; +/** + * Get register list corresponding to the frame context. + */ +#define VM_GET_REGISTERS(frame_ctx_p) ((ecma_value_t *) ((frame_ctx_p) + 1)) + +/** + * Read or write a specific register. + */ +#define VM_GET_REGISTER(frame_ctx_p, i) (((ecma_value_t *) ((frame_ctx_p) + 1))[i]) + +/** + * Generator frame context. + */ +typedef struct +{ + ecma_extended_object_t extended_object; /**< extended object part */ + vm_frame_ctx_t frame_ctx; /**< frame context part */ +} vm_executable_object_t; + /** * @} * @} diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index a00b0c02..e22b3509 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -18,6 +18,7 @@ #include "ecma-helpers.h" #include "vm-defines.h" #include "vm-stack.h" +#include "ecma-iterator-object.h" /** \addtogroup vm Virtual machine * @{ @@ -26,8 +27,8 @@ * @{ */ -JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, - parser_with_context_stack_allocation_must_be_equal_to_parser_super_class_context_stack_allocation); +JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_BLOCK_CONTEXT_STACK_ALLOCATION, + parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation); /** * Abort (finalize) the current stack context, and remove it. @@ -38,58 +39,58 @@ ecma_value_t * vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_value_t *vm_stack_top_p) /**< current stack top */ { - switch (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1])) + ecma_value_t context_info = vm_stack_top_p[-1]; + + if (context_info & VM_CONTEXT_HAS_LEX_ENV) + { + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + ecma_deref_object (lex_env_p); + } + + switch (VM_GET_CONTEXT_TYPE (context_info)) { case VM_CONTEXT_FINALLY_THROW: case VM_CONTEXT_FINALLY_RETURN: { ecma_free_value (vm_stack_top_p[-2]); - - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); - vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; - break; + /* FALLTHRU */ } case VM_CONTEXT_FINALLY_JUMP: case VM_CONTEXT_TRY: + case VM_CONTEXT_CATCH: { VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; break; } - case VM_CONTEXT_CATCH: - { - JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION > PARSER_WITH_CONTEXT_STACK_ALLOCATION); - - const uint16_t size_diff = PARSER_TRY_CONTEXT_STACK_ALLOCATION - PARSER_WITH_CONTEXT_STACK_ALLOCATION; - - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, size_diff); - vm_stack_top_p -= size_diff; - /* FALLTHRU */ - } +#if ENABLED (JERRY_ES2015) + case VM_CONTEXT_BLOCK: +#endif /* ENABLED (JERRY_ES2015) */ case VM_CONTEXT_WITH: -#if ENABLED (JERRY_ES2015_CLASS) - case VM_CONTEXT_SUPER_CLASS: -#endif /* ENABLED (JERRY_ES2015_CLASS) */ { - ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; - JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); - frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); - ecma_deref_object (lex_env_p); - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_WITH_CONTEXT_STACK_ALLOCATION; break; } -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case VM_CONTEXT_FOR_OF: { + ecma_value_t iterator = vm_stack_top_p[-3]; + + if (context_info & VM_CONTEXT_CLOSE_ITERATOR) + { + ecma_op_iterator_close (iterator); + } + ecma_free_value (iterator); + ecma_free_value (vm_stack_top_p[-2]); - ecma_free_value (vm_stack_top_p[-3]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION; break; } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ default: { JERRY_ASSERT (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]) == VM_CONTEXT_FOR_IN); @@ -106,7 +107,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_collection_destroy (collection_p); - ecma_deref_object (ecma_get_object_from_value (vm_stack_top_p[-4])); + ecma_free_value (vm_stack_top_p[-4]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; @@ -123,7 +124,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ * @return branch offset */ static uint32_t -vm_decode_branch_offset (uint8_t *branch_offset_p, /**< start offset of byte code */ +vm_decode_branch_offset (const uint8_t *branch_offset_p, /**< start offset of byte code */ uint32_t length) /**< length of the branch */ { uint32_t branch_offset = *branch_offset_p; @@ -184,7 +185,7 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ context_type = VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]); if (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_CATCH) { - uint8_t *byte_code_p; + const uint8_t *byte_code_p; uint32_t branch_offset_length; uint32_t branch_offset; @@ -194,6 +195,16 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ return false; } +#if ENABLED (JERRY_ES2015) + if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) + { + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + ecma_deref_object (lex_env_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + byte_code_p = frame_ctx_p->byte_code_start_p + context_end; if (context_type == VM_CONTEXT_TRY) @@ -232,10 +243,15 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } else { - ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; - JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); - frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); - ecma_deref_object (lex_env_p); +#if !ENABLED (JERRY_ES2015) + if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) + { + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + ecma_deref_object (lex_env_p); + } +#endif /* !ENABLED (JERRY_ES2015) */ if (byte_code_p[0] == CBC_CONTEXT_END) { @@ -271,6 +287,108 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ return false; } /* vm_stack_find_finally */ +#if ENABLED (JERRY_ES2015) + +/** + * Get the offsets of ecma values from the specified item of a context. + * + * @return array of offsets, last item represents the size of the context item + */ +uint32_t +vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a context */ +{ + switch (VM_GET_CONTEXT_TYPE (context_item_p[-1])) + { + case VM_CONTEXT_FINALLY_THROW: + case VM_CONTEXT_FINALLY_RETURN: + { + return (2 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_TRY_CONTEXT_STACK_ALLOCATION; + } + case VM_CONTEXT_FINALLY_JUMP: + case VM_CONTEXT_TRY: + case VM_CONTEXT_CATCH: + { + return PARSER_TRY_CONTEXT_STACK_ALLOCATION; + } +#if ENABLED (JERRY_ES2015) + case VM_CONTEXT_BLOCK: +#endif /* ENABLED (JERRY_ES2015) */ + case VM_CONTEXT_WITH: + { + return PARSER_WITH_CONTEXT_STACK_ALLOCATION; + } +#if ENABLED (JERRY_ES2015) + case VM_CONTEXT_FOR_OF: + { + return ((3 << (VM_CONTEXT_OFFSET_SHIFT * 2)) + | (2 << (VM_CONTEXT_OFFSET_SHIFT)) + | PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); + } +#endif /* ENABLED (JERRY_ES2015) */ + default: + { + return (4 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; + } + } +} /* vm_get_context_value_offsets */ + +/** + * Ref / deref lexical environments in the chain using the current context. + */ +void +vm_ref_lex_env_chain (ecma_object_t *lex_env_p, /**< top of lexical environment */ + uint16_t context_depth, /**< depth of function context */ + ecma_value_t *context_end_p, /**< end of function context */ + bool do_ref) /**< ref or deref lexical environments */ +{ + ecma_value_t *context_top_p = context_end_p + context_depth; + JERRY_ASSERT (context_top_p > context_end_p); + + do + { + if (context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) + { + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + ecma_object_t *next_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + + if (do_ref) + { + ecma_ref_object (lex_env_p); + } + else + { + ecma_deref_object (lex_env_p); + } + + lex_env_p = next_lex_env_p; + } + + uint32_t offsets = vm_get_context_value_offsets (context_top_p); + + while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets)) + { + int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets); + + if (do_ref) + { + ecma_ref_if_object (context_top_p[offset]); + } + else + { + ecma_deref_if_object (context_top_p[offset]); + } + + offsets >>= VM_CONTEXT_OFFSET_SHIFT; + } + + JERRY_ASSERT (context_top_p >= context_end_p + offsets); + context_top_p -= offsets; + } + while (context_top_p > context_end_p); +} /* vm_ref_lex_env_chain */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/vm/vm-stack.h b/jerry-core/vm/vm-stack.h index 331c264b..a555d745 100644 --- a/jerry-core/vm/vm-stack.h +++ b/jerry-core/vm/vm-stack.h @@ -25,33 +25,85 @@ * @{ */ -#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | (end_offset) << 4)) -#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0xf)) -#define VM_GET_CONTEXT_END(value) ((value) >> 4) +/** + * Create context on the vm stack. + */ +#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | ((end_offset) << 7))) + +/** + * Create context on the vm stack with environment. + */ +#define VM_CREATE_CONTEXT_WITH_ENV(type, end_offset) \ + (VM_CREATE_CONTEXT ((type),(end_offset)) | VM_CONTEXT_HAS_LEX_ENV) + +/** + * Get type of a vm context. + */ +#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0x1f)) + +/** + * Get the end position of a vm context. + */ +#define VM_GET_CONTEXT_END(value) ((value) >> 7) + +/** + * This flag is set if the context has a lexical environment. + */ +#define VM_CONTEXT_HAS_LEX_ENV 0x20 + +/** + * This flag is set if the iterator close operation should be invoked during a for-of context break. + */ +#define VM_CONTEXT_CLOSE_ITERATOR 0x40 /** * Context types for the vm stack. */ typedef enum { + /* Update VM_CONTEXT_IS_FINALLY macro if the following three values are changed. */ VM_CONTEXT_FINALLY_JUMP, /**< finally context with a jump */ VM_CONTEXT_FINALLY_THROW, /**< finally context with a throw */ VM_CONTEXT_FINALLY_RETURN, /**< finally context with a return */ VM_CONTEXT_TRY, /**< try context */ VM_CONTEXT_CATCH, /**< catch context */ +#if ENABLED (JERRY_ES2015) + VM_CONTEXT_BLOCK, /**< block context */ +#endif /* ENABLED (JERRY_ES2015) */ VM_CONTEXT_WITH, /**< with context */ -#if ENABLED (JERRY_ES2015_CLASS) - VM_CONTEXT_SUPER_CLASS, /**< super class context */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ VM_CONTEXT_FOR_IN, /**< for-in context */ -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) VM_CONTEXT_FOR_OF, /**< for-of context */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ } vm_stack_context_type_t; +/** + * Checks whether the context type is a finally type. + */ +#define VM_CONTEXT_IS_FINALLY(context_type) \ + ((context_type) <= VM_CONTEXT_FINALLY_RETURN) + +/** + * Shift needs to be applied to get the next item of the offset array. + */ +#define VM_CONTEXT_OFFSET_SHIFT 4 + +/** + * Checks whether an offset is available. + */ +#define VM_CONTEXT_HAS_NEXT_OFFSET(offsets) ((offsets) >= (1 << VM_CONTEXT_OFFSET_SHIFT)) + +/** + * Gets the next offset from the offset array. + */ +#define VM_CONTEXT_GET_NEXT_OFFSET(offsets) (-((int32_t) ((offsets) & ((1 << VM_CONTEXT_OFFSET_SHIFT) - 1)))) + ecma_value_t *vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, ecma_value_t *vm_stack_top_p); bool vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top_ref_p, vm_stack_context_type_t finally_type, uint32_t search_limit); +uint32_t vm_get_context_value_offsets (ecma_value_t *context_item_p); +void vm_ref_lex_env_chain (ecma_object_t *lex_env_p, uint16_t context_depth, + ecma_value_t *context_end_p, bool do_ref); /** * @} diff --git a/jerry-core/vm/vm-utils.c b/jerry-core/vm/vm-utils.c index b96b05cd..d6cc482d 100644 --- a/jerry-core/vm/vm-utils.c +++ b/jerry-core/vm/vm-utils.c @@ -17,6 +17,7 @@ #include "ecma-helpers.h" #include "ecma-objects.h" #include "jcontext.h" +#include "lit-char-helpers.h" #include "vm.h" /** @@ -55,7 +56,7 @@ vm_is_direct_eval_form_call (void) static ecma_string_t* vm_get_function_name_string (vm_frame_ctx_t *context_p) { - ecma_string_t* func_name; + ecma_stringbuilder_t func_name_builder; if (context_p->prev_context_p != NULL) { vm_frame_ctx_t* prev_ctx_p = context_p->prev_context_p; ecma_object_t* func_obj = ecma_get_object_from_value (prev_ctx_p->callee_value); @@ -66,26 +67,26 @@ vm_get_function_name_string (vm_frame_ctx_t *context_p) ecma_string_t* name_prop = ecma_get_magic_string (LIT_MAGIC_STRING_NAME); ecma_value_t func_name_value = ecma_op_object_get (func_obj, name_prop); if (func_name_value == ECMA_VALUE_UNDEFINED) { - func_name = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *)"", 9); + func_name_builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) (""), 9); } else { - func_name = ecma_get_string_from_value (func_name_value); + func_name_builder = ecma_stringbuilder_create_from(ecma_get_string_from_value (func_name_value)); } ecma_deref_ecma_string (name_prop); } else { - func_name = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *)"", 11); + func_name_builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) (""), 11); } } else { - func_name = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *)"", 8); + func_name_builder = ecma_stringbuilder_create_raw ((lit_utf8_byte_t *) (""), 8); } - ecma_string_t* lbracket = ecma_new_ecma_string_from_utf8((const lit_utf8_byte_t *)"(", 1); - ecma_string_t* rbracket = ecma_new_ecma_string_from_utf8((const lit_utf8_byte_t *)")", 1); - func_name = ecma_concat_ecma_strings (func_name, lbracket); - func_name = ecma_concat_ecma_strings (func_name, rbracket); - func_name = ecma_append_magic_string_to_string (func_name, LIT_MAGIC_STRING_COMMA_CHAR); - func_name = ecma_append_magic_string_to_string (func_name, LIT_MAGIC_STRING_SPACE_CHAR); + ecma_string_t* lbracket = ecma_new_ecma_string_from_utf8((const lit_utf8_byte_t *) ("("), 1); + ecma_string_t* rbracket = ecma_new_ecma_string_from_utf8((const lit_utf8_byte_t *) (")"), 1); + ecma_stringbuilder_append (&func_name_builder, lbracket); + ecma_stringbuilder_append (&func_name_builder, rbracket); + ecma_stringbuilder_append_byte (&func_name_builder, LIT_CHAR_COMMA); + ecma_stringbuilder_append_byte (&func_name_builder, LIT_CHAR_SP); ecma_deref_ecma_string(rbracket); ecma_deref_ecma_string(lbracket); - return func_name; + return ecma_stringbuilder_finalize (&func_name_builder); } #endif @@ -109,7 +110,7 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p); ecma_object_t *array_p = ecma_get_object_from_value (result_array); - JERRY_ASSERT (((ecma_extended_object_t *) array_p)->u.array.is_fast_mode); + JERRY_ASSERT (ecma_op_object_is_fast_array (array_p)); uint32_t index = 0; while (context_p != NULL) @@ -120,16 +121,12 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite ecma_string_t* func_name = vm_get_function_name_string (context_p); func_name = ecma_concat_ecma_strings (func_name, str_p); - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_fast_array_set_property (array_p, index_str_p, ecma_make_string_value (func_name)); + ecma_fast_array_set_property (array_p, index, ecma_make_string_value (func_name)); ecma_deref_ecma_string(str_p); - ecma_deref_ecma_string(index_str_p); ecma_deref_ecma_string(func_name); #else - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_fast_array_set_property (array_p, index_str_p, ecma_make_string_value (str_p)); + ecma_fast_array_set_property (array_p, index, ecma_make_string_value (str_p)); ecma_deref_ecma_string (str_p); - ecma_deref_ecma_string (index_str_p); #endif context_p = context_p->prev_context_p; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 8fe72586..bc1e0898 100755 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -18,6 +18,7 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" #include "ecma-builtins.h" +#include "ecma-builtin-object.h" #include "ecma-comparison.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" @@ -46,6 +47,11 @@ * @{ */ +/** + * Special constant to represent direct eval code. + */ +#define VM_DIRECT_EVAL ((void *) 0x1) + /** * Get the value of object[property]. * @@ -70,7 +76,7 @@ vm_op_get_value (ecma_value_t object, /**< base object */ { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p) && (uint32_t) int_value < ext_object_p->u.array.length)) { ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); @@ -91,12 +97,12 @@ vm_op_get_value (ecma_value_t object, /**< base object */ property_name_p = ecma_get_string_from_value (property); } -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015) if (ecma_is_value_symbol (property)) { property_name_p = ecma_get_symbol_from_value (property); } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ +#endif /* ENABLED (JERRY_ES2015) */ if (property_name_p != NULL) { @@ -151,84 +157,101 @@ vm_op_get_value (ecma_value_t object, /**< base object */ * if the property setting is unsuccessful */ static ecma_value_t -vm_op_set_value (ecma_value_t object, /**< base object */ +vm_op_set_value (ecma_value_t base, /**< base object */ ecma_value_t property, /**< property name */ ecma_value_t value, /**< ecma value */ bool is_strict) /**< strict mode */ { - ecma_object_t * object_p; - - if (JERRY_UNLIKELY (!ecma_is_value_object (object))) - { - ecma_value_t to_object = ecma_op_to_object (object); - ecma_free_value (object); - - if (ECMA_IS_VALUE_ERROR (to_object)) - { -#if ENABLED (JERRY_ERROR_MESSAGES) - ecma_free_value (to_object); - ecma_free_value (JERRY_CONTEXT (error_value)); - - ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, - "Cannot set property '%' of %", - property, - object); - ecma_free_value (property); - - return error_value; -#else /* !ENABLED (JERRY_ERROR_MESSAGES) */ - ecma_free_value (property); - return to_object; -#endif /* ENABLED (JERRY_ERROR_MESSAGES) */ - } - - object_p = ecma_get_object_from_value (to_object); - ecma_set_object_extensible (object_p, false); - } - else - { - object_p = ecma_get_object_from_value (object); - } - + ecma_value_t result = ECMA_VALUE_EMPTY; + ecma_object_t *object_p; ecma_string_t *property_p; - if (!ecma_is_value_prop_name (property)) + if (JERRY_UNLIKELY (!ecma_is_value_object (base))) { - property_p = ecma_op_to_prop_name (property); - ecma_fast_free_value (property); - - if (JERRY_UNLIKELY (property_p == NULL)) + if (JERRY_UNLIKELY (ecma_is_value_null (base) || ecma_is_value_undefined (base))) { - ecma_deref_object (object_p); - return ECMA_VALUE_ERROR; +#if ENABLED (JERRY_ERROR_MESSAGES) + result = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, + "Cannot set property '%' of %", + property, + base); +#else /* !ENABLED (JERRY_ERROR_MESSAGES) */ + result = ecma_raise_type_error (NULL); +#endif /* ENABLED (JERRY_ERROR_MESSAGES) */ + ecma_free_value (property); + return result; } + + if (JERRY_UNLIKELY (!ecma_is_value_prop_name (property))) + { + property_p = ecma_op_to_string (property); + ecma_fast_free_value (property); + + if (JERRY_UNLIKELY (property_p == NULL)) + { + ecma_free_value (base); + return ECMA_VALUE_ERROR; + } + } + else + { + property_p = ecma_get_prop_name_from_value (property); + } + + ecma_value_t object = ecma_op_to_object (base); + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (object)); + + object_p = ecma_get_object_from_value (object); + ecma_op_ordinary_object_prevent_extensions (object_p); + + result = ecma_op_object_put_with_receiver (object_p, + property_p, + value, + base, + is_strict); + + ecma_free_value (base); } else { - property_p = ecma_get_prop_name_from_value (property); - } + object_p = ecma_get_object_from_value (base); - ecma_value_t completion_value = ECMA_VALUE_EMPTY; + if (JERRY_UNLIKELY (!ecma_is_value_prop_name (property))) + { + property_p = ecma_op_to_string (property); + ecma_fast_free_value (property); - if (!ecma_is_lexical_environment (object_p)) - { - completion_value = ecma_op_object_put (object_p, - property_p, - value, - is_strict); - } - else - { - completion_value = ecma_op_set_mutable_binding (object_p, - property_p, - value, - is_strict); + if (JERRY_UNLIKELY (property_p == NULL)) + { + ecma_deref_object (object_p); + return ECMA_VALUE_ERROR; + } + } + else + { + property_p = ecma_get_prop_name_from_value (property); + } + + if (!ecma_is_lexical_environment (object_p)) + { + result = ecma_op_object_put_with_receiver (object_p, + property_p, + value, + base, + is_strict); + } + else + { + result = ecma_op_set_mutable_binding (object_p, + property_p, + value, + is_strict); + } } ecma_deref_object (object_p); ecma_deref_ecma_string (property_p); - - return completion_value; + return result; } /* vm_op_set_value */ /** Compact bytecode define */ @@ -258,12 +281,15 @@ ecma_value_t vm_run_module (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode to run */ ecma_object_t *lex_env_p) /**< pointer to the specified lexenv to run in */ { - ecma_object_t *glob_obj_p = ecma_builtin_get_global (); + const ecma_value_t module_init_result = ecma_module_initialize_current (); + if (ECMA_IS_VALUE_ERROR (module_init_result)) + { + return module_init_result; + } return vm_run (bytecode_p, - ecma_make_object_value (glob_obj_p), + ECMA_VALUE_UNDEFINED, lex_env_p, - false, NULL, 0); } /* vm_run_module */ @@ -282,10 +308,39 @@ vm_run_global (const ecma_compiled_code_t *bytecode_p) /**< pointer to bytecode { ecma_object_t *glob_obj_p = ecma_builtin_get_global (); +#if ENABLED (JERRY_ES2015) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED) + { + ecma_create_global_lexical_block (); + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_object_t *const global_scope_p = ecma_get_global_scope (); + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (JERRY_CONTEXT (module_top_context_p) != NULL) + { + JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p)->parent_p == NULL); + ecma_module_t *module_p = JERRY_CONTEXT (module_top_context_p)->module_p; + + JERRY_ASSERT (module_p->scope_p == NULL); + ecma_ref_object (global_scope_p); + module_p->scope_p = global_scope_p; + + const ecma_value_t module_init_result = ecma_module_initialize_current (); + ecma_module_cleanup (); + JERRY_CONTEXT (module_top_context_p) = NULL; + + if (ECMA_IS_VALUE_ERROR (module_init_result)) + { + return module_init_result; + } + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + return vm_run (bytecode_p, ecma_make_object_value (glob_obj_p), - ecma_get_global_environment (), - false, + global_scope_p, NULL, 0); } /* vm_run_global */ @@ -310,6 +365,7 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ #if ENABLED (JERRY_DEBUGGER) uint32_t chain_index = parse_opts >> ECMA_PARSE_CHAIN_INDEX_SHIFT; + parse_opts &= (1 << ECMA_PARSE_CHAIN_INDEX_SHIFT) - 1; while (chain_index != 0) { @@ -333,7 +389,7 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ ecma_object_t *global_obj_p = ecma_builtin_get_global (); ecma_ref_object (global_obj_p); this_binding = ecma_make_object_value (global_obj_p); - lex_env_p = ecma_get_global_environment (); + lex_env_p = ecma_get_global_scope (); } ecma_ref_object (lex_env_p); @@ -341,16 +397,24 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0) { ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p); - ecma_deref_object (lex_env_p); + ecma_deref_object (lex_env_p); lex_env_p = strict_lex_env_p; } + if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED) != 0) + { + ecma_object_t *lex_block_p = ecma_create_decl_lex_env (lex_env_p); + lex_block_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK; + + ecma_deref_object (lex_env_p); + lex_env_p = lex_block_p; + } + ecma_value_t completion_value = vm_run (bytecode_data_p, this_binding, lex_env_p, - parse_opts, - NULL, + (parse_opts & ECMA_PARSE_DIRECT_EVAL) ? VM_DIRECT_EVAL : NULL, 0); ecma_deref_object (lex_env_p); @@ -397,16 +461,14 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ #if ENABLED (JERRY_BUILTIN_REGEXP) if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) { - ecma_value_t ret_value; - ret_value = ecma_op_create_regexp_object_from_bytecode ((re_compiled_code_t *) bytecode_p); + ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); - if (ECMA_IS_VALUE_ERROR (ret_value)) + if (JERRY_UNLIKELY (regexp_obj_p == NULL)) { - /* TODO: throw exception instead of define an 'undefined' value. */ - return ECMA_VALUE_UNDEFINED; + return ECMA_VALUE_ERROR; } - return ret_value; + return ecma_op_create_regexp_from_bytecode (regexp_obj_p, (re_compiled_code_t *) bytecode_p);; } #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ @@ -414,21 +476,24 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_object_t *func_obj_p; -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) - { -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p, - bytecode_p); -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - } - else +#if ENABLED (JERRY_ES2015) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, bytecode_p, frame_ctx_p->this_binding); } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + else if (bytecode_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + { + func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ return ecma_make_object_value (func_obj_p); } /* vm_construct_literal_object */ @@ -468,7 +533,7 @@ static const uint8_t vm_error_byte_code_p[] = CBC_EXT_OPCODE, CBC_EXT_ERROR }; -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) /** * 'super(...)' function call handler. */ @@ -478,41 +543,80 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL); JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE); - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3; uint8_t opcode = byte_code_p[-2]; - uint32_t arguments_list_len = byte_code_p[-1]; + uint32_t arguments_list_len; - ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len; + bool spread_arguments = opcode >= CBC_EXT_SPREAD_SUPER_CALL; - ecma_value_t func_value = stack_top_p[-1]; - ecma_value_t completion_value; - ecma_op_set_super_called (frame_ctx_p->lex_env_p); - ecma_value_t this_value = ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p); + ecma_collection_t *collection_p = NULL; + ecma_value_t *arguments_p; - if (!ecma_is_constructor (func_value)) + if (spread_arguments) { - completion_value = ecma_raise_type_error ("Class extends value is not a constructor."); + ecma_value_t collection = *(--frame_ctx_p->stack_top_p); + collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, collection); + arguments_p = collection_p->buffer_p; + arguments_list_len = collection_p->item_count; } else { - completion_value = ecma_op_function_construct (ecma_get_object_from_value (func_value), - this_value, - stack_top_p, + arguments_list_len = byte_code_p[-1]; + arguments_p = frame_ctx_p->stack_top_p; + } + + ecma_value_t func_value = *(--frame_ctx_p->stack_top_p); + ecma_value_t completion_value; + + ecma_property_t *prop_p = ecma_op_get_this_property (frame_ctx_p->lex_env_p); + + if (ecma_op_this_binding_is_initialized (prop_p)) + { + completion_value = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once")); + } + else if (!ecma_is_constructor (func_value)) + { + completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value is not a constructor.")); + } + else + { + ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value); + completion_value = ecma_op_function_construct (func_obj_p, + JERRY_CONTEXT (current_new_target), + arguments_p, arguments_list_len); - if (this_value != completion_value && ecma_is_value_object (completion_value)) + if (ecma_is_value_object (completion_value)) { - ecma_op_set_class_prototype (completion_value, this_value); - ecma_op_set_class_this_binding (frame_ctx_p->lex_env_p, completion_value); + ecma_value_t proto_value = ecma_op_object_get_by_magic_id (JERRY_CONTEXT (current_new_target), + LIT_MAGIC_STRING_PROTOTYPE); + if (ECMA_IS_VALUE_ERROR (proto_value)) + { + ecma_free_value (completion_value); + completion_value = ECMA_VALUE_ERROR; + } + else if (ecma_is_value_object (proto_value)) + { + ECMA_SET_POINTER (ecma_get_object_from_value (completion_value)->u2.prototype_cp, + ecma_get_object_from_value (proto_value)); + } + ecma_free_value (proto_value); } } /* Free registers. */ for (uint32_t i = 0; i < arguments_list_len; i++) { - ecma_fast_free_value (stack_top_p[i]); + ecma_fast_free_value (arguments_p[i]); } + if (collection_p != NULL) + { + ecma_collection_destroy (collection_p); + } + + ecma_free_value (func_value); + if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value))) { #if ENABLED (JERRY_DEBUGGER) @@ -522,8 +626,10 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { + ecma_op_bind_this_value (prop_p, completion_value); + frame_ctx_p->this_binding = completion_value; + frame_ctx_p->byte_code_p = byte_code_p; - ecma_free_value (*(--stack_top_p)); uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode]; if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) @@ -532,7 +638,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else if (opcode_data & VM_OC_PUT_STACK) { - *stack_top_p++ = completion_value; + *frame_ctx_p->stack_top_p++ = completion_value; } else { @@ -540,10 +646,103 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->block_result = completion_value; } } - - frame_ctx_p->stack_top_p = stack_top_p; } /* vm_super_call */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + +/** + * Perform one of the following call/construct operation with spreaded argument list + * - f(...args) + * - o.f(...args) + * - new O(...args) + */ +static void +vm_spread_operation (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE); + + uint8_t opcode = frame_ctx_p->byte_code_p[1]; + ecma_value_t completion_value; + ecma_value_t collection = *(--frame_ctx_p->stack_top_p); + + ecma_collection_t *collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, collection); + ecma_value_t func_value = *(--frame_ctx_p->stack_top_p); + bool is_call_prop = opcode >= CBC_EXT_SPREAD_CALL_PROP; + + if (frame_ctx_p->byte_code_p[1] == CBC_EXT_SPREAD_NEW) + { + if (!ecma_is_value_object (func_value) + || !ecma_object_is_constructor (ecma_get_object_from_value (func_value))) + { + completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor.")); + } + else + { + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (func_value); + + completion_value = ecma_op_function_construct (constructor_obj_p, + constructor_obj_p, + collection_p->buffer_p, + collection_p->item_count); + } + } + else + { + ecma_value_t this_value = is_call_prop ? frame_ctx_p->stack_top_p[-2] : ECMA_VALUE_UNDEFINED; + + if (!ecma_is_value_object (func_value) + || !ecma_op_object_is_callable (ecma_get_object_from_value (func_value))) + { + completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function.")); + } + else + { + ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value); + + completion_value = ecma_op_function_call (func_obj_p, + this_value, + collection_p->buffer_p, + collection_p->item_count); + } + + if (is_call_prop) + { + ecma_free_value (*(--frame_ctx_p->stack_top_p)); + ecma_free_value (*(--frame_ctx_p->stack_top_p)); + } + } + + ecma_collection_free (collection_p); + ecma_free_value (func_value); + + if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value))) + { +#if ENABLED (JERRY_DEBUGGER) + JERRY_CONTEXT (debugger_exception_byte_code_p) = frame_ctx_p->byte_code_p; +#endif /* ENABLED (JERRY_DEBUGGER) */ + frame_ctx_p->byte_code_p = (uint8_t *) vm_error_byte_code_p; + } + else + { + uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode]; + + if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) + { + ecma_fast_free_value (completion_value); + } + else if (opcode_data & VM_OC_PUT_STACK) + { + *frame_ctx_p->stack_top_p++ = completion_value; + } + else + { + ecma_fast_free_value (frame_ctx_p->block_result); + frame_ctx_p->block_result = completion_value; + } + + /* EXT_OPCODE, SPREAD_OPCODE, BYTE_ARG */ + frame_ctx_p->byte_code_p += 3; + } +} /* vm_spread_operation */ +#endif /* ENABLED (JERRY_ES2015) */ /** * 'Function call' opcode handler. @@ -553,7 +752,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ static void opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; uint8_t opcode = byte_code_p[-1]; uint32_t arguments_list_len; @@ -577,7 +776,8 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->callee_value = func_value; #endif - if (!ecma_op_is_callable (func_value)) + if (!ecma_is_value_object (func_value) + || !ecma_op_object_is_callable (ecma_get_object_from_value (func_value))) { completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function.")); } @@ -644,7 +844,7 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ static void opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; uint8_t opcode = byte_code_p[-1]; unsigned int arguments_list_len; @@ -661,7 +861,8 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t constructor_value = stack_top_p[-1]; ecma_value_t completion_value; - if (!ecma_is_constructor (constructor_value)) + if (!ecma_is_value_object (constructor_value) + || !ecma_object_is_constructor (ecma_get_object_from_value (constructor_value))) { completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor.")); } @@ -672,8 +873,9 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ #if defined(JERRY_FUNCTION_BACKTRACE) && !defined(__APPLE__) frame_ctx_p->callee_value = constructor_value; #endif + completion_value = ecma_op_function_construct (constructor_obj_p, - ECMA_VALUE_UNDEFINED, + constructor_obj_p, stack_top_p, arguments_list_len); } @@ -735,7 +937,7 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if ((literal_index) < register_end) \ { \ /* Note: There should be no specialization for arguments. */ \ - (target_value) = ecma_fast_copy_value (frame_ctx_p->registers_p[literal_index]); \ + (target_value) = ecma_fast_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); \ } \ else \ { \ @@ -764,168 +966,6 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } \ while (0) -/** - * Run initializer byte codes. - * - * @return ecma value - */ -static void -vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ -{ - const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; - uint8_t *byte_code_p = frame_ctx_p->byte_code_p; - uint16_t encoding_limit; - uint16_t encoding_delta; - uint16_t register_end; - ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; - bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0); - - /* Prepare. */ - if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING)) - { - encoding_limit = CBC_SMALL_LITERAL_ENCODING_LIMIT; - encoding_delta = CBC_SMALL_LITERAL_ENCODING_DELTA; - } - else - { - encoding_limit = CBC_FULL_LITERAL_ENCODING_LIMIT; - encoding_delta = CBC_FULL_LITERAL_ENCODING_DELTA; - } - - if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) - { - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) (frame_ctx_p->bytecode_header_p); - register_end = args_p->register_end; - } - else - { - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) (frame_ctx_p->bytecode_header_p); - register_end = args_p->register_end; - } - - while (true) - { - switch (*byte_code_p) - { - case CBC_DEFINE_VARS: - { - uint32_t literal_index_end; - uint32_t literal_index = register_end; - - byte_code_p++; - READ_LITERAL_INDEX (literal_index_end); - - while (literal_index <= literal_index_end) - { - ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - vm_var_decl (frame_ctx_p, name_p); - literal_index++; - } - break; - } - - case CBC_INITIALIZE_VAR: - case CBC_INITIALIZE_VARS: - { - uint8_t type = *byte_code_p; - uint32_t literal_index; - uint32_t literal_index_end; - - byte_code_p++; - READ_LITERAL_INDEX (literal_index); - - if (type == CBC_INITIALIZE_VAR) - { - literal_index_end = literal_index; - } - else - { - READ_LITERAL_INDEX (literal_index_end); - } - - while (literal_index <= literal_index_end) - { - uint32_t value_index; - ecma_value_t lit_value; - - READ_LITERAL_INDEX (value_index); - - if (value_index < register_end) - { - lit_value = frame_ctx_p->registers_p[value_index]; - } - else - { - lit_value = vm_construct_literal_object (frame_ctx_p, - literal_start_p[value_index]); - } - - if (literal_index < register_end) - { - frame_ctx_p->registers_p[literal_index] = lit_value; - } - else - { - ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - - vm_var_decl (frame_ctx_p, name_p); - - ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p, - name_p, - is_strict, - lit_value); - - JERRY_ASSERT (ecma_is_value_boolean (put_value_result) - || ecma_is_value_empty (put_value_result) - || ECMA_IS_VALUE_ERROR (put_value_result)); - - if (ECMA_IS_VALUE_ERROR (put_value_result)) - { - ecma_free_value (JERRY_CONTEXT (error_value)); - } else { -#if defined(JERRY_FUNCTION_NAME) && !defined(__APPLE__) - if (ecma_is_value_object(lit_value)) { - ecma_object_t* obj = ecma_get_object_from_value(lit_value); - ecma_object_type_t obj_type = ecma_get_object_type(obj); - if (obj_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION || obj_type == ECMA_OBJECT_TYPE_FUNCTION) { - ecma_string_t* property_name = ecma_get_magic_string (LIT_MAGIC_STRING_NAME); - ecma_property_value_t* prop_val = ecma_create_named_data_property(obj, property_name, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); - prop_val->value = ecma_copy_value(literal_start_p[literal_index]); - } - } -#endif - } - - if (value_index >= register_end) - { - ecma_free_value (lit_value); - } - } - - literal_index++; - } - break; - } - -#if ENABLED (JERRY_SNAPSHOT_EXEC) - case CBC_SET_BYTECODE_PTR: - { - memcpy (&byte_code_p, byte_code_p + 1, sizeof (uint8_t *)); - frame_ctx_p->byte_code_start_p = byte_code_p; - break; - } -#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ - - default: - { - frame_ctx_p->byte_code_p = byte_code_p; - return; - } - } - } -} /* vm_init_loop */ - /** * Run generic byte code. * @@ -935,7 +975,7 @@ static ecma_value_t JERRY_ATTR_NOINLINE vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; - uint8_t *byte_code_p = frame_ctx_p->byte_code_p; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p; ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; ecma_value_t *stack_top_p; @@ -986,7 +1026,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ /* Internal loop for byte code execution. */ while (true) { - uint8_t *byte_code_start_p = byte_code_p; + const uint8_t *byte_code_start_p = byte_code_p; uint8_t opcode = *byte_code_p++; uint32_t opcode_data = opcode; @@ -1022,7 +1062,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_GET_STACK_LITERAL: { - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); right_value = left_value; left_value = *(--stack_top_p); break; @@ -1043,12 +1083,12 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (operands == VM_OC_GET_STACK || operands == VM_OC_GET_STACK_STACK); - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); left_value = *(--stack_top_p); if (operands == VM_OC_GET_STACK_STACK) { - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); right_value = left_value; left_value = *(--stack_top_p); } @@ -1088,16 +1128,17 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { JERRY_CONTEXT (vm_exec_stop_counter) = 1; - if (!ecma_is_value_error_reference (result)) + if (ecma_is_value_error_reference (result)) { - JERRY_CONTEXT (error_value) = result; + ecma_raise_error_from_error_reference (result); } else { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result, false); + jcontext_raise_exception (result); } - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + JERRY_ASSERT (jcontext_has_pending_exception ()); + jcontext_set_abort_flag (true); result = ECMA_VALUE_ERROR; goto error; } @@ -1112,7 +1153,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { case VM_OC_POP: { - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); ecma_free_value (*(--stack_top_p)); continue; } @@ -1229,21 +1270,506 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p; - JERRY_ASSERT (frame_ctx_p->lex_env_p == ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_func_p->u.function.scope_cp)); + JERRY_ASSERT (frame_ctx_p->lex_env_p == + ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, ext_func_p->u.function.scope_cp)); ecma_object_t *name_lex_env = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); ecma_op_create_immutable_binding (name_lex_env, ecma_get_string_from_value (right_value), left_value); - ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, name_lex_env); + ECMA_SET_NON_NULL_POINTER_TAG (ext_func_p->u.function.scope_cp, name_lex_env, 0); ecma_free_value (right_value); ecma_deref_object (name_lex_env); *stack_top_p++ = left_value; continue; } -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + case VM_OC_CREATE_BINDING: + { +#if !ENABLED (JERRY_ES2015) + JERRY_ASSERT (opcode == CBC_CREATE_VAR); +#endif /* !ENABLED (JERRY_ES2015) */ + + uint32_t literal_index; + + READ_LITERAL_INDEX (literal_index); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL); + + uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; + +#if ENABLED (JERRY_ES2015) + if (opcode == CBC_CREATE_LET) + { + prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE; + } + else if (opcode == CBC_CREATE_CONST) + { + prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE; + } + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL); + + if (opcode != CBC_CREATE_VAR) + { + property_value_p->value = ECMA_VALUE_UNINITIALIZED; + } +#else /* !ENABLED (JERRY_ES2015) */ + ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL); +#endif /* ENABLED (JERRY_ES2015) */ + + continue; + } + case VM_OC_VAR_EVAL: + { + uint32_t literal_index; + ecma_value_t lit_value = ECMA_VALUE_UNDEFINED; + + if (opcode == CBC_CREATE_VAR_FUNC_EVAL) + { + uint32_t value_index; + READ_LITERAL_INDEX (value_index); + JERRY_ASSERT (value_index >= const_literal_end); + + lit_value = vm_construct_literal_object (frame_ctx_p, + literal_start_p[value_index]); + } + + READ_LITERAL_INDEX (literal_index); + JERRY_ASSERT (literal_index >= register_end); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + + while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { +#if ENABLED (JERRY_ES2015) && !(defined JERRY_NDEBUG) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE)); + } +#endif /* ENABLED (JERRY_ES2015) && !JERRY_NDEBUG */ + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + +#if ENABLED (JERRY_ES2015) && !(defined JERRY_NDEBUG) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE)); + } +#endif /* ENABLED (JERRY_ES2015) && !JERRY_NDEBUG */ + + result = vm_var_decl (lex_env_p, name_p, frame_ctx_p->is_eval_code); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + if (lit_value != ECMA_VALUE_UNDEFINED) + { + result = vm_set_var (lex_env_p, name_p, is_strict, lit_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + } + + continue; + } +#if ENABLED (JERRY_ES2015) + case VM_OC_EXT_VAR_EVAL: + { + uint32_t literal_index; + ecma_value_t lit_value = ECMA_VALUE_UNDEFINED; + + JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); + + if (opcode == CBC_EXT_CREATE_VAR_FUNC_EVAL) + { + uint32_t value_index; + READ_LITERAL_INDEX (value_index); + JERRY_ASSERT (value_index >= const_literal_end); + + lit_value = vm_construct_literal_object (frame_ctx_p, + literal_start_p[value_index]); + } + + READ_LITERAL_INDEX (literal_index); + JERRY_ASSERT (literal_index >= register_end); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + ecma_object_t *prev_lex_env_p = NULL; + + while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { +#if !(defined JERRY_NDEBUG) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE)); + } +#endif /* !JERRY_NDEBUG */ + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + prev_lex_env_p = lex_env_p; + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (prev_lex_env_p != NULL + && ecma_get_lex_env_type (prev_lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + ecma_property_t *property_p = ecma_find_named_property (prev_lex_env_p, name_p); + ecma_property_value_t *property_value_p; + + if (property_p == NULL) + { + property_value_p = ecma_create_named_data_property (prev_lex_env_p, + name_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + + if (lit_value == ECMA_VALUE_UNDEFINED) + { + continue; + } + } + else + { + if (lit_value == ECMA_VALUE_UNDEFINED) + { + continue; + } + + property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + ecma_free_value_if_not_object (property_value_p->value); + } + + property_value_p->value = lit_value; + ecma_deref_object (ecma_get_object_from_value (lit_value)); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_SNAPSHOT_EXEC) + case VM_OC_SET_BYTECODE_PTR: + { + memcpy (&byte_code_p, byte_code_p++, sizeof (uint8_t *)); + frame_ctx_p->byte_code_start_p = byte_code_p; + continue; + } +#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ + case VM_OC_INIT_ARG_OR_FUNC: + { + uint32_t literal_index, value_index; + ecma_value_t lit_value; + + READ_LITERAL_INDEX (value_index); + READ_LITERAL_INDEX (literal_index); + + JERRY_ASSERT (value_index != literal_index); + JERRY_ASSERT (value_index >= register_end || literal_index >= register_end); + + if (value_index < register_end) + { + /* Take (not copy) the reference. */ + lit_value = ecma_copy_value_if_not_object (VM_GET_REGISTER (frame_ctx_p, value_index)); + } + else + { + lit_value = vm_construct_literal_object (frame_ctx_p, + literal_start_p[value_index]); + } + + if (literal_index < register_end) + { + ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); + VM_GET_REGISTER (frame_ctx_p, literal_index) = lit_value; + continue; + } + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL); + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, + name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + + JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); + property_value_p->value = lit_value; + +#if defined(JERRY_FUNCTION_NAME) && !defined(__APPLE__) + if (ecma_is_value_object(lit_value)) { + ecma_object_t* obj = ecma_get_object_from_value(lit_value); + ecma_object_type_t obj_type = ecma_get_object_type(obj); + if (obj_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION || obj_type == ECMA_OBJECT_TYPE_FUNCTION) { + ecma_string_t* property_name = ecma_get_magic_string (LIT_MAGIC_STRING_NAME); + ecma_property_value_t* prop_val = ecma_create_named_data_property(obj, property_name, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); + prop_val->value = ecma_copy_value(literal_start_p[literal_index]); + } + } +#endif + + if (value_index >= register_end) + { + ecma_free_value (lit_value); + } + + continue; + } +#if ENABLED (JERRY_ES2015) + case VM_OC_CHECK_VAR: + { + JERRY_ASSERT (ecma_get_global_scope () == frame_ctx_p->lex_env_p); + + uint32_t literal_index; + READ_LITERAL_INDEX (literal_index); + + if ((frame_ctx_p->lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) == 0) + { + continue; + } + + ecma_string_t *const literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_property_t *const binding_p = ecma_find_named_property (frame_ctx_p->lex_env_p, literal_name_p); + + if (binding_p != NULL) + { + result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared.")); + goto error; + } + + continue; + } + case VM_OC_CHECK_LET: + { + JERRY_ASSERT (ecma_get_global_scope () == frame_ctx_p->lex_env_p); + + uint32_t literal_index; + READ_LITERAL_INDEX (literal_index); + + ecma_string_t *literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + ecma_property_t *binding_p = NULL; + + if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { + binding_p = ecma_find_named_property (lex_env_p, literal_name_p); + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + + if (binding_p != NULL) + { + result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared.")); + goto error; + } + + result = ecma_op_has_binding (lex_env_p, literal_name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (result)) + { + result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared.")); + goto error; + } + + continue; + } + case VM_OC_ASSIGN_LET_CONST: + { + uint32_t literal_index; + READ_LITERAL_INDEX (literal_index); + + JERRY_ASSERT (literal_index >= register_end); + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_property_t *property_p = ecma_find_named_property (frame_ctx_p->lex_env_p, name_p); + + JERRY_ASSERT (property_p != NULL + && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); + JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p)->value == ECMA_VALUE_UNINITIALIZED); + + ECMA_PROPERTY_VALUE_PTR (property_p)->value = left_value; + + if (ecma_is_value_object (left_value)) + { + ecma_deref_object (ecma_get_object_from_value (left_value)); + } + continue; + } + case VM_OC_INIT_BINDING: + { + uint32_t literal_index; + + READ_LITERAL_INDEX (literal_index); + + JERRY_ASSERT (literal_index >= register_end); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL); + + uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; + + if (opcode == CBC_INIT_LET) + { + prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE; + } + else if (opcode == CBC_INIT_CONST) + { + prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE; + } + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, + name_p, + prop_attributes, + NULL); + + JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); + + ecma_value_t value = *(--stack_top_p); + + property_value_p->value = value; + ecma_deref_if_object (value); + continue; + } + case VM_OC_THROW_CONST_ERROR: + { + result = ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned.")); + goto error; + } + case VM_OC_COPY_TO_GLOBAL: + { + uint32_t literal_index; + READ_LITERAL_INDEX (literal_index); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + + while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { +#ifndef JERRY_NDEBUG + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + JERRY_ASSERT (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE)); + } +#endif /* !JERRY_NDEBUG */ + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + ecma_property_value_t *prop_value_p; + + if (property_p == NULL) + { + prop_value_p = ecma_create_named_data_property (lex_env_p, + name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + } + else + { +#ifndef JERRY_NDEBUG + JERRY_ASSERT (!(*property_p & ECMA_PROPERTY_FLAG_ENUMERABLE)); +#endif /* !JERRY_NDEBUG */ + prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + } + + ecma_named_data_property_assign_value (lex_env_p, prop_value_p, left_value); + } + else + { + result = ecma_op_set_mutable_binding (lex_env_p, name_p, left_value, is_strict); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + } + + goto free_left_value; + } + case VM_OC_COPY_FROM_ARG: + { + uint32_t literal_index; + READ_LITERAL_INDEX (literal_index); + JERRY_ASSERT (literal_index >= register_end); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + ecma_object_t *arg_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + + JERRY_ASSERT ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + && ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (arg_lex_env_p != NULL + && !(arg_lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + && ecma_get_lex_env_type (arg_lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (lex_env_p, + name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + + ecma_property_t *property_p = ecma_find_named_property (arg_lex_env_p, name_p); + JERRY_ASSERT (property_p != NULL); + + ecma_property_value_t *arg_prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + property_value_p->value = ecma_copy_value_if_not_object (arg_prop_value_p->value); + continue; + } + case VM_OC_CLONE_CONTEXT: + { + JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); + + bool copy_values = (byte_code_start_p[1] == CBC_EXT_CLONE_FULL_CONTEXT); + frame_ctx_p->lex_env_p = ecma_clone_decl_lexical_environment (frame_ctx_p->lex_env_p, copy_values); + continue; + } + case VM_OC_SET__PROTO__: + { + result = ecma_builtin_object_object_set_proto (stack_top_p[-1], left_value); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + goto free_left_value; + } case VM_OC_SET_COMPUTED_PROPERTY: { /* Swap values. */ @@ -1252,7 +1778,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ left_value ^= right_value; /* FALLTHRU */ } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#endif /* ENABLED (JERRY_ES2015) */ case VM_OC_SET_PROPERTY: { JERRY_STATIC_ASSERT (VM_OC_NON_STATIC_FLAG == VM_OC_BACKWARD_BRANCH, @@ -1268,7 +1794,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ goto error; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE)) && !(opcode_data & VM_OC_NON_STATIC_FLAG)) { @@ -1277,14 +1803,13 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2; -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ const int index = -1; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[index]); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); ecma_property_t *property_p = ecma_find_named_property (object_p, prop_name_p); @@ -1344,7 +1869,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ goto error; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) if (JERRY_UNLIKELY (ecma_compare_ecma_string_to_magic_id (prop_name_p, LIT_MAGIC_STRING_PROTOTYPE)) && !(opcode_data & VM_OC_NON_STATIC_FLAG)) { @@ -1353,9 +1878,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } const int index = (int) (opcode_data >> VM_OC_NON_STATIC_SHIFT) - 2; -#else /* !ENABLED (JERRY_ES2015_CLASS) */ +#else /* !ENABLED (JERRY_ES2015) */ const int index = -1; -#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#endif /* ENABLED (JERRY_ES2015) */ opfunc_set_accessor (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_SET_GETTER, stack_top_p[index], @@ -1372,332 +1897,358 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = ecma_make_object_value (ecma_op_new_fast_array_object (0)); continue; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) + case VM_OC_LOCAL_EVAL: + { + ECMA_CLEAR_LOCAL_PARSE_OPTS (); + uint8_t parse_opts = *byte_code_p++; + ECMA_SET_LOCAL_PARSE_OPTS (parse_opts); + continue; + } case VM_OC_SUPER_CALL: { + uint8_t arguments_list_len = *byte_code_p++; + + if (opcode >= CBC_EXT_SPREAD_SUPER_CALL) + { + stack_top_p -= arguments_list_len; + ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len); + + if (JERRY_UNLIKELY (arguments_p == NULL)) + { + result = ECMA_VALUE_ERROR; + goto error; + } + + stack_top_p++; + ECMA_SET_INTERNAL_VALUE_POINTER (stack_top_p[-1], arguments_p); + } + else + { + stack_top_p -= arguments_list_len; + } + frame_ctx_p->call_operation = VM_EXEC_SUPER_CALL; frame_ctx_p->byte_code_p = byte_code_start_p; frame_ctx_p->stack_top_p = stack_top_p; return ECMA_VALUE_UNDEFINED; } - case VM_OC_CLASS_HERITAGE: + case VM_OC_PUSH_CLASS_ENVIRONMENT: { - ecma_value_t super_value = *(--stack_top_p); - ecma_object_t *super_class_p; - branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); + opfunc_push_class_environment (frame_ctx_p, &stack_top_p, left_value); + goto free_left_value; + } + case VM_OC_PUSH_IMPLICIT_CTOR: + { + *stack_top_p++ = opfunc_create_implicit_class_constructor (opcode); + continue; + } + case VM_OC_INIT_CLASS: + { + result = opfunc_init_class (frame_ctx_p, stack_top_p); - if (ecma_is_value_null (super_value)) + if (ECMA_IS_VALUE_ERROR (result)) { - super_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), - 0, - ECMA_OBJECT_TYPE_GENERAL); + goto error; } - else + continue; + } + case VM_OC_FINALIZE_CLASS: + { + opfunc_finalize_class (frame_ctx_p, &stack_top_p, left_value); + goto free_left_value; + } + case VM_OC_PUSH_SUPER_CONSTRUCTOR: + { + result = ecma_op_function_get_super_constructor (JERRY_CONTEXT (current_function_obj_p)); + + if (ECMA_IS_VALUE_ERROR (result)) { - result = ecma_op_to_object (super_value); - ecma_free_value (super_value); + goto error; + } - if (ECMA_IS_VALUE_ERROR (result) || !ecma_is_constructor (result)) + *stack_top_p++ = result; + continue; + } + case VM_OC_RESOLVE_LEXICAL_THIS: + { + result = ecma_op_get_this_binding (frame_ctx_p->lex_env_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + *stack_top_p++ = result; + continue; + } + case VM_OC_SUPER_REFERENCE: + { + result = opfunc_form_super_reference (&stack_top_p, frame_ctx_p, left_value, opcode); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + goto free_left_value; + } + case VM_OC_PUSH_SPREAD_ELEMENT: + { + *stack_top_p++ = ECMA_VALUE_SPREAD_ELEMENT; + continue; + } + case VM_OC_GET_ITERATOR: + { + result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_EMPTY); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + *stack_top_p++ = result; + continue; + } + case VM_OC_ITERATOR_STEP: + { + JERRY_ASSERT (opcode >= CBC_EXT_ITERATOR_STEP && opcode <= CBC_EXT_ITERATOR_STEP_3); + const uint8_t index = (uint8_t) (1 + (opcode - CBC_EXT_ITERATOR_STEP)); + result = ecma_op_iterator_step (stack_top_p[-index]); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + ecma_value_t value = ECMA_VALUE_UNDEFINED; + + if (!ecma_is_value_false (result)) + { + value = ecma_op_iterator_value (result); + ecma_free_value (result); + + if (ECMA_IS_VALUE_ERROR (value)) { - if (ECMA_IS_VALUE_ERROR (result)) - { - ecma_free_value (JERRY_CONTEXT (error_value)); - } - - ecma_free_value (result); - - result = ecma_raise_type_error ("Value provided by class extends is not an object or null."); + result = value; goto error; } - else - { - super_class_p = ecma_get_object_from_value (result); - } } - ecma_object_t *super_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, - super_class_p, - ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); - - ecma_deref_object (super_class_p); - - VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); - stack_top_p += PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION; - - stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_SUPER_CLASS, branch_offset); - - frame_ctx_p->lex_env_p = super_env_p; - + *stack_top_p++ = value; continue; } - case VM_OC_CLASS_INHERITANCE: + case VM_OC_ITERATOR_CLOSE: { - ecma_value_t child_value = stack_top_p[-2]; - ecma_value_t child_prototype_value = stack_top_p[-1]; + result = ecma_op_iterator_close (left_value); - ecma_object_t *child_class_p = ecma_get_object_from_value (child_value); - ecma_object_t *child_prototype_class_p = ecma_get_object_from_value (child_prototype_value); - - ecma_object_t *super_class_p = ecma_get_lex_env_binding_object (frame_ctx_p->lex_env_p); - - if (super_class_p->u2.prototype_cp != JMEM_CP_NULL) + if (ECMA_IS_VALUE_ERROR (result)) { - ecma_value_t super_prototype_value = ecma_op_object_get_by_magic_id (super_class_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (super_prototype_value)) - { - result = super_prototype_value; - goto error; - } - - if (ecma_get_object_type (super_class_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION - && !ecma_is_value_object (super_prototype_value)) - { - ecma_free_value (super_prototype_value); - result = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value does not have valid " - "prototype property.")); - goto error; - } - if (!(ECMA_IS_VALUE_ERROR (super_prototype_value) || !ecma_is_value_object (super_prototype_value))) - { - ecma_object_t *super_prototype_class_p = ecma_get_object_from_value (super_prototype_value); - - ECMA_SET_NON_NULL_POINTER (child_prototype_class_p->u2.prototype_cp, super_prototype_class_p); - ECMA_SET_NON_NULL_POINTER (child_class_p->u2.prototype_cp, super_class_p); - - } - ecma_free_value (super_prototype_value); + goto error; } + goto free_left_value; + } + case VM_OC_DEFAULT_INITIALIZER: + { + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); + + if (stack_top_p[-1] != ECMA_VALUE_UNDEFINED) + { + byte_code_p = byte_code_start_p + branch_offset; + continue; + } + + stack_top_p--; continue; } - case VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE: + case VM_OC_REST_INITIALIZER: { - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + JERRY_ASSERT (opcode >= CBC_EXT_REST_INITIALIZER && opcode <= CBC_EXT_REST_INITIALIZER_3); + const uint8_t iterator_index = (uint8_t) (1 + (opcode - CBC_EXT_REST_INITIALIZER)); + ecma_object_t *array_p = ecma_op_new_fast_array_object (0); + ecma_value_t iterator = stack_top_p[-iterator_index]; + uint32_t index = 0; - ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + while (true) + { + result = ecma_op_iterator_step (iterator); - ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p; - ext_func_obj_p->u.external_handler_cb = ecma_op_function_implicit_constructor_handler_cb; + if (ECMA_IS_VALUE_ERROR (result)) + { + ecma_deref_object (array_p); + goto error; + } - ecma_value_t function_obj_value = ecma_make_object_value (function_obj_p); - *stack_top_p++ = function_obj_value; + if (ecma_is_value_false (result)) + { + break; + } - ecma_object_t *prototype_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), - 0, - ECMA_OBJECT_TYPE_GENERAL); - *stack_top_p++ = ecma_make_object_value (prototype_class_p); + ecma_value_t value = ecma_op_iterator_value (result); + ecma_free_value (result); - /* 14.5.14.18 Set constructor to prototype */ - ecma_property_value_t *prop_value_p; - prop_value_p = ecma_create_named_data_property (prototype_class_p, - ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), - ECMA_PROPERTY_CONFIGURABLE_WRITABLE, - NULL); - ecma_named_data_property_assign_value (prototype_class_p, prop_value_p, function_obj_value); + if (ECMA_IS_VALUE_ERROR (value)) + { + ecma_deref_object (array_p); + result = value; + goto error; + } + bool set_result = ecma_fast_array_set_property (array_p, index++, value); + JERRY_ASSERT (set_result); + ecma_free_value (value); + } + + *stack_top_p++ = ecma_make_object_value (array_p); continue; } - case VM_OC_SET_CLASS_CONSTRUCTOR: + case VM_OC_INITIALIZER_PUSH_PROP: { - ecma_object_t *new_constructor_obj_p = ecma_get_object_from_value (left_value); - ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]); + result = vm_op_get_value (stack_top_p[-1], left_value); - ecma_extended_object_t *new_ext_func_obj_p = (ecma_extended_object_t *) new_constructor_obj_p; - ecma_extended_object_t *current_ext_func_obj_p = (ecma_extended_object_t *) current_constructor_obj_p; + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } - uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs; - const int new_type = ECMA_OBJECT_TYPE_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; - current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type); - - ecma_compiled_code_t *bytecode_p; - bytecode_p = (ecma_compiled_code_t *) ecma_op_function_get_compiled_code (new_ext_func_obj_p); - bytecode_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR; - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p); - ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.bytecode_cp, - bytecode_p); - ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.scope_cp, - ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_object_t, - new_ext_func_obj_p->u.function.scope_cp)); - ecma_deref_object (new_constructor_obj_p); - continue; + *stack_top_p++ = result; + goto free_left_value; } - case VM_OC_PUSH_IMPL_CONSTRUCTOR: + case VM_OC_SPREAD_ARGUMENTS: { - ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]); + uint8_t arguments_list_len = *byte_code_p++; + stack_top_p -= arguments_list_len; - uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs; - const int new_type = ECMA_OBJECT_TYPE_BOUND_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; - current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type); + ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len); - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) current_constructor_obj_p; - ecma_object_t *super_obj_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - - ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, - super_obj_p); - ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_IMPLICIT_CONSTRUCTOR; - - continue; - } - case VM_OC_CLASS_EXPR_CONTEXT_END: - { - JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_SUPER_CLASS); - stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p - 1); + if (JERRY_UNLIKELY (arguments_p == NULL)) + { + result = ECMA_VALUE_ERROR; + goto error; + } stack_top_p++; - stack_top_p[-1] = *stack_top_p; - continue; + ECMA_SET_INTERNAL_VALUE_POINTER (stack_top_p[-1], arguments_p); + + frame_ctx_p->call_operation = VM_EXEC_SPREAD_OP; + frame_ctx_p->byte_code_p = byte_code_start_p; + frame_ctx_p->stack_top_p = stack_top_p; + return ECMA_VALUE_UNDEFINED; } - case VM_OC_CLASS_EVAL: + case VM_OC_CREATE_GENERATOR: { - ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS (); - ECMA_SET_SUPER_EVAL_PARSER_OPTS (*byte_code_p++); - continue; - } - case VM_OC_PUSH_CONSTRUCTOR_SUPER: - { - JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); + frame_ctx_p->call_operation = VM_EXEC_RETURN; + frame_ctx_p->byte_code_p = byte_code_p; + frame_ctx_p->stack_top_p = stack_top_p; + result = opfunc_create_executable_object (frame_ctx_p); - bool is_super_called = ecma_op_is_super_called (frame_ctx_p->lex_env_p); - - if (byte_code_start_p[1] != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) + if (ECMA_IS_VALUE_ERROR (result)) { - /* Calling super(...) */ - if (is_super_called) - { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once.")); - - goto error; - } - } - else if (!is_super_called) - { - /* Reference to super.method or super["method"] */ - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " - "accessing 'super'.")); goto error; } - /* FALLTHRU */ + return result; } - case VM_OC_PUSH_SUPER: + case VM_OC_YIELD: + { + frame_ctx_p->call_operation = VM_EXEC_RETURN; + frame_ctx_p->byte_code_p = byte_code_p; + frame_ctx_p->stack_top_p = --stack_top_p; + return *stack_top_p; + } + case VM_OC_AWAIT: { - JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); - - if (byte_code_start_p[1] == CBC_EXT_PUSH_SUPER - || byte_code_start_p[1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) - { - ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - - ecma_value_t super_prototype = ecma_op_object_get_by_magic_id (super_class_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (super_prototype)) - { - result = super_prototype; - goto error; - } - - *stack_top_p++ = super_prototype; - } - else - { - ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - ecma_ref_object (super_class_p); - *stack_top_p++ = ecma_make_object_value (super_class_p); - } - continue; } - case VM_OC_PUSH_CONSTRUCTOR_THIS: - { - if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p)) - { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " - "accessing 'this' or returning from it.")); - goto error; - } - - *stack_top_p++ = ecma_copy_value (ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p)); - continue; - } - case VM_OC_SUPER_PROP_REFERENCE: - { - /** - * In case of this VM_OC_SUPER_PROP_REFERENCE the previously pushed 'super' must be replaced - * with the current 'this' value to correctly access the properties. - */ - int index = -1; /* -1 in case of CBC_EXT_SUPER_PROP_ASSIGN */ - - if (JERRY_LIKELY (byte_code_start_p[1] == CBC_EXT_SUPER_PROP_CALL)) - { - cbc_opcode_t next_call_opcode = (cbc_opcode_t) byte_code_start_p[2]; - /* The next opcode must be a call opcode */ - JERRY_ASSERT (CBC_CALL <= next_call_opcode && next_call_opcode <= CBC_CALL2_PROP_BLOCK); - - int arguments_list_len; - if (next_call_opcode >= CBC_CALL0) - { - /* CBC_CALL{0,1,2}* have their arg count encoded, extract it from there */ - arguments_list_len = (int) ((next_call_opcode - CBC_CALL0) / 6); - } - else - { - /** - * In this case the arguments are coded into the byte code stream as a byte argument - * following the call opcode. - */ - arguments_list_len = (int) byte_code_start_p[3]; - } - /* The old 'super' value is at least '-3' element away from the current position on the stack. */ - index = -3 - arguments_list_len; - } - else - { - /** - * The bytecode order for super assignment should be one of this: - * - CBC_EXT_PUSH_SUPER, CBC_EXT_SUPER_PROP_ASSIGN. - * - CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_EXT_SUPER_PROP_ASSIGN. - * That is one ext opcode back (-1). - */ - JERRY_ASSERT (byte_code_start_p[-1] == CBC_EXT_PUSH_SUPER - || byte_code_start_p[-1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP); - } - - /* Replace the old 'super' value with the correct 'this' binding */ - ecma_free_value (stack_top_p[index]); - stack_top_p[index] = ecma_copy_value (frame_ctx_p->this_binding); - continue; - } - case VM_OC_CONSTRUCTOR_RET: + case VM_OC_EXT_RETURN: { result = left_value; left_value = ECMA_VALUE_UNDEFINED; - if (!ecma_is_value_object (result)) + ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; + + while (stack_top_p > stack_bottom_p) { - if (ecma_is_value_undefined (result)) - { - if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p)) - { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class " - "before returning from derived constructor")); - } - } - else - { - ecma_free_value (result); - result = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only " - "return object or undefined.")); - } + ecma_fast_free_value (*(--stack_top_p)); } goto error; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + case VM_OC_RETURN_PROMISE: + { + result = opfunc_return_promise (left_value); + left_value = ECMA_VALUE_UNDEFINED; + goto error; + } + case VM_OC_STRING_CONCAT: + { + ecma_string_t *left_str_p = ecma_op_to_string (left_value); + + if (JERRY_UNLIKELY (left_str_p == NULL)) + { + result = ECMA_VALUE_ERROR; + goto error; + } + ecma_string_t *right_str_p = ecma_op_to_string (right_value); + + if (JERRY_UNLIKELY (right_str_p == NULL)) + { + ecma_deref_ecma_string (left_str_p); + result = ECMA_VALUE_ERROR; + goto error; + } + + ecma_string_t *result_str_p = ecma_concat_ecma_strings (left_str_p, right_str_p); + ecma_deref_ecma_string (right_str_p); + + *stack_top_p++ = ecma_make_string_value (result_str_p); + goto free_both_values; + } + case VM_OC_GET_TEMPLATE_OBJECT: + { + uint8_t tagged_idx = *byte_code_p++; + ecma_collection_t *collection_p = ecma_compiled_code_get_tagged_template_collection (bytecode_header_p); + JERRY_ASSERT (tagged_idx < collection_p->item_count); + + *stack_top_p++ = ecma_copy_value (collection_p->buffer_p[tagged_idx]); + continue; + } + case VM_OC_PUSH_NEW_TARGET: + { + ecma_object_t *new_target_object = JERRY_CONTEXT (current_new_target); + if (new_target_object == NULL) + { + *stack_top_p++ = ECMA_VALUE_UNDEFINED; + } + else + { + ecma_ref_object (new_target_object); + *stack_top_p++ = ecma_make_object_value (new_target_object); + } + continue; + } + case VM_OC_REQUIRE_OBJECT_COERCIBLE: + { + result = ecma_op_check_object_coercible (stack_top_p[-1]); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + continue; + } + case VM_OC_ASSIGN_SUPER: + { + result = opfunc_assign_super_reference (&stack_top_p, frame_ctx_p, opcode_data); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ case VM_OC_PUSH_ELISON: { *stack_top_p++ = ECMA_VALUE_ARRAY_HOLE; @@ -1705,74 +2256,25 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_APPEND_ARRAY: { - ecma_object_t *array_obj_p; - uint32_t values_length = *byte_code_p++; - + uint16_t values_length = *byte_code_p++; stack_top_p -= values_length; - array_obj_p = ecma_get_object_from_value (stack_top_p[-1]); - ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; - uint32_t old_length = ext_array_obj_p->u.array.length; - - if (JERRY_LIKELY (ext_array_obj_p->u.array.is_fast_mode)) +#if ENABLED (JERRY_ES2015) + if (*byte_code_start_p == CBC_EXT_OPCODE) { - ecma_value_t *values_p = ecma_fast_array_extend (array_obj_p, old_length + values_length); - - for (uint32_t i = 0; i < values_length; i++) - { - values_p[old_length + i] = stack_top_p[i]; - - if (JERRY_UNLIKELY (ecma_is_value_array_hole (stack_top_p[i]))) - { - ext_array_obj_p->u.array.hole_count++; - } - else if (ecma_is_value_object (stack_top_p[i])) - { - ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); - } - } - - if (JERRY_UNLIKELY (ext_array_obj_p->u.array.length > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) - { - ecma_fast_array_convert_to_normal (array_obj_p); - } + values_length = (uint16_t) (values_length | OPFUNC_HAS_SPREAD_ELEMENT); } - else +#endif /* ENABLED (JERRY_ES2015) */ + result = opfunc_append_array (stack_top_p, values_length); + +#if ENABLED (JERRY_ES2015) + if (ECMA_IS_VALUE_ERROR (result)) { - for (uint32_t i = 0; i < values_length; i++) - { - if (!ecma_is_value_array_hole (stack_top_p[i])) - { - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (old_length + i); - - ecma_property_value_t *prop_value_p; - - prop_value_p = ecma_create_named_data_property (array_obj_p, - index_str_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - - ecma_deref_ecma_string (index_str_p); - prop_value_p->value = stack_top_p[i]; - - if (ecma_is_value_object (stack_top_p[i])) - { - ecma_free_value (stack_top_p[i]); - } - - } - } - - ext_array_obj_p->u.array.length = old_length + values_length; + goto error; } - - continue; - } - case VM_OC_PUSH_UNDEFINED_BASE: - { - stack_top_p[0] = stack_top_p[-1]; - stack_top_p[-1] = ECMA_VALUE_UNDEFINED; - stack_top_p++; +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (ecma_is_value_empty (result)); +#endif /* ENABLED (JERRY_ES2015) */ continue; } case VM_OC_IDENT_REFERENCE: @@ -1786,8 +2288,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (literal_index < register_end) { *stack_top_p++ = ECMA_VALUE_REGISTER_REF; - *stack_top_p++ = literal_index; - *stack_top_p++ = ecma_fast_copy_value (frame_ctx_p->registers_p[literal_index]); + *stack_top_p++ = ecma_make_integer_value (literal_index); + *stack_top_p++ = ecma_fast_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); } else { @@ -1933,7 +2435,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p[-2] = stack_top_p[-3]; stack_top_p[-3] = result; } - opcode_data &= (uint32_t)~VM_OC_PUT_STACK; + opcode_data &= (uint32_t) ~VM_OC_PUT_STACK; } else if (opcode_data & VM_OC_PUT_BLOCK) { @@ -1996,7 +2498,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p[-2] = stack_top_p[-3]; stack_top_p[-3] = ecma_copy_value (result); } - opcode_data &= (uint32_t)~VM_OC_PUT_STACK; + opcode_data &= (uint32_t) ~VM_OC_PUT_STACK; } else if (opcode_data & VM_OC_PUT_BLOCK) { @@ -2041,15 +2543,15 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_MOV_IDENT: { - uint16_t literal_index; + uint32_t literal_index; READ_LITERAL_INDEX (literal_index); JERRY_ASSERT (literal_index < register_end); JERRY_ASSERT (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))); - ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]); - frame_ctx_p->registers_p[literal_index] = left_value; + ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); + VM_GET_REGISTER (frame_ctx_p, literal_index) = left_value; continue; } case VM_OC_ASSIGN_PROP: @@ -2101,7 +2603,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ left_value = ECMA_VALUE_UNDEFINED; break; } - case VM_OC_RET: + case VM_OC_RETURN: { JERRY_ASSERT (opcode == CBC_RETURN || opcode == CBC_RETURN_WITH_BLOCK @@ -2119,8 +2621,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_THROW: { - JERRY_CONTEXT (error_value) = left_value; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (left_value); result = ECMA_VALUE_ERROR; left_value = ECMA_VALUE_UNDEFINED; @@ -2134,7 +2635,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_EVAL: { JERRY_CONTEXT (status_flags) |= ECMA_STATUS_DIRECT_EVAL; - JERRY_ASSERT (*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK); + JERRY_ASSERT ((*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK) + || (*byte_code_p == CBC_EXT_OPCODE + && byte_code_p[1] >= CBC_EXT_SPREAD_CALL + && byte_code_p[1] <= CBC_EXT_SPREAD_CALL_PROP_BLOCK)); continue; } case VM_OC_CALL: @@ -2227,7 +2731,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { ecma_value_t value = *(--stack_top_p); - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + JERRY_ASSERT (stack_top_p > VM_GET_REGISTERS (frame_ctx_p) + register_end); if (ecma_op_strict_equality_compare (value, stack_top_p[-1])) { @@ -2323,7 +2827,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (literal_index < register_end) { - left_value = ecma_copy_value (frame_ctx_p->registers_p[literal_index]); + left_value = ecma_copy_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); } else { @@ -2337,7 +2841,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (ref_base_lex_env_p == NULL) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); result = ECMA_VALUE_UNDEFINED; } else if (ECMA_IS_VALUE_ERROR (result)) @@ -2440,7 +2944,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } - result = do_number_arithmetic (NUMBER_ARITHMETIC_SUBSTRACTION, + result = do_number_arithmetic (NUMBER_ARITHMETIC_SUBTRACTION, left_value, right_value); @@ -2566,6 +3070,22 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = result; goto free_both_values; } +#if ENABLED (JERRY_ES2015) + case VM_OC_EXP: + { + result = do_number_arithmetic (NUMBER_ARITHMETIC_EXPONENTIATION, + left_value, + right_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + *stack_top_p++ = result; + goto free_both_values; + } +#endif /* ENABLED (JERRY_ES2015) */ case VM_OC_EQUAL: { result = opfunc_equality (left_value, right_value); @@ -2929,6 +3449,55 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = result; goto free_both_values; } + case VM_OC_BLOCK_CREATE_CONTEXT: + { +#if ENABLED (JERRY_ES2015) + ecma_value_t *stack_context_top_p; + stack_context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; + + JERRY_ASSERT (stack_context_top_p == stack_top_p || stack_context_top_p == stack_top_p - 1); + + if (byte_code_start_p[0] != CBC_EXT_OPCODE) + { + branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); + + if (stack_context_top_p != stack_top_p) + { + /* Preserve the value of switch statement. */ + stack_context_top_p[1] = stack_context_top_p[0]; + } + + stack_context_top_p[0] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_BLOCK, branch_offset); + + VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); + stack_top_p += PARSER_BLOCK_CONTEXT_STACK_ALLOCATION; + } + else + { + JERRY_ASSERT (byte_code_start_p[1] == CBC_EXT_TRY_CREATE_ENV); + + JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_TRY + || VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_CATCH + || VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP + || VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_THROW + || VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN); + + JERRY_ASSERT (!(stack_context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)); + + stack_context_top_p[-1] |= VM_CONTEXT_HAS_LEX_ENV; + } +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_CATCH + && !(stack_top_p[-2] & VM_CONTEXT_HAS_LEX_ENV)); + + stack_top_p[-2] |= VM_CONTEXT_HAS_LEX_ENV; +#endif /* ENABLED (JERRY_ES2015) */ + + frame_ctx_p->lex_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); + frame_ctx_p->lex_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK; + + continue; + } case VM_OC_WITH: { ecma_value_t value = *(--stack_top_p); @@ -2937,7 +3506,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); result = ecma_op_to_object (value); ecma_free_value (value); @@ -2957,8 +3526,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_WITH_CONTEXT_STACK_ALLOCATION; - stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_WITH, branch_offset); + stack_top_p[-1] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_WITH, branch_offset); + with_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK; frame_ctx_p->lex_env_p = with_env_p; continue; } @@ -2966,7 +3536,22 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { ecma_value_t value = *(--stack_top_p); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_object (value) + && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value))) + { + /* Note: - For proxy objects we should create a new object which implements the iterable protocol, + and iterates through the enumerated collection below. + - This inkoves that the VM context type should be adjusted and checked in all FOR-IN related + instruction. + - For other objects we should keep the current implementation due to performance reasons.*/ + result = ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy support in for-in.")); + ecma_free_value (value); + goto error; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_value_t expr_obj_value = ECMA_VALUE_UNDEFINED; ecma_collection_t *prop_names_p = opfunc_for_in (value, &expr_obj_value); @@ -2983,16 +3568,23 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; - stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset); + stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset); ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], prop_names_p); stack_top_p[-3] = 0; stack_top_p[-4] = expr_obj_value; +#if ENABLED (JERRY_ES2015) + if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT) + { + /* No need to duplicate the first context. */ + byte_code_p += 2; + } +#endif /* ENABLED (JERRY_ES2015) */ continue; } case VM_OC_FOR_IN_GET_NEXT: { - ecma_value_t *context_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; + ecma_value_t *context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; ecma_collection_t *collection_p; collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, context_top_p[-2]); @@ -3008,7 +3600,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_FOR_IN_HAS_NEXT: { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); ecma_collection_t *collection_p; collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, stack_top_p[-2]); @@ -3018,12 +3610,17 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t *buffer_p = collection_p->buffer_p; ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-4]); uint32_t index = stack_top_p[-3]; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ while (index < collection_p->item_count) { ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[index]); - if (JERRY_LIKELY (ecma_op_object_has_property (object_p, prop_name_p))) + result = ecma_op_object_has_property (object_p, prop_name_p); + + if (JERRY_LIKELY (ecma_is_value_true (result))) { byte_code_p = byte_code_start_p + branch_offset; break; @@ -3046,12 +3643,12 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } continue; } -#if ENABLED (JERRY_ES2015_FOR_OF) +#if ENABLED (JERRY_ES2015) case VM_OC_FOR_OF_CREATE_CONTEXT: { ecma_value_t value = *(--stack_top_p); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_EMPTY); @@ -3063,16 +3660,16 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ goto error; } - ecma_value_t iterator_step = ecma_op_iterator_step (iterator); + ecma_value_t next_value = ecma_op_iterator_step (iterator); - if (ECMA_IS_VALUE_ERROR (iterator_step)) + if (ECMA_IS_VALUE_ERROR (next_value)) { ecma_free_value (iterator); - result = iterator_step; + result = next_value; goto error; } - if (ecma_is_value_false (iterator_step)) + if (ecma_is_value_false (next_value)) { ecma_free_value (iterator); byte_code_p = byte_code_start_p + branch_offset; @@ -3083,15 +3680,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION; - stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_OF, branch_offset); - stack_top_p[-2] = iterator_step; + stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_OF, branch_offset) | VM_CONTEXT_CLOSE_ITERATOR; + stack_top_p[-2] = next_value; stack_top_p[-3] = iterator; + if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT) + { + /* No need to duplicate the first context. */ + byte_code_p += 2; + } continue; } case VM_OC_FOR_OF_GET_NEXT: { - ecma_value_t *context_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; + ecma_value_t *context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_OF); ecma_value_t next_value = ecma_op_iterator_value (context_top_p[-2]); @@ -3107,20 +3709,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_FOR_OF_HAS_NEXT: { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); - ecma_value_t iterator_step = ecma_op_iterator_step (stack_top_p[-3]); + ecma_value_t next_value = ecma_op_iterator_step (stack_top_p[-3]); - if (ECMA_IS_VALUE_ERROR (iterator_step)) + if (ECMA_IS_VALUE_ERROR (next_value)) { - result = iterator_step; + result = next_value; goto error; } - if (!ecma_is_value_false (iterator_step)) + if (!ecma_is_value_false (next_value)) { ecma_free_value (stack_top_p[-2]); - stack_top_p[-2] = iterator_step; + stack_top_p[-2] = next_value; byte_code_p = byte_code_start_p + branch_offset; continue; } @@ -3129,27 +3731,26 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_free_value (stack_top_p[-3]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); stack_top_p -= PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION; - continue; } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +#endif /* ENABLED (JERRY_ES2015) */ case VM_OC_TRY: { /* Try opcode simply creates the try context. */ branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_TRY_CONTEXT_STACK_ALLOCATION; - stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset); + stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset); continue; } case VM_OC_CATCH: { /* Catches are ignored and turned to jumps. */ - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY); byte_code_p = byte_code_start_p + branch_offset; @@ -3159,88 +3760,96 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY || VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH); - if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH) + if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) + { + ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + ecma_deref_object (lex_env_p); + + stack_top_p[-1] &= (ecma_value_t) ~VM_CONTEXT_HAS_LEX_ENV; + } + + stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset); + stack_top_p[-2] = (ecma_value_t) branch_offset; + continue; + } + case VM_OC_CONTEXT_END: + { + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (!(stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR)); + + ecma_value_t context_type = VM_GET_CONTEXT_TYPE (stack_top_p[-1]); + + if (!VM_CONTEXT_IS_FINALLY (context_type)) + { + stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p); + + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + continue; + } + +#if ENABLED (JERRY_ES2015) + if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) { ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); ecma_deref_object (lex_env_p); } +#endif /* ENABLED (JERRY_ES2015) */ - stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset); - stack_top_p[-2] = (ecma_value_t) branch_offset; - continue; - } - case VM_OC_CONTEXT_END: - { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, + PARSER_TRY_CONTEXT_STACK_ALLOCATION); + stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; - switch (VM_GET_CONTEXT_TYPE (stack_top_p[-1])) + if (context_type == VM_CONTEXT_FINALLY_RETURN) { - case VM_CONTEXT_FINALLY_JUMP: - { - uint32_t jump_target = stack_top_p[-2]; - - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, - PARSER_TRY_CONTEXT_STACK_ALLOCATION); - stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; - - if (vm_stack_find_finally (frame_ctx_p, - &stack_top_p, - VM_CONTEXT_FINALLY_JUMP, - jump_target)) - { - JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP); - byte_code_p = frame_ctx_p->byte_code_p; - stack_top_p[-2] = jump_target; - } - else - { - byte_code_p = frame_ctx_p->byte_code_start_p + jump_target; - } - break; - } - case VM_CONTEXT_FINALLY_THROW: - { - JERRY_CONTEXT (error_value) = stack_top_p[-2]; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, - PARSER_TRY_CONTEXT_STACK_ALLOCATION); - stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; - result = ECMA_VALUE_ERROR; - -#if ENABLED (JERRY_DEBUGGER) - JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); -#endif /* ENABLED (JERRY_DEBUGGER) */ - goto error; - } - case VM_CONTEXT_FINALLY_RETURN: - { - result = stack_top_p[-2]; - - VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, - PARSER_TRY_CONTEXT_STACK_ALLOCATION); - stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; - goto error; - } - default: - { - stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p); - } + result = *stack_top_p; + goto error; } - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + if (context_type == VM_CONTEXT_FINALLY_THROW) + { + jcontext_raise_exception (*stack_top_p); + result = ECMA_VALUE_ERROR; + +#if ENABLED (JERRY_DEBUGGER) + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); +#endif /* ENABLED (JERRY_DEBUGGER) */ + goto error; + } + + JERRY_ASSERT (context_type == VM_CONTEXT_FINALLY_JUMP); + + uint32_t jump_target = *stack_top_p; + + if (vm_stack_find_finally (frame_ctx_p, + &stack_top_p, + VM_CONTEXT_FINALLY_JUMP, + jump_target)) + { + JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP); + byte_code_p = frame_ctx_p->byte_code_p; + stack_top_p[-2] = jump_target; + } + else + { + byte_code_p = frame_ctx_p->byte_code_start_p + jump_target; + } + + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); continue; } case VM_OC_JUMP_AND_EXIT_CONTEXT: { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (!jcontext_has_pending_exception ()); branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); @@ -3258,7 +3867,15 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ byte_code_p = frame_ctx_p->byte_code_start_p + branch_offset; } - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); +#if ENABLED (JERRY_ES2015) + if (jcontext_has_pending_exception ()) + { + result = ECMA_VALUE_ERROR; + goto error; + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); continue; } #if ENABLED (JERRY_DEBUGGER) @@ -3336,36 +3953,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } #endif /* ENABLED (JERRY_DEBUGGER) */ -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) case VM_OC_RESOURCE_NAME: { - ecma_length_t formal_params_number = 0; - - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_header_p)) - { - if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) - { - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; - - formal_params_number = args_p->argument_end; - } - else - { - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; - - formal_params_number = args_p->argument_end; - } - } - - uint8_t *byte_p = (uint8_t *) bytecode_header_p; - byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; - - ecma_value_t *resource_name_p = (ecma_value_t *) byte_p; - resource_name_p -= formal_params_number; - - frame_ctx_p->resource_name = resource_name_p[-1]; + frame_ctx_p->resource_name = ecma_op_resource_name (bytecode_header_p); continue; } +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) case VM_OC_LINE: { uint32_t value = 0; @@ -3382,6 +3977,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } #endif /* ENABLED (JERRY_LINE_INFO) */ + case VM_OC_NONE: default: { JERRY_ASSERT (VM_OC_GROUP_GET_INDEX (opcode_data) == VM_OC_NONE); @@ -3400,9 +3996,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (literal_index < register_end) { - ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]); - - frame_ctx_p->registers_p[literal_index] = result; + ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); + VM_GET_REGISTER (frame_ctx_p, literal_index) = result; if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)) { @@ -3452,13 +4047,13 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ else if (opcode_data & VM_OC_PUT_REFERENCE) { ecma_value_t property = *(--stack_top_p); - ecma_value_t object = *(--stack_top_p); + ecma_value_t base = *(--stack_top_p); - if (object == ECMA_VALUE_REGISTER_REF) + if (base == ECMA_VALUE_REGISTER_REF) { - ecma_fast_free_value (frame_ctx_p->registers_p[property]); - - frame_ctx_p->registers_p[property] = result; + property = (ecma_value_t) ecma_get_integer_from_value (property); + ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, property)); + VM_GET_REGISTER (frame_ctx_p, property) = result; if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) { @@ -3468,7 +4063,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_value_t set_value_result = vm_op_set_value (object, + ecma_value_t set_value_result = vm_op_set_value (base, property, result, is_strict); @@ -3503,31 +4098,29 @@ free_both_values: free_left_value: ecma_fast_free_value (left_value); } -error: +error: ecma_fast_free_value (left_value); ecma_fast_free_value (right_value); if (ECMA_IS_VALUE_ERROR (result)) { - ecma_value_t *vm_stack_p = stack_top_p; + JERRY_ASSERT (jcontext_has_pending_exception ()); + ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; - for (vm_stack_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; - vm_stack_p < stack_top_p; - vm_stack_p++) + while (stack_top_p > stack_bottom_p) { - if (*vm_stack_p == ECMA_VALUE_REGISTER_REF) + ecma_value_t stack_item = *(--stack_top_p); +#if ENABLED (JERRY_ES2015) + if (stack_item == ECMA_VALUE_RELEASE_LEX_ENV) { - JERRY_ASSERT (vm_stack_p < stack_top_p); - vm_stack_p++; - } - else - { - ecma_free_value (*vm_stack_p); + opfunc_pop_lexical_environment (frame_ctx_p); + continue; } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_fast_free_value (stack_item); } - stack_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; #if ENABLED (JERRY_DEBUGGER) const uint32_t dont_stop = (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE @@ -3542,7 +4135,7 @@ error: therefore an evaluation error, or user-created error throw would overwrite it. */ ecma_value_t current_error_value = JERRY_CONTEXT (error_value); - if (jerry_debugger_send_exception_string ()) + if (jerry_debugger_send_exception_string (current_error_value)) { jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT); @@ -3561,7 +4154,7 @@ error: #endif /* ENABLED (JERRY_DEBUGGER) */ } - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); if (frame_ctx_p->context_depth == 0) { @@ -3580,57 +4173,57 @@ error: 0)) { JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN); - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + +#if ENABLED (JERRY_ES2015) + if (jcontext_has_pending_exception ()) + { + stack_top_p[-1] = (ecma_value_t) (stack_top_p[-1] - VM_CONTEXT_FINALLY_RETURN + VM_CONTEXT_FINALLY_THROW); + ecma_free_value (result); + result = jcontext_take_exception (); + } +#endif /* ENABLED (JERRY_ES2015) */ byte_code_p = frame_ctx_p->byte_code_p; stack_top_p[-2] = result; continue; } + +#if ENABLED (JERRY_ES2015) + if (jcontext_has_pending_exception ()) + { + ecma_free_value (result); + result = ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015) */ } - else if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) + else if (jcontext_has_pending_exception () && !jcontext_has_pending_abort ()) { if (vm_stack_find_finally (frame_ctx_p, &stack_top_p, VM_CONTEXT_FINALLY_THROW, 0)) { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (!(stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)); #if ENABLED (JERRY_DEBUGGER) JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); #endif /* ENABLED (JERRY_DEBUGGER) */ + result = jcontext_take_exception (); + byte_code_p = frame_ctx_p->byte_code_p; - if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH) + if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW) { - *stack_top_p++ = JERRY_CONTEXT (error_value); - - JERRY_ASSERT (byte_code_p[0] == CBC_ASSIGN_SET_IDENT); - - uint32_t literal_index = byte_code_p[1]; - - if (literal_index >= encoding_limit) - { - literal_index = ((literal_index << 8) | byte_code_p[2]) - encoding_delta; - } - - ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); -#if ENABLED (JERRY_DEBUGGER) - catch_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE; -#endif /* ENABLED (JERRY_DEBUGGER) */ - - ecma_string_t *catch_name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - ecma_op_create_mutable_binding (catch_env_p, catch_name_p, false); - - frame_ctx_p->lex_env_p = catch_env_p; - } - else - { - JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW); - stack_top_p[-2] = JERRY_CONTEXT (error_value); + stack_top_p[-2] = result; + continue; } + JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH); + + *stack_top_p++ = result; continue; } } @@ -3638,7 +4231,7 @@ error: { do { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p); } @@ -3656,19 +4249,30 @@ error: #undef READ_LITERAL_INDEX /** - * Execute code block. + * Initialize code block execution * - * @return ecma value + * @return ECMA_VALUE_ERROR - if the initialization fails + * ECMA_VALUE_EMPTY - otherwise */ -static ecma_value_t JERRY_ATTR_NOINLINE -vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ - const ecma_value_t *arg_p, /**< arguments list */ - ecma_length_t arg_list_len) /**< length of arguments list */ +static void JERRY_ATTR_NOINLINE +vm_init_exec (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + const ecma_value_t *arg_p, /**< arguments list */ + ecma_length_t arg_list_len) /**< length of arguments list */ { + frame_ctx_p->prev_context_p = JERRY_CONTEXT (vm_top_context_p); + frame_ctx_p->block_result = ECMA_VALUE_UNDEFINED; +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) + frame_ctx_p->resource_name = ECMA_VALUE_UNDEFINED; +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) + frame_ctx_p->current_line = 0; +#endif /* ENABLED (JERRY_LINE_INFO) */ + frame_ctx_p->context_depth = 0; + frame_ctx_p->is_eval_code = (arg_p == VM_DIRECT_EVAL); + const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; - ecma_value_t completion_value; - uint16_t argument_end; - uint16_t register_end; + uint16_t argument_end, register_end; + ecma_value_t *literal_p; if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { @@ -3676,6 +4280,11 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ argument_end = args_p->argument_end; register_end = args_p->register_end; + + literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint16_arguments_t)); + literal_p -= register_end; + frame_ctx_p->literal_start_p = literal_p; + literal_p += args_p->literal_end; } else { @@ -3683,13 +4292,28 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ argument_end = args_p->argument_end; register_end = args_p->register_end; + + literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint8_arguments_t)); + literal_p -= register_end; + frame_ctx_p->literal_start_p = literal_p; + literal_p += args_p->literal_end; } - frame_ctx_p->stack_top_p = frame_ctx_p->registers_p + register_end; + frame_ctx_p->byte_code_p = (uint8_t *) literal_p; + frame_ctx_p->byte_code_start_p = (uint8_t *) literal_p; + frame_ctx_p->stack_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end; -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if defined(JERRY_FUNCTION_BACKTRACE) && !defined(__APPLE__) + if (JERRY_LIKELY(frame_ctx_p->prev_context_p != NULL)) { + frame_ctx_p->callee_value = frame_ctx_p->prev_context_p->callee_value; + } else { + frame_ctx_p->callee_value = ECMA_VALUE_UNDEFINED; + } +#endif + +#if ENABLED (JERRY_ES2015) uint32_t function_call_argument_count = arg_list_len; -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ if (arg_list_len > argument_end) { @@ -3698,14 +4322,14 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ for (uint32_t i = 0; i < arg_list_len; i++) { - frame_ctx_p->registers_p[i] = ecma_fast_copy_value (arg_p[i]); + VM_GET_REGISTER (frame_ctx_p, i) = ecma_fast_copy_value (arg_p[i]); } /* The arg_list_len contains the end of the copied arguments. * Fill everything else with undefined. */ if (register_end > arg_list_len) { - ecma_value_t *stack_p = frame_ctx_p->registers_p + arg_list_len; + ecma_value_t *stack_p = VM_GET_REGISTERS (frame_ctx_p) + arg_list_len; for (uint32_t i = arg_list_len; i < register_end; i++) { @@ -3713,7 +4337,7 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } } -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) +#if ENABLED (JERRY_ES2015) if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_REST_PARAMETER) { JERRY_ASSERT (function_call_argument_count >= arg_list_len); @@ -3721,21 +4345,25 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ function_call_argument_count - arg_list_len, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); - frame_ctx_p->registers_p[argument_end] = new_array; - arg_list_len++; + VM_GET_REGISTER (frame_ctx_p, argument_end) = new_array; } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ +#endif /* ENABLED (JERRY_ES2015) */ JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; - - vm_frame_ctx_t *prev_context_p = JERRY_CONTEXT (vm_top_context_p); JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p; +} /* vm_init_exec */ - vm_init_loop (frame_ctx_p); - +/** + * Resume execution of a code block. + * + * @return ecma value + */ +ecma_value_t JERRY_ATTR_NOINLINE +vm_execute (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ while (true) { - completion_value = vm_loop (frame_ctx_p); + ecma_value_t completion_value = vm_loop (frame_ctx_p); switch (frame_ctx_p->call_operation) { @@ -3744,13 +4372,22 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ opfunc_call (frame_ctx_p); break; } -#if ENABLED (JERRY_ES2015_CLASS) +#if ENABLED (JERRY_ES2015) case VM_EXEC_SUPER_CALL: { vm_super_call (frame_ctx_p); break; } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + case VM_EXEC_SPREAD_OP: + { + vm_spread_operation (frame_ctx_p); + break; + } + case VM_EXEC_RETURN: + { + return completion_value; + } +#endif /* ENABLED (JERRY_ES2015) */ case VM_EXEC_CONSTRUCT: { opfunc_construct (frame_ctx_p); @@ -3760,10 +4397,23 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ { JERRY_ASSERT (frame_ctx_p->call_operation == VM_NO_EXEC_OP); + const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; + uint32_t register_end; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + register_end = ((cbc_uint16_arguments_t *) bytecode_header_p)->register_end; + } + else + { + register_end = ((cbc_uint8_arguments_t *) bytecode_header_p)->register_end; + } + /* Free arguments and registers */ + ecma_value_t *registers_p = VM_GET_REGISTERS (frame_ctx_p); for (uint32_t i = 0; i < register_end; i++) { - ecma_fast_free_value (frame_ctx_p->registers_p[i]); + ecma_fast_free_value (registers_p[i]); } #if ENABLED (JERRY_DEBUGGER) @@ -3775,7 +4425,7 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ - JERRY_CONTEXT (vm_top_context_p) = prev_context_p; + JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p->prev_context_p; return completion_value; } } @@ -3791,13 +4441,11 @@ ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data header */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ - uint32_t parse_opts, /**< ecma_parse_opts_t option bits */ const ecma_value_t *arg_list_p, /**< arguments list */ ecma_length_t arg_list_len) /**< length of arguments list */ { - ecma_value_t *literal_p; - vm_frame_ctx_t frame_ctx; - uint32_t call_stack_size; + vm_frame_ctx_t *frame_ctx_p; + size_t frame_size; #if defined(JERRY_FOR_IAR_CONFIG) ecma_value_t* stack; ecma_value_t ret; @@ -3806,87 +4454,41 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; - call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); - - literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint16_arguments_t)); - literal_p -= args_p->register_end; - frame_ctx.literal_start_p = literal_p; - literal_p += args_p->literal_end; + frame_size = (size_t) (args_p->register_end + args_p->stack_limit); } else { cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; - call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); - - literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint8_arguments_t)); - literal_p -= args_p->register_end; - frame_ctx.literal_start_p = literal_p; - literal_p += args_p->literal_end; + frame_size = (size_t) (args_p->register_end + args_p->stack_limit); } - frame_ctx.bytecode_header_p = bytecode_header_p; - frame_ctx.byte_code_p = (uint8_t *) literal_p; - frame_ctx.byte_code_start_p = (uint8_t *) literal_p; - frame_ctx.lex_env_p = lex_env_p; -#if defined (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) - frame_ctx.prev_context_p = JERRY_CONTEXT (vm_top_context_p); -#endif /* defined (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) */ - frame_ctx.this_binding = this_binding_value; - frame_ctx.block_result = ECMA_VALUE_UNDEFINED; -#if ENABLED (JERRY_LINE_INFO) - frame_ctx.resource_name = ECMA_VALUE_UNDEFINED; - frame_ctx.current_line = 0; -#endif /* ENABLED (JERRY_LINE_INFO) */ - frame_ctx.context_depth = 0; - frame_ctx.is_eval_code = parse_opts & ECMA_PARSE_DIRECT_EVAL; + frame_size = frame_size * sizeof (ecma_value_t) + sizeof (vm_frame_ctx_t); + frame_size = (frame_size + sizeof (uintptr_t) - 1) / sizeof (uintptr_t); /* Use JERRY_MAX() to avoid array declaration with size 0. */ #if defined(JERRY_FOR_IAR_CONFIG) - stack = (ecma_value_t*)jerry_vla_malloc (sizeof(ecma_value_t) * JERRY_MAX (call_stack_size, 1)); + stack = (ecma_value_t*)jerry_vla_malloc (sizeof(ecma_value_t) * frame_size); if (!stack) { return ecma_raise_common_error (ECMA_ERR_MSG ("malloc stack failed")); } #else - JERRY_VLA (ecma_value_t, stack, JERRY_MAX (call_stack_size, 1)); -#endif - frame_ctx.registers_p = stack; - -#if defined(JERRY_FUNCTION_BACKTRACE) && !defined(__APPLE__) - if (JERRY_LIKELY(frame_ctx.prev_context_p != NULL)) { - frame_ctx.callee_value = frame_ctx.prev_context_p->callee_value; - } else { - frame_ctx.callee_value = ECMA_VALUE_UNDEFINED; - } + JERRY_VLA (uintptr_t, stack, frame_size); #endif -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (JERRY_CONTEXT (module_top_context_p) != NULL) - { - ecma_value_t ret_value = ecma_module_connect_imports (); + frame_ctx_p = (vm_frame_ctx_t *) stack; - if (ecma_is_value_empty (ret_value)) - { - ret_value = ecma_module_check_indirect_exports (); - } - - ecma_module_cleanup (); - - if (!ecma_is_value_empty (ret_value)) - { - return ret_value; - } - - JERRY_CONTEXT (module_top_context_p) = NULL; - } -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + frame_ctx_p->bytecode_header_p = bytecode_header_p; + frame_ctx_p->lex_env_p = lex_env_p; + frame_ctx_p->this_binding = this_binding_value; + vm_init_exec (frame_ctx_p, arg_list_p, arg_list_len); #if defined(JERRY_FOR_IAR_CONFIG) - ret = vm_execute (&frame_ctx, arg_list_p, arg_list_len); + ret = vm_execute (frame_ctx_p); jerry_vla_free ((char*)stack); return ret; #else - return vm_execute (&frame_ctx, arg_list_p, arg_list_len); + return vm_execute (frame_ctx_p); #endif } /* vm_run */ diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index b2a2f25d..9d648d4a 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -44,12 +44,12 @@ * If VM_OC_GET_ARGS_INDEX(opcode) == VM_OC_GET_BRANCH, * this flag signals that the branch is a backward branch. */ -#define VM_OC_BACKWARD_BRANCH 0x4000 +#define VM_OC_BACKWARD_BRANCH (1 << 15) /** * Position of "get arguments" opcode. */ -#define VM_OC_GET_ARGS_SHIFT 7 +#define VM_OC_GET_ARGS_SHIFT 8 /** * Mask of "get arguments" opcode. @@ -91,7 +91,7 @@ typedef enum /** * Mask of "group" opcode. */ -#define VM_OC_GROUP_MASK 0x7f +#define VM_OC_GROUP_MASK 0xff /** * Extract the "group" opcode. @@ -122,12 +122,9 @@ typedef enum VM_OC_PUSH_OBJECT, /**< push object */ VM_OC_PUSH_NAMED_FUNC_EXPR, /**< push named function expression */ VM_OC_SET_PROPERTY, /**< set property */ -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */ -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + VM_OC_SET_GETTER, /**< set getter */ VM_OC_SET_SETTER, /**< set setter */ - VM_OC_PUSH_UNDEFINED_BASE, /**< push undefined base */ VM_OC_PUSH_ARRAY, /**< push array */ VM_OC_PUSH_ELISON, /**< push elison */ VM_OC_APPEND_ARRAY, /**< append array */ @@ -153,7 +150,7 @@ typedef enum VM_OC_ASSIGN_PROP, /**< assign property */ VM_OC_ASSIGN_PROP_THIS, /**< assign prop this */ - VM_OC_RET, /**< return */ + VM_OC_RETURN, /**< return */ VM_OC_THROW, /**< throw */ VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */ @@ -164,7 +161,7 @@ typedef enum VM_OC_ERROR, /**< error while the vm_loop is suspended */ VM_OC_JUMP, /**< jump */ - VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */ + VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if strict equal */ /* These four opcodes must be in this order. */ VM_OC_BRANCH_IF_TRUE, /**< branch if true */ @@ -185,6 +182,9 @@ typedef enum VM_OC_MUL, /**< mul */ VM_OC_DIV, /**< div */ VM_OC_MOD, /**< mod */ +#if ENABLED (JERRY_ES2015) + VM_OC_EXP, /**< exponentiation */ +#endif /* ENABLED (JERRY_ES2015) */ VM_OC_EQUAL, /**< equal */ VM_OC_NOT_EQUAL, /**< not equal */ @@ -204,43 +204,82 @@ typedef enum VM_OC_RIGHT_SHIFT, /**< right shift */ VM_OC_UNS_RIGHT_SHIFT, /**< unsigned right shift */ + VM_OC_BLOCK_CREATE_CONTEXT, /**< create lexical environment for blocks enclosed in braces */ VM_OC_WITH, /**< with */ VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */ VM_OC_FOR_IN_GET_NEXT, /**< get next */ VM_OC_FOR_IN_HAS_NEXT, /**< has next */ -#if ENABLED (JERRY_ES2015_FOR_OF) - VM_OC_FOR_OF_CREATE_CONTEXT, /**< for of create context */ - VM_OC_FOR_OF_GET_NEXT, /**< get next */ - VM_OC_FOR_OF_HAS_NEXT, /**< has next */ -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + VM_OC_TRY, /**< try */ VM_OC_CATCH, /**< catch */ VM_OC_FINALLY, /**< finally */ VM_OC_CONTEXT_END, /**< context end */ VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */ -#if ENABLED (JERRY_ES2015_CLASS) - VM_OC_CLASS_HERITAGE, /**< create a super class context */ - VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, /**< push class constructor */ - VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */ - VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */ - VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */ - VM_OC_CLASS_EVAL, /**< eval inside a class */ - VM_OC_SUPER_CALL, /**< call the 'super' constructor */ - VM_OC_SUPER_PROP_REFERENCE, /**< resolve super property reference */ - VM_OC_PUSH_SUPER, /**< push resolvable super reference */ - VM_OC_PUSH_CONSTRUCTOR_SUPER, /**< push 'super' inside a class constructor */ - VM_OC_PUSH_CONSTRUCTOR_THIS, /**< push 'this' inside a class constructor */ - VM_OC_CONSTRUCTOR_RET, /**< explicit return from a class constructor */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ + + VM_OC_CREATE_BINDING, /**< create variables */ + VM_OC_SET_BYTECODE_PTR, /**< setting bytecode pointer */ + VM_OC_VAR_EVAL, /**< variable and function evaluation */ +#if ENABLED (JERRY_ES2015) + VM_OC_EXT_VAR_EVAL, /**< variable and function evaluation for + * functions with separate argument context */ +#endif /* ENABLED (JERRY_ES2015) */ + VM_OC_INIT_ARG_OR_FUNC, /**< create and init a function or argument binding */ + #if ENABLED (JERRY_DEBUGGER) VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ #endif /* ENABLED (JERRY_DEBUGGER) */ -#if ENABLED (JERRY_LINE_INFO) +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) VM_OC_RESOURCE_NAME, /**< resource name of the current function */ +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_LINE_INFO) VM_OC_LINE, /**< line number of the next statement */ #endif /* ENABLED (JERRY_LINE_INFO) */ +#if ENABLED (JERRY_ES2015) + VM_OC_CHECK_VAR, /**< check redeclared vars in the global scope */ + VM_OC_CHECK_LET, /**< check redeclared lets in the global scope */ + VM_OC_ASSIGN_LET_CONST, /**< assign values to let/const declarations */ + VM_OC_INIT_BINDING, /**< create and intialize a binding */ + VM_OC_THROW_CONST_ERROR, /**< throw invalid assignment to const variable error */ + VM_OC_COPY_TO_GLOBAL, /**< copy value to global lex env */ + VM_OC_COPY_FROM_ARG, /**< copy value from arg lex env */ + VM_OC_CLONE_CONTEXT, /**< clone lexical environment with let/const declarations */ + VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */ + + VM_OC_FOR_OF_CREATE_CONTEXT, /**< for of create context */ + VM_OC_FOR_OF_GET_NEXT, /**< get next */ + VM_OC_FOR_OF_HAS_NEXT, /**< has next */ + + VM_OC_LOCAL_EVAL, /**< eval in local context */ + VM_OC_SUPER_CALL, /**< call the 'super' constructor */ + VM_OC_PUSH_CLASS_ENVIRONMENT, /**< push class environment */ + VM_OC_PUSH_IMPLICIT_CTOR, /**< create implicit class constructor */ + VM_OC_INIT_CLASS, /**< initialize class */ + VM_OC_FINALIZE_CLASS, /**< finalize class */ + VM_OC_PUSH_SUPER_CONSTRUCTOR, /**< getSuperConstructor operation */ + VM_OC_RESOLVE_LEXICAL_THIS, /**< resolve this_binding from from the lexical environment */ + VM_OC_SUPER_REFERENCE, /**< push super reference */ + + VM_OC_PUSH_SPREAD_ELEMENT, /**< push spread element */ + VM_OC_GET_ITERATOR, /**< GetIterator abstract operation */ + VM_OC_ITERATOR_STEP, /**< IteratorStep abstract operation */ + VM_OC_ITERATOR_CLOSE, /**< IteratorClose abstract operation */ + VM_OC_DEFAULT_INITIALIZER, /**< default initializer inside a pattern */ + VM_OC_REST_INITIALIZER, /**< create rest object inside an array pattern */ + VM_OC_INITIALIZER_PUSH_PROP, /**< push property for object initializer */ + VM_OC_SPREAD_ARGUMENTS, /**< perform function call/construct with spreaded arguments */ + VM_OC_CREATE_GENERATOR, /**< create a generator object */ + VM_OC_YIELD, /**< yield operation */ + VM_OC_AWAIT, /**< await operation */ + VM_OC_EXT_RETURN, /**< return which also clears the stack */ + VM_OC_RETURN_PROMISE, /**< return from an async function */ + VM_OC_STRING_CONCAT, /**< string concatenation */ + VM_OC_GET_TEMPLATE_OBJECT, /**< GetTemplateObject operation */ + VM_OC_PUSH_NEW_TARGET, /**< push new.target onto the stack */ + VM_OC_REQUIRE_OBJECT_COERCIBLE,/**< RequireObjectCoercible opretaion */ + VM_OC_ASSIGN_SUPER, /**< assign super reference */ + VM_OC_SET__PROTO__, /**< set prototpe when __proto__: form is used */ +#endif /* ENABLED (JERRY_ES2015) */ VM_OC_NONE, /**< a special opcode for unsupported byte codes */ } vm_oc_types; @@ -249,37 +288,67 @@ typedef enum */ typedef enum { -#if !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */ -#endif /* !ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#if !ENABLED (JERRY_ES2015) + VM_OC_EXP = VM_OC_NONE, /**< exponentiation */ +#endif /* !ENABLED (JERRY_ES2015) */ #if !ENABLED (JERRY_DEBUGGER) VM_OC_BREAKPOINT_ENABLED = VM_OC_NONE, /**< enabled breakpoint for debugger is unused */ VM_OC_BREAKPOINT_DISABLED = VM_OC_NONE, /**< disabled breakpoint for debugger is unused */ #endif /* !ENABLED (JERRY_DEBUGGER) */ -#if !ENABLED (JERRY_LINE_INFO) +#if !ENABLED (JERRY_LINE_INFO) && !ENABLED (JERRY_ES2015_MODULE_SYSTEM) VM_OC_RESOURCE_NAME = VM_OC_NONE, /**< resource name of the current function is unused */ +#endif /* !ENABLED (JERRY_LINE_INFO) && !ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if !ENABLED (JERRY_LINE_INFO) VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */ #endif /* !ENABLED (JERRY_LINE_INFO) */ -#if !ENABLED (JERRY_ES2015_CLASS) - VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */ - VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE = VM_OC_NONE, /**< push class constructor */ - VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */ - VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */ - VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */ - VM_OC_CLASS_EVAL = VM_OC_NONE, /**< eval inside a class */ - VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */ - VM_OC_SUPER_PROP_REFERENCE = VM_OC_NONE, /**< resolve super property reference */ - VM_OC_PUSH_SUPER = VM_OC_NONE, /**< push resolvable super reference */ - VM_OC_PUSH_CONSTRUCTOR_SUPER = VM_OC_NONE, /**< push 'super' inside a class constructor */ - VM_OC_PUSH_CONSTRUCTOR_THIS = VM_OC_NONE, /**< push 'this' inside a class constructor */ - VM_OC_CONSTRUCTOR_RET = VM_OC_NONE, /**< explicit return from a class constructor */ -#endif /* !ENABLED (JERRY_ES2015_CLASS) */ -#if !ENABLED (JERRY_ES2015_FOR_OF) +#if !ENABLED (JERRY_ES2015) + VM_OC_EXT_VAR_EVAL = VM_OC_NONE, /**< variable and function evaluation for + * functions with separate argument context */ + VM_OC_CHECK_VAR = VM_OC_NONE, /**< check redeclared vars in the global scope */ + VM_OC_CHECK_LET = VM_OC_NONE, /**< check redeclared lets in the global scope */ + VM_OC_ASSIGN_LET_CONST = VM_OC_NONE, /**< assign values to let/const declarations */ + VM_OC_INIT_BINDING = VM_OC_NONE, /**< create and intialize a binding */ + VM_OC_THROW_CONST_ERROR = VM_OC_NONE, /**< throw invalid assignment to const variable error */ + VM_OC_COPY_TO_GLOBAL = VM_OC_NONE, /**< copy value to global lex env */ + VM_OC_COPY_FROM_ARG = VM_OC_NONE, /**< copy value from arg lex env */ + VM_OC_CLONE_CONTEXT = VM_OC_NONE, /**< clone lexical environment with let/const declarations */ + VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */ + VM_OC_FOR_OF_CREATE_CONTEXT = VM_OC_NONE, /**< for of create context */ VM_OC_FOR_OF_GET_NEXT = VM_OC_NONE, /**< get next */ VM_OC_FOR_OF_HAS_NEXT = VM_OC_NONE, /**< has next */ -#endif /* !ENABLED (JERRY_ES2015_FOR_OF) */ + + VM_OC_LOCAL_EVAL = VM_OC_NONE, /**< eval in local context */ + VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */ + VM_OC_PUSH_CLASS_ENVIRONMENT = VM_OC_NONE, /**< push class environment */ + VM_OC_PUSH_IMPLICIT_CTOR = VM_OC_NONE, /**< create implicit class constructor */ + VM_OC_INIT_CLASS = VM_OC_NONE, /**< initialize class */ + VM_OC_FINALIZE_CLASS = VM_OC_NONE, /**< finalize class */ + VM_OC_PUSH_SUPER_CONSTRUCTOR = VM_OC_NONE, /**< getSuperConstructor operation */ + VM_OC_RESOLVE_LEXICAL_THIS = VM_OC_NONE, /**< resolve this_binding from from the lexical environment */ + VM_OC_SUPER_REFERENCE = VM_OC_NONE, /**< push super reference */ + + VM_OC_PUSH_SPREAD_ELEMENT = VM_OC_NONE, /**< push spread element */ + VM_OC_GET_ITERATOR = VM_OC_NONE, /**< GetIterator abstract operation */ + VM_OC_ITERATOR_STEP = VM_OC_NONE, /**< IteratorStep abstract operation */ + VM_OC_ITERATOR_CLOSE = VM_OC_NONE, /**< IteratorClose abstract operation */ + VM_OC_DEFAULT_INITIALIZER = VM_OC_NONE, /**< default initializer inside a pattern */ + VM_OC_REST_INITIALIZER = VM_OC_NONE, /**< create rest object inside an array pattern */ + VM_OC_INITIALIZER_PUSH_PROP = VM_OC_NONE, /**< push property for object initializer */ + VM_OC_SPREAD_ARGUMENTS = VM_OC_NONE, /**< perform function call/construct with spreaded arguments */ + VM_OC_CREATE_GENERATOR = VM_OC_NONE, /**< create a generator object */ + VM_OC_YIELD = VM_OC_NONE, /**< yield operation */ + VM_OC_AWAIT = VM_OC_NONE, /**< await operation */ + VM_OC_EXT_RETURN = VM_OC_NONE, /**< return which also clears the stack */ + VM_OC_RETURN_PROMISE = VM_OC_NONE, /**< return from an async function */ + VM_OC_STRING_CONCAT = VM_OC_NONE, /**< string concatenation */ + VM_OC_GET_TEMPLATE_OBJECT = VM_OC_NONE, /**< GetTemplateObject operation */ + VM_OC_PUSH_NEW_TARGET = VM_OC_NONE, /**< push new.target onto the stack */ + VM_OC_REQUIRE_OBJECT_COERCIBLE = VM_OC_NONE,/**< RequireObjectCoercible opretaion */ + VM_OC_ASSIGN_SUPER = VM_OC_NONE, /**< assign super reference */ + VM_OC_SET__PROTO__ = VM_OC_NONE, /**< set prototpe when __proto__: form is used */ +#endif /* !ENABLED (JERRY_ES2015) */ + VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */ } vm_oc_unused_types; @@ -311,7 +380,7 @@ typedef enum /** * Bit index shift for non-static property initializers. */ -#define VM_OC_NON_STATIC_SHIFT 14 +#define VM_OC_NON_STATIC_SHIFT 15 /** * This flag is set for static property initializers. @@ -321,7 +390,7 @@ typedef enum /** * Position of "put result" opcode. */ -#define VM_OC_PUT_RESULT_SHIFT 10 +#define VM_OC_PUT_RESULT_SHIFT 11 /** * Mask of "put result" opcode. @@ -360,6 +429,8 @@ typedef enum VM_NO_EXEC_OP, /**< do nothing */ VM_EXEC_CALL, /**< invoke a function */ VM_EXEC_SUPER_CALL, /**< invoke a function through 'super' keyword */ + VM_EXEC_SPREAD_OP, /**< call/construct operation with spreaded argument list */ + VM_EXEC_RETURN, /**< return with the completion value without freeing registers */ VM_EXEC_CONSTRUCT, /**< construct a new object */ } vm_call_operation; @@ -371,8 +442,8 @@ ecma_value_t vm_run_module (const ecma_compiled_code_t *bytecode_p, ecma_object_ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t this_binding_value, - ecma_object_t *lex_env_p, uint32_t parse_opts, const ecma_value_t *arg_list_p, - ecma_length_t arg_list_len); + ecma_object_t *lex_env_p, const ecma_value_t *arg_list_p, ecma_length_t arg_list_len); +ecma_value_t vm_execute (vm_frame_ctx_t *frame_ctx_p); bool vm_is_strict_mode (void); bool vm_is_direct_eval_form_call (void); diff --git a/jerry-debugger/jerry_client.py b/jerry-debugger/jerry_client.py index a20e824c..6ce9baca 100755 --- a/jerry-debugger/jerry_client.py +++ b/jerry-debugger/jerry_client.py @@ -76,8 +76,12 @@ class DebuggerPrompt(Cmd): """ Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """ write(self.debugger.delete(args)) + def do_exception(self, args): + """ Config the exception handler module """ + write(self.debugger.exception(args)) + def do_next(self, args): - """ Next breakpoint in the same context """ + """ Next breakpoint in the same code block """ self.stop = True if not args: args = 0 @@ -116,23 +120,34 @@ class DebuggerPrompt(Cmd): self.stop = True do_s = do_step + def do_continue(self, _): + """ Continue execution """ + self.debugger.do_continue() + self.stop = True + if not self.debugger.non_interactive: + print("Press enter to stop JavaScript execution.") + do_c = do_continue + + def do_finish(self, _): + """ Continue running until the current function returns """ + self.debugger.finish() + self.stop = True + do_f = do_finish + def do_backtrace(self, args): """ Get backtrace data from debugger """ write(self.debugger.backtrace(args)) self.stop = True do_bt = do_backtrace - def do_variables(self, args): - """ Get scope variables from debugger """ - write(self.debugger.scope_variables(args)) - self.stop = True - def do_src(self, args): """ Get current source code """ if args: line_num = src_check_args(args) if line_num >= 0: write(self.debugger.print_source(line_num, 0)) + else: + write(self.debugger.print_source(0, 0)) do_source = do_src def do_scroll(self, _): @@ -148,27 +163,6 @@ class DebuggerPrompt(Cmd): else: print("Invalid key") - def do_continue(self, _): - """ Continue execution """ - self.debugger.get_continue() - self.stop = True - if not self.debugger.non_interactive: - print("Press enter to stop JavaScript execution.") - do_c = do_continue - - def do_finish(self, _): - """ Continue running until the current function returns """ - self.debugger.finish() - self.stop = True - do_f = do_finish - - def do_dump(self, args): - """ Dump all of the debugger data """ - if args: - print("Error: No argument expected") - else: - pprint(self.debugger.function_list) - def do_eval(self, args): """ Evaluate JavaScript source code """ self.debugger.eval(args) @@ -198,19 +192,13 @@ class DebuggerPrompt(Cmd): self.debugger.eval_at(code, index) self.stop = True - def do_memstats(self, _): - """ Memory statistics """ - self.debugger.memstats() - self.stop = True - do_ms = do_memstats - - def do_scopes(self, _): - """ Memory statistics """ - self.debugger.scope_chain() + def do_throw(self, args): + """ Throw an exception """ + self.debugger.throw(args) self.stop = True def do_abort(self, args): - """ Throw an exception """ + """ Throw an exception which cannot be caught """ self.debugger.abort(args) self.stop = True @@ -220,14 +208,36 @@ class DebuggerPrompt(Cmd): self.stop = True do_res = do_restart - def do_throw(self, args): - """ Throw an exception """ - self.debugger.throw(args) + def do_scope(self, _): + """ Get lexical environment chain """ + self.debugger.scope_chain() self.stop = True - def do_exception(self, args): - """ Config the exception handler module """ - write(self.debugger.exception(args)) + def do_variables(self, args): + """ Get scope variables from debugger """ + write(self.debugger.scope_variables(args)) + self.stop = True + + def do_memstats(self, _): + """ Memory statistics """ + self.debugger.memstats() + self.stop = True + do_ms = do_memstats + + def do_dump(self, args): + """ Dump all of the debugger data """ + if args: + print("Error: No argument expected") + else: + pprint(self.debugger.function_list) + + # pylint: disable=invalid-name + def do_EOF(self, _): + """ Exit JerryScript debugger """ + print("Unexpected end of input. Connection closed.") + self.debugger.quit() + self.quit = True + self.stop = True def _scroll_direction(debugger, direction): """ Helper function for do_scroll """ @@ -250,7 +260,7 @@ def src_check_args(args): print("Error: Non-negative integer number expected: %s" % (val_errno)) return -1 -# pylint: disable=too-many-branches,too-many-locals,too-many-statements,redefined-variable-type +# pylint: disable=too-many-branches,too-many-locals,too-many-statements def main(): args = jerry_client_main.arguments_parse() diff --git a/jerry-debugger/jerry_client_main.py b/jerry-debugger/jerry_client_main.py index 82ae47a7..9aae3f30 100644 --- a/jerry-debugger/jerry_client_main.py +++ b/jerry-debugger/jerry_client_main.py @@ -267,7 +267,7 @@ class DebuggerAction(object): class JerryDebugger(object): - # pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use,redefined-variable-type + # pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use def __init__(self, channel): self.prompt = False self.function_list = {} @@ -276,7 +276,7 @@ class JerryDebugger(object): self.exception_string = '' self.frame_index = 0 self.scope_vars = "" - self.scopes = "" + self.scope_data = "" self.client_sources = [] self.last_breakpoint_hit = None self.next_breakpoint_index = 0 @@ -340,38 +340,26 @@ class JerryDebugger(object): self.channel.close() def _exec_command(self, command_id): - self.send_command(command_id) + message = struct.pack(self.byte_order + "BB", + 1, + command_id) + self.channel.send_message(self.byte_order, message) def quit(self): self.prompt = False self._exec_command(JERRY_DEBUGGER_CONTINUE) + def set_colors(self): + self.nocolor = '\033[0m' + self.green = '\033[92m' + self.red = '\033[31m' + self.yellow = '\033[93m' + self.green_bg = '\033[42m\033[30m' + self.yellow_bg = '\033[43m\033[30m' + self.blue = '\033[94m' + def stop(self): - self.send_command(JERRY_DEBUGGER_STOP) - - def get_continue(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_CONTINUE) - - def finish(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_FINISH) - - def next(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_NEXT) - - def step(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_STEP) - - def memstats(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_MEMSTATS) - - def scope_chain(self): - self.prompt = False - self._exec_command(JERRY_DEBUGGER_GET_SCOPE_CHAIN) + self._exec_command(JERRY_DEBUGGER_STOP) def set_break(self, args): if not args: @@ -389,40 +377,6 @@ class JerryDebugger(object): return self._set_breakpoint(args, False) - def delete(self, args): - if not args: - return "Error: Breakpoint index expected\n" \ - "Delete the given breakpoint, use 'delete all|active|pending' " \ - "to clear all the given breakpoints\n " - elif args in ['all', 'pending', 'active']: - if args == "all": - self.delete_active() - self.delete_pending() - elif args == "pending": - self.delete_pending() - elif args == "active": - self.delete_active() - return "" - - try: - breakpoint_index = int(args) - except ValueError as val_errno: - return "Error: Integer number expected, %s\n" % (val_errno) - - if breakpoint_index in self.active_breakpoint_list: - breakpoint = self.active_breakpoint_list[breakpoint_index] - del self.active_breakpoint_list[breakpoint_index] - breakpoint.active_index = -1 - self.send_breakpoint(breakpoint) - return "Breakpoint %d deleted\n" % (breakpoint_index) - elif breakpoint_index in self.pending_breakpoint_list: - del self.pending_breakpoint_list[breakpoint_index] - if not self.pending_breakpoint_list: - self.send_parser_config(0) - return "Pending breakpoint %d deleted\n" % (breakpoint_index) - else: - return "Error: Breakpoint %d not found\n" % (breakpoint_index) - def breakpoint_list(self): result = '' if self.active_breakpoint_list: @@ -439,6 +393,60 @@ class JerryDebugger(object): return result + def delete(self, args): + if not args: + return "Error: Breakpoint index expected\n" \ + "Delete the given breakpoint, use 'delete all|active|pending' " \ + "to clear all the given breakpoints\n " + elif args in ['all', 'pending', 'active']: + if args != "pending": + for i in self.active_breakpoint_list.values(): + breakpoint = self.active_breakpoint_list[i.active_index] + del self.active_breakpoint_list[i.active_index] + breakpoint.active_index = -1 + self._send_breakpoint(breakpoint) + + if args != "active": + if self.pending_breakpoint_list: + self.pending_breakpoint_list.clear() + self._send_parser_config(0) + return "" + + try: + breakpoint_index = int(args) + except ValueError as val_errno: + return "Error: Integer number expected, %s\n" % (val_errno) + + if breakpoint_index in self.active_breakpoint_list: + breakpoint = self.active_breakpoint_list[breakpoint_index] + del self.active_breakpoint_list[breakpoint_index] + breakpoint.active_index = -1 + self._send_breakpoint(breakpoint) + return "Breakpoint %d deleted\n" % (breakpoint_index) + elif breakpoint_index in self.pending_breakpoint_list: + del self.pending_breakpoint_list[breakpoint_index] + if not self.pending_breakpoint_list: + self._send_parser_config(0) + return "Pending breakpoint %d deleted\n" % (breakpoint_index) + else: + return "Error: Breakpoint %d not found\n" % (breakpoint_index) + + def next(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_NEXT) + + def step(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_STEP) + + def do_continue(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_CONTINUE) + + def finish(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_FINISH) + def backtrace(self, args): max_depth = 0 min_depth = 0 @@ -480,28 +488,6 @@ class JerryDebugger(object): self.prompt = False return "" - def scope_variables(self, args): - index = 0 - if args: - try: - index = int(args) - if index < 0: - print ("Error: A non negative integer number expected") - return - - except ValueError as val_errno: - return "Error: Non negative integer number expected, %s\n" % (val_errno) - - message = struct.pack(self.byte_order + "BB" + self.idx_format, - 1 + 4, - JERRY_DEBUGGER_GET_SCOPE_VARIABLES, - index) - - self.channel.send_message(self.byte_order, message) - - self.prompt = False - return "" - def eval(self, code): self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL) self.prompt = False @@ -535,15 +521,45 @@ class JerryDebugger(object): if enabled: logging.debug("Stop at exception enabled") - self.send_exception_config(enabled) + self._send_exception_config(enabled) return "Stop at exception enabled\n" logging.debug("Stop at exception disabled") - self.send_exception_config(enabled) + self._send_exception_config(enabled) return "Stop at exception disabled\n" + def scope_chain(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_GET_SCOPE_CHAIN) + + def scope_variables(self, args): + index = 0 + if args: + try: + index = int(args) + if index < 0: + print("Error: A non negative integer number expected") + return "" + + except ValueError as val_errno: + return "Error: Non negative integer number expected, %s\n" % (val_errno) + + message = struct.pack(self.byte_order + "BB" + self.idx_format, + 1 + 4, + JERRY_DEBUGGER_GET_SCOPE_VARIABLES, + index) + + self.channel.send_message(self.byte_order, message) + + self.prompt = False + return "" + + def memstats(self): + self.prompt = False + self._exec_command(JERRY_DEBUGGER_MEMSTATS) + def _send_string(self, args, message_type, index=0): # 1: length of type byte @@ -591,19 +607,7 @@ class JerryDebugger(object): self.channel.send_message(self.byte_order, message + args[prev_offset:offset]) - def delete_active(self): - for i in self.active_breakpoint_list.values(): - breakpoint = self.active_breakpoint_list[i.active_index] - del self.active_breakpoint_list[i.active_index] - breakpoint.active_index = -1 - self.send_breakpoint(breakpoint) - - def delete_pending(self): - if self.pending_breakpoint_list: - self.pending_breakpoint_list.clear() - self.send_parser_config(0) - - def breakpoint_pending_exists(self, breakpoint): + def _breakpoint_pending_exists(self, breakpoint): for existing_bp in self.pending_breakpoint_list.values(): if (breakpoint.line and existing_bp.source_name == breakpoint.source_name and \ existing_bp.line == breakpoint.line) \ @@ -612,7 +616,7 @@ class JerryDebugger(object): return False - def send_breakpoint(self, breakpoint): + def _send_breakpoint(self, breakpoint): message = struct.pack(self.byte_order + "BBB" + self.cp_format + self.idx_format, 1 + 1 + self.cp_size + 4, JERRY_DEBUGGER_UPDATE_BREAKPOINT, @@ -621,42 +625,27 @@ class JerryDebugger(object): breakpoint.offset) self.channel.send_message(self.byte_order, message) - def send_bytecode_cp(self, byte_code_cp): + def _send_bytecode_cp(self, byte_code_cp): message = struct.pack(self.byte_order + "BB" + self.cp_format, 1 + self.cp_size, JERRY_DEBUGGER_FREE_BYTE_CODE_CP, byte_code_cp) self.channel.send_message(self.byte_order, message) - def send_command(self, command): - message = struct.pack(self.byte_order + "BB", - 1, - command) - self.channel.send_message(self.byte_order, message) - - def send_exception_config(self, enable): + def _send_exception_config(self, enable): message = struct.pack(self.byte_order + "BBB", 1 + 1, JERRY_DEBUGGER_EXCEPTION_CONFIG, enable) self.channel.send_message(self.byte_order, message) - def send_parser_config(self, enable): + def _send_parser_config(self, enable): message = struct.pack(self.byte_order + "BBB", 1 + 1, JERRY_DEBUGGER_PARSER_CONFIG, enable) self.channel.send_message(self.byte_order, message) - def set_colors(self): - self.nocolor = '\033[0m' - self.green = '\033[92m' - self.red = '\033[31m' - self.yellow = '\033[93m' - self.green_bg = '\033[42m\033[30m' - self.yellow_bg = '\033[43m\033[30m' - self.blue = '\033[94m' - def store_client_sources(self, args): self.client_sources = args @@ -715,7 +704,7 @@ class JerryDebugger(object): return DebuggerAction(DebuggerAction.TEXT, result) elif buffer_type == JERRY_DEBUGGER_WAITING_AFTER_PARSE: - self.send_command(JERRY_DEBUGGER_PARSER_RESUME) + self._exec_command(JERRY_DEBUGGER_PARSER_RESUME) elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP: self._release_function(data) @@ -808,11 +797,11 @@ class JerryDebugger(object): self.send_client_source() elif buffer_type in [JERRY_DEBUGGER_SCOPE_CHAIN, JERRY_DEBUGGER_SCOPE_CHAIN_END]: - self.scopes = data[1:] + self.scope_data = data[1:] if buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN_END: - result = self.process_scopes() - self.scopes = "" + result = self._process_scope() + self.scope_data = "" self.prompt = True @@ -822,7 +811,7 @@ class JerryDebugger(object): self.scope_vars += "".join(data[1:]) if buffer_type == JERRY_DEBUGGER_SCOPE_VARIABLES_END: - result = self.process_scope_variables() + result = self._process_scope_variables() self.scope_vars = "" self.prompt = True @@ -974,7 +963,7 @@ class JerryDebugger(object): if byte_code_cp in new_function_list: del new_function_list[byte_code_cp] - self.send_bytecode_cp(byte_code_cp) + self._send_bytecode_cp(byte_code_cp) else: self._release_function(data) @@ -1024,7 +1013,7 @@ class JerryDebugger(object): del bp_list[breakpoint_index] if not bp_list: - self.send_parser_config(0) + self._send_parser_config(0) return result logging.debug("No pending breakpoints") @@ -1043,13 +1032,13 @@ class JerryDebugger(object): del self.active_breakpoint_list[breakpoint.active_index] del self.function_list[byte_code_cp] - self.send_bytecode_cp(byte_code_cp) + self._send_bytecode_cp(byte_code_cp) logging.debug("Function {0x%x} byte-code released", byte_code_cp) def _enable_breakpoint(self, breakpoint): if isinstance(breakpoint, JerryPendingBreakpoint): - if self.breakpoint_pending_exists(breakpoint): + if self._breakpoint_pending_exists(breakpoint): return "%sPending breakpoint%s already exists\n" % (self.yellow, self.nocolor) self.next_breakpoint_index += 1 @@ -1064,7 +1053,7 @@ class JerryDebugger(object): self.next_breakpoint_index += 1 self.active_breakpoint_list[self.next_breakpoint_index] = breakpoint breakpoint.active_index = self.next_breakpoint_index - self.send_breakpoint(breakpoint) + self._send_breakpoint(breakpoint) return "%sBreakpoint %d%s at %s\n" % (self.green, breakpoint.active_index, @@ -1089,9 +1078,15 @@ class JerryDebugger(object): result += self._enable_breakpoint(breakpoint) else: + functions_to_enable = [] for function in self.function_list.values(): if function.name == string: - result += self._enable_breakpoint(function.lines[function.first_breakpoint_line]) + functions_to_enable.append(function) + + functions_to_enable.sort(key=lambda x: x.line) + + for function in functions_to_enable: + result += self._enable_breakpoint(function.lines[function.first_breakpoint_line]) if not result and not pending: print("No breakpoint found, do you want to add a %spending breakpoint%s? (y or [n])" % \ @@ -1100,7 +1095,7 @@ class JerryDebugger(object): ans = sys.stdin.readline() if ans in ['yes\n', 'y\n']: if not self.pending_breakpoint_list: - self.send_parser_config(1) + self._send_parser_config(1) if line: breakpoint = JerryPendingBreakpoint(int(line.group(2)), line.group(1)) @@ -1188,7 +1183,7 @@ class JerryDebugger(object): return "Uncaught exception: %s" % (message) return message - def process_scope_variables(self): + def _process_scope_variables(self): buff_size = len(self.scope_vars) buff_pos = 0 @@ -1228,15 +1223,15 @@ class JerryDebugger(object): elif value_type == JERRY_DEBUGGER_VALUE_OBJECT: table.append([name, 'Object', value]) - result = self.form_table(table) + result = self._form_table(table) return result - def process_scopes(self): + def _process_scope(self): result = "" table = [['level', 'type']] - for i, level in enumerate(self.scopes): + for i, level in enumerate(self.scope_data): if ord(level) == JERRY_DEBUGGER_SCOPE_WITH: table.append([str(i), 'with']) elif ord(level) == JERRY_DEBUGGER_SCOPE_GLOBAL: @@ -1251,11 +1246,11 @@ class JerryDebugger(object): else: raise Exception("Unexpected scope chain element") - result = self.form_table(table) + result = self._form_table(table) return result - def form_table(self, table): + def _form_table(self, table): result = "" col_width = [max(len(x) for x in col) for col in zip(*table)] for line in table: diff --git a/jerry-ext/BUILD.gn b/jerry-ext/BUILD.gn index e36f90dd..4efd8ec6 100755 --- a/jerry-ext/BUILD.gn +++ b/jerry-ext/BUILD.gn @@ -37,6 +37,7 @@ lite_library("jerry-ext_shared") { "handler/handler-gc.c", "handler/handler-print.c", "handler/handler-register.c", + "handler/handler-resource-name.c", "module/module.c", ] include_dirs = [ diff --git a/jerry-ext/CMakeLists.txt b/jerry-ext/CMakeLists.txt index ea76dd1a..967b777f 100644 --- a/jerry-ext/CMakeLists.txt +++ b/jerry-ext/CMakeLists.txt @@ -50,7 +50,7 @@ target_link_libraries(${JERRY_EXT_NAME} jerry-core) set(JERRY_EXT_PKGCONFIG_LIBS) -if(USING_MSVC AND FEATURE_DEBUGGER) +if(USING_MSVC AND JERRY_DEBUGGER) target_link_libraries(${JERRY_EXT_NAME} ws2_32) set(JERRY_EXT_PKGCONFIG_LIBS -lws2_32) endif() diff --git a/jerry-ext/arg/arg.c b/jerry-ext/arg/arg.c index 7a84a7ad..63a58611 100755 --- a/jerry-ext/arg/arg.c +++ b/jerry-ext/arg/arg.c @@ -20,7 +20,6 @@ #include "jerryscript-core.h" #endif - #define JERRYX_STATIC_ASSERT(x, msg) \ enum { static_assertion_failed_ ## msg = 1 / (!!(x)) } diff --git a/jerry-ext/debugger/debugger-tcp.c b/jerry-ext/debugger/debugger-tcp.c index 5d75c4d2..a12ac916 100755 --- a/jerry-ext/debugger/debugger-tcp.c +++ b/jerry-ext/debugger/debugger-tcp.c @@ -267,7 +267,7 @@ jerryx_debugger_tcp_configure_socket (jerryx_socket server_socket, /** < socket return false; } - if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) != 0) + if (bind (server_socket, (struct sockaddr *) &addr, sizeof (struct sockaddr_in)) != 0) { return false; } @@ -319,7 +319,7 @@ jerryx_debugger_tcp_create (uint16_t port) /**< listening port */ struct sockaddr_in addr; socklen_t sin_size = sizeof (struct sockaddr_in); - jerryx_socket tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size); + jerryx_socket tcp_socket = accept (server_socket, (struct sockaddr *) &addr, &sin_size); jerryx_debugger_tcp_close_socket (server_socket); diff --git a/jerry-ext/handler/handler-register.c b/jerry-ext/handler/handler-register.c index ad35d8c3..d808061f 100644 --- a/jerry-ext/handler/handler-register.c +++ b/jerry-ext/handler/handler-register.c @@ -63,7 +63,13 @@ jerryx_set_properties (const jerry_value_t target_object, /**< target object */ { #define JERRYX_SET_PROPERTIES_RESULT(VALUE, IDX) ((jerryx_register_result) { VALUE, IDX }) uint32_t idx = 0; - for (; ((entries + idx) != NULL) && (entries[idx].name != NULL); idx++) + + if (entries == NULL) + { + return JERRYX_SET_PROPERTIES_RESULT (jerry_create_undefined (), 0); + } + + for (; (entries[idx].name != NULL); idx++) { const jerryx_property_entry *entry = &entries[idx]; @@ -99,9 +105,12 @@ void jerryx_release_property_entry (const jerryx_property_entry entries[], /**< list of property entries */ const jerryx_register_result register_result) /**< previous result of registration */ { - for (uint32_t idx = register_result.registered; - ((entries + idx) != NULL) && (entries[idx].name != NULL); - idx++) + if (entries == NULL) + { + return; + } + + for (uint32_t idx = register_result.registered; entries[idx].name != NULL; idx++) { jerry_release_value (entries[idx].value); } diff --git a/jerry-ext/handler/handler-resource-name.c b/jerry-ext/handler/handler-resource-name.c new file mode 100644 index 00000000..94704437 --- /dev/null +++ b/jerry-ext/handler/handler-resource-name.c @@ -0,0 +1,42 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript-ext/handler.h" + +/** + * Get the resource name (usually a file name) of the currently executed script or the given function object + * + * Note: returned value must be freed with jerry_release_value, when it is no longer needed + * + * @return JS string constructed from + * - the currently executed function object's resource name, if the given value is undefined + * - resource name of the function object, if the given value is a function object + * - "", otherwise + */ +jerry_value_t +jerryx_handler_resource_name (const jerry_value_t func_obj_val, /**< function object */ + const jerry_value_t this_p, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + (void) func_obj_val; /* unused */ + (void) this_p; /* unused */ + + jerry_value_t undefined_value = jerry_create_undefined (); + jerry_value_t resource_name = jerry_get_resource_name (args_cnt > 0 ? args_p[0] : undefined_value); + jerry_release_value (undefined_value); + + return resource_name; +} /* jerryx_handler_resource_name */ diff --git a/jerry-ext/include/jerryscript-ext/handle-scope.h b/jerry-ext/include/jerryscript-ext/handle-scope.h index bd871fb7..bf403b82 100644 --- a/jerry-ext/include/jerryscript-ext/handle-scope.h +++ b/jerry-ext/include/jerryscript-ext/handle-scope.h @@ -67,7 +67,6 @@ struct jerryx_handle_scope_s JERRYX_HANDLE_SCOPE_FIELDS; /**< common handle scope fields */ }; - typedef struct jerryx_handle_scope_dynamic_s jerryx_handle_scope_dynamic_t; /** * Dynamically allocated handle scope type. diff --git a/jerry-ext/include/jerryscript-ext/handler.h b/jerry-ext/include/jerryscript-ext/handler.h index 41bfeeb8..c36b6b87 100644 --- a/jerry-ext/include/jerryscript-ext/handler.h +++ b/jerry-ext/include/jerryscript-ext/handler.h @@ -44,6 +44,8 @@ jerry_value_t jerryx_handler_gc (const jerry_value_t func_obj_val, const jerry_v const jerry_value_t args_p[], const jerry_length_t args_cnt); jerry_value_t jerryx_handler_print (const jerry_value_t func_obj_val, const jerry_value_t this_p, const jerry_value_t args_p[], const jerry_length_t args_cnt); +jerry_value_t jerryx_handler_resource_name (const jerry_value_t func_obj_val, const jerry_value_t this_p, + const jerry_value_t args_p[], const jerry_length_t args_cnt); /** * Struct used by the `jerryx_set_functions` method to diff --git a/jerry-ext/module/module.c b/jerry-ext/module/module.c index 6da6ced7..fb6a8dc7 100755 --- a/jerry-ext/module/module.c +++ b/jerry-ext/module/module.c @@ -230,7 +230,6 @@ jerryx_module_resolver_t jerryx_module_native_resolver = .resolve_p = jerryx_resolve_native_module }; - static void jerryx_module_resolve_local (const jerry_value_t name, /**< name of the module to load */ const jerryx_module_resolver_t **resolvers_p, /**< list of resolvers */ diff --git a/jerry-libm/BUILD.gn b/jerry-libm/BUILD.gn index c59149b9..c4c24e1d 100755 --- a/jerry-libm/BUILD.gn +++ b/jerry-libm/BUILD.gn @@ -1,48 +1,55 @@ -# Copyright (c) 2020 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build/lite/config/component/lite_component.gni") -import("//third_party/jerryscript/engine.gni") - -lite_component("jerry-libm") { - features = [ - ":jerry-libm_shared", - ] -} - -lite_library("jerry-libm_shared") { -target_type = "shared_library" - sources = [ - "acos.c", - "asin.c", - "atan2.c", - "atan.c", - "ceil.c", - "copysign.c", - "exp.c", - "fabs.c", - "finite.c", - "floor.c", - "fmod.c", - "isnan.c", - "log.c", - "nextafter.c", - "pow.c", - "scalbn.c", - "sqrt.c", - "trig.c", - ] - include_dirs = [ - "include", - ] -} +# Copyright (c) 2020 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/lite/config/component/lite_component.gni") +import("//third_party/jerryscript/engine.gni") + +lite_component("jerry-libm") { + features = [ ":jerry-libm_shared" ] +} + +lite_library("jerry-libm_shared") { + target_type = "shared_library" + sources = [ + "acos.c", + "acosh.c", + "asin.c", + "asinh.c", + "atan.c", + "atan2.c", + "atanh.c", + "cbrt.c", + "ceil.c", + "copysign.c", + "cosh.c", + "exp.c", + "expm1.c", + "fabs.c", + "finite.c", + "floor.c", + "fmod.c", + "isnan.c", + "log.c", + "log10.c", + "log1p.c", + "log2.c", + "nextafter.c", + "pow.c", + "scalbn.c", + "sinh.c", + "sqrt.c", + "tanh.c", + "trig.c", + ] + include_dirs = [ "include" ] +} diff --git a/jerry-libm/acos.c b/jerry-libm/acos.c index 875d41ef..14e6ded4 100644 --- a/jerry-libm/acos.c +++ b/jerry-libm/acos.c @@ -88,7 +88,7 @@ acos (double x) return pi + 2.0 * pio2_lo; } } - return (x - x) / (x - x); /* acos(|x|>1) is NaN */ + return NAN; /* acos(|x|>1) is NaN */ } if (ix < 0x3fe00000) /* |x| < 0.5 */ { diff --git a/jerry-libm/acosh.c b/jerry-libm/acosh.c new file mode 100644 index 00000000..7201f4f2 --- /dev/null +++ b/jerry-libm/acosh.c @@ -0,0 +1,92 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_acosh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* acosh(x) + * Method : + * Based on + * acosh(x) = log [ x + sqrt(x * x - 1) ] + * we have + * acosh(x) := log(x) + ln2, if x is large; else + * acosh(x) := log(2x - 1 / (sqrt(x * x - 1) + x)), if x > 2; else + * acosh(x) := log1p(t + sqrt(2.0 * t + t * t)); where t = x - 1. + * + * Special cases: + * acosh(x) is NaN with signal if x < 1. + * acosh(NaN) is NaN without signal. + */ + +#define one 1.0 +#define ln2 6.93147180559945286227e-01 /* 0x3FE62E42, 0xFEFA39EF */ + +double +acosh (double x) +{ + double t; + int hx; + hx = __HI (x); + if (hx < 0x3ff00000) + { + /* x < 1 */ + return NAN; + } + else if (hx >= 0x41b00000) + { + /* x > 2**28 */ + if (hx >= 0x7ff00000) + { + /* x is inf of NaN */ + return x + x; + } + else + { + /* acosh(huge) = log(2x) */ + return log (x) + ln2; + } + } + else if (((hx - 0x3ff00000) | __LO (x)) == 0) + { + /* acosh(1) = 0 */ + return 0.0; + } + else if (hx > 0x40000000) + { + /* 2**28 > x > 2 */ + t = x * x; + return log (2.0 * x - one / (x + sqrt (t - one))); + } + else + { + /* 1 < x < 2 */ + t = x - one; + return log1p (t + sqrt (2.0 * t + t * t)); + } +} /* acosh */ + +#undef one +#undef ln2 diff --git a/jerry-libm/asin.c b/jerry-libm/asin.c index 1af9c3c5..2c70db52 100644 --- a/jerry-libm/asin.c +++ b/jerry-libm/asin.c @@ -89,7 +89,7 @@ asin (double x) { return x * pio2_hi + x * pio2_lo; } - return (x - x) / (x - x); /* asin(|x|>1) is NaN */ + return NAN; /* asin(|x|>1) is NaN */ } else if (ix < 0x3fe00000) /* |x| < 0.5 */ { diff --git a/jerry-libm/asinh.c b/jerry-libm/asinh.c new file mode 100644 index 00000000..17edbec7 --- /dev/null +++ b/jerry-libm/asinh.c @@ -0,0 +1,95 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_asinh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* asinh(x) + * Method : + * Based on + * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] + * we have + * asinh(x) := x if 1 + x * x = 1, + * := sign(x) * (log(x)+ln2)) for large |x|, else + * := sign(x) * log(2|x| + 1 / (|x| + sqrt(x * x + 1))) if|x| > 2, else + * := sign(x) * log1p(|x| + x^2 / (1 + sqrt(1 + x^2))) + */ + +#define one 1.0 +#define ln2 6.93147180559945286227e-01 /* 0x3FE62E42, 0xFEFA39EF */ +#define huge 1.0e+300 + +double +asinh (double x) +{ + double t, w; + int hx, ix; + hx = __HI (x); + ix = hx & 0x7fffffff; + if (ix >= 0x7ff00000) + { + /* x is inf or NaN */ + return x + x; + } + if (ix < 0x3e300000) + { + /* |x| < 2**-28 */ + if (huge + x > one) + { + /* return x inexact except 0 */ + return x; + } + } + if (ix > 0x41b00000) + { + /* |x| > 2**28 */ + w = log (fabs (x)) + ln2; + } + else if (ix > 0x40000000) + { + /* 2**28 > |x| > 2.0 */ + t = fabs (x); + w = log (2.0 * t + one / (sqrt (x * x + one) + t)); + } + else + { + /* 2.0 > |x| > 2**-28 */ + t = x * x; + w = log1p (fabs (x) + t / (one + sqrt (one + t))); + } + if (hx > 0) + { + return w; + } + else + { + return -w; + } +} /* asinh */ + +#undef one +#undef ln2 +#undef huge diff --git a/jerry-libm/atan2.c b/jerry-libm/atan2.c index 025e128f..5f9eb137 100644 --- a/jerry-libm/atan2.c +++ b/jerry-libm/atan2.c @@ -82,7 +82,7 @@ atan2 (double y, double x) { return atan (y); } - m = ((hy >> 31) & 1) | ((hx >> 30) & 2); /* 2 * sign(x) + sign(y) */ + m = ((hy < 0) ? 1 : 0) + ((hx < 0) ? 2 : 0); /* 2 * sign(x) + sign(y) */ /* when y = 0 */ if ((iy | ly) == 0) diff --git a/jerry-libm/atanh.c b/jerry-libm/atanh.c new file mode 100644 index 00000000..ee6eb0cb --- /dev/null +++ b/jerry-libm/atanh.c @@ -0,0 +1,100 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_atanh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* atanh(x) + * Method : + * 1.Reduced x to positive by atanh(-x) = -atanh(x) + * 2.For x >= 0.5 + * 1 2x x + * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + * 2 1 - x 1 - x + * + * For x < 0.5 +* atanh(x) = 0.5 * log1p(2x + 2x * x / (1 - x)) + * + * Special cases: + * atanh(x) is NaN if |x| > 1 with signal; + * atanh(NaN) is that NaN with no signal; + * atanh(+-1) is +-INF with signal. + * + */ + +#define zero 0.0 +#define one 1.0 +#define huge 1.0e+300 + +double +atanh (double x) +{ + double t; + int hx, ix; + double_accessor temp; + temp.dbl = x; + hx = temp.as_int.hi; + ix = hx & 0x7fffffff; + + /* |x| > 1 */ + if ((ix | ((unsigned int) (temp.as_int.lo | (-temp.as_int.lo)) >> 31)) > 0x3ff00000) + { + return NAN; + } + if (ix == 0x3ff00000) + { + return x / zero; + } + if (ix < 0x3e300000 && (huge + x) > zero) + { + return x; /* x<2**-28 */ + } + + /* x <- |x| */ + temp.as_int.hi = ix; + if (ix < 0x3fe00000) + { + /* x < 0.5 */ + t = temp.dbl + temp.dbl; + t = 0.5 * log1p (t + t * temp.dbl / (one - temp.dbl)); + } + else + { + t = 0.5 * log1p ((temp.dbl + temp.dbl) / (one - temp.dbl)); + } + if (hx >= 0) + { + return t; + } + else + { + return -t; + } +} /* atanh */ + +#undef zero +#undef one +#undef huge diff --git a/jerry-libm/cbrt.c b/jerry-libm/cbrt.c new file mode 100644 index 00000000..cedb2a9d --- /dev/null +++ b/jerry-libm/cbrt.c @@ -0,0 +1,103 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_cbrt.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* cbrt(x) + * Return cube root of x + */ + +#define B1 715094163 /* B1 = (682 - 0.03306235651) * 2**20 */ +#define B2 696219795 /* B2 = (664 - 0.03306235651) * 2**20 */ +#define C 5.42857142857142815906e-01 /* 19/35 = 0x3FE15F15, 0xF15F15F1 */ +#define D -7.05306122448979611050e-01 /* -864/1225 = 0xBFE691DE, 0x2532C834 */ +#define E 1.41428571428571436819e+00 /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */ +#define F 1.60714285714285720630e+00 /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */ +#define G 3.57142857142857150787e-01 /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */ + +double +cbrt (double x) +{ + double r, s, w; + double_accessor t, temp; + unsigned int sign; + t.dbl = 0.0; + temp.dbl = x; + + sign = temp.as_int.hi & 0x80000000; /* sign = sign(x) */ + temp.as_int.hi ^= sign; + + if (temp.as_int.hi >= 0x7ff00000) + { + /* cbrt(NaN, INF) is itself */ + return (x + x); + } + if ((temp.as_int.hi | temp.as_int.lo) == 0) + { + /* cbrt(0) is itself */ + return (x); + } + /* rough cbrt to 5 bits */ + if (temp.as_int.hi < 0x00100000) /* subnormal number */ + { + t.as_int.hi = 0x43500000; /* set t= 2**54 */ + t.dbl *= temp.dbl; + t.as_int.hi = t.as_int.hi / 3 + B2; + } + else + { + t.as_int.hi = temp.as_int.hi / 3 + B1; + } + + /* new cbrt to 23 bits, may be implemented in single precision */ + r = t.dbl * t.dbl / temp.dbl; + s = C + r * t.dbl; + t.dbl *= G + F / (s + E + D / s); + + /* chopped to 20 bits and make it larger than cbrt(x) */ + t.as_int.lo = 0; + t.as_int.hi += 0x00000001; + + /* one step newton iteration to 53 bits with error less than 0.667 ulps */ + s = t.dbl * t.dbl; /* t*t is exact */ + r = temp.dbl / s; + w = t.dbl + t.dbl; + r = (r - t.dbl) / (w + r); /* r-s is exact */ + t.dbl = t.dbl + (t.dbl * r); + + /* retore the sign bit */ + t.as_int.hi |= sign; + return (t.dbl); +} /* cbrt */ + +#undef B1 +#undef B2 +#undef C +#undef D +#undef E +#undef F +#undef G diff --git a/jerry-libm/cosh.c b/jerry-libm/cosh.c new file mode 100644 index 00000000..c21297b9 --- /dev/null +++ b/jerry-libm/cosh.c @@ -0,0 +1,113 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_cosh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* cosh(x) + * Method: + * mathematically cosh(x) if defined to be (exp(x) + exp(-x)) / 2 + * 1. Replace x by |x| (cosh(x) = cosh(-x)). + * 2. + * [ exp(x) - 1 ]^2 + * 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- + * 2*exp(x) + * + * exp(x) + 1/exp(x) + * ln2/2 <= x <= 22 : cosh(x) := ------------------- + * 2 + * + * 22 <= x <= lnovft : cosh(x) := exp(x)/2 + * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) + * ln2ovft < x : cosh(x) := huge * huge (overflow) + * + * Special cases: + * cosh(x) is |x| if x is +INF, -INF, or NaN. + * only cosh(0) = 1 is exact for finite x. + */ + +#define one 1.0 +#define half 0.5 +#define huge 1.0e300 + +double +cosh (double x) +{ + double t, w; + int ix; + unsigned lx; + + /* High word of |x|. */ + ix = __HI (x); + ix &= 0x7fffffff; + + /* x is INF or NaN */ + if (ix >= 0x7ff00000) + { + return x * x; + } + /* |x| in [0, 0.5 * ln2], return 1 + expm1(|x|)^2 / (2 * exp(|x|)) */ + if (ix < 0x3fd62e43) + { + t = expm1 (fabs (x)); + w = one + t; + if (ix < 0x3c800000) + { + /* cosh(tiny) = 1 */ + return w; + } + return one + (t * t) / (w + w); + } + + /* |x| in [0.5 * ln2, 22], return (exp(|x|) + 1 / exp(|x|) / 2; */ + if (ix < 0x40360000) + { + t = exp (fabs (x)); + return half * t + half / t; + } + + /* |x| in [22, log(maxdouble)] return half * exp(|x|) */ + if (ix < 0x40862E42) + { + return half * exp (fabs (x)); + } + /* |x| in [log(maxdouble), overflowthresold] */ + lx = ((1 >> 29) + (unsigned int) x); + if ((ix < 0x408633CE) || + ((ix == 0x408633ce) && (lx <= (unsigned) 0x8fb9f87d))) + { + w = exp (half * fabs (x)); + t = half * w; + return t * w; + } + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge * huge; +} /* cosh */ + +#undef one +#undef half +#undef huge diff --git a/jerry-libm/exp.c b/jerry-libm/exp.c index 8970528f..201dd02d 100644 --- a/jerry-libm/exp.c +++ b/jerry-libm/exp.c @@ -197,7 +197,7 @@ exp (double x) /* default IEEE double exp */ } if (k >= -1021) { - ret.as_int.hi += (k << 20); /* add k to y's exponent */ + ret.as_int.hi += (((unsigned int) k) << 20); /* add k to y's exponent */ return ret.dbl; } else diff --git a/jerry-libm/expm1.c b/jerry-libm/expm1.c new file mode 100644 index 00000000..e23f1ad7 --- /dev/null +++ b/jerry-libm/expm1.c @@ -0,0 +1,305 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_expm1.c 5.1 93/09/24 + */ + +#include "jerry-libm-internal.h" + +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Reme algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#define one 1.0 +#define huge 1.0e+300 +#define tiny 1.0e-300 +#define o_threshold 7.09782712893383973096e+02 /* 0x40862E42, 0xFEFA39EF */ +#define ln2_hi 6.93147180369123816490e-01 /* 0x3fe62e42, 0xfee00000 */ +#define ln2_lo 1.90821492927058770002e-10 /* 0x3dea39ef, 0x35793c76 */ +#define invln2 1.44269504088896338700e+00 /* 0x3ff71547, 0x652b82fe */ + +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +#define Q1 -3.33333333333331316428e-02 /* BFA11111 111110F4 */ +#define Q2 1.58730158725481460165e-03 /* 3F5A01A0 19FE5585 */ +#define Q3 -7.93650757867487942473e-05 /* BF14CE19 9EAADBB7 */ +#define Q4 4.00821782732936239552e-06 /* 3ED0CFCA 86E65239 */ +#define Q5 -2.01099218183624371326e-07 /* BE8AFDB7 6E09C32D */ + +double +expm1 (double x) +{ + double y, hi, lo, c, e, hxs, hfx, r1; + double_accessor t, twopk; + int k, xsb; + unsigned int hx; + + hx = __HI (x); + xsb = hx & 0x80000000; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) + { + /* if |x|>=56*ln2 */ + if (hx >= 0x40862E42) + { + /* if |x|>=709.78... */ + if (hx >= 0x7ff00000) + { + unsigned int low; + low = __LO (x); + if (((hx & 0xfffff) | low) != 0) + { + /* NaN */ + return x + x; + } + else + { + /* exp(+-inf)-1={inf,-1} */ + return (xsb == 0) ? x : -1.0; + } + } + if (x > o_threshold) + { + /* overflow */ + return huge * huge; + } + } + if (xsb != 0) + { + /* x < -56*ln2, return -1.0 with inexact */ + if (x + tiny < 0.0) /* raise inexact */ + { + /* return -1 */ + return tiny - one; + } + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) + { + /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) + { + /* and |x| < 1.5 ln2 */ + if (xsb == 0) + { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } + else + { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } + else + { + k = (int) (invln2 * x + ((xsb == 0) ? 0.5 : -0.5)); + t.dbl = k; + hi = x - t.dbl * ln2_hi; /* t*ln2_hi is exact here */ + lo = t.dbl * ln2_lo; + } + x = hi - lo; + c = (hi - x) - lo; + } + else if (hx < 0x3c900000) + { + /* when |x|<2**-54, return x */ + return x; + } + else + { + k = 0; + } + + /* x is now in primary range */ + hfx = 0.5 * x; + hxs = x * hfx; + r1 = one + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t.dbl = 3.0 - r1 * hfx; + e = hxs * ((r1 - t.dbl) / (6.0 - x * t.dbl)); + if (k == 0) + { + /* c is 0 */ + return x - (x * e - hxs); + } + else + { + twopk.as_int.hi = 0x3ff00000 + ((unsigned int) k << 20); /* 2^k */ + twopk.as_int.lo = 0; + e = (x * (e - c) - c); + e -= hxs; + if (k == -1) + { + return 0.5 * (x - e) - 0.5; + } + if (k == 1) + { + if (x < -0.25) + { + return -2.0 * (e - (x + 0.5)); + } + else + { + return one + 2.0 * (x - e); + } + } + if ((k <= -2) || (k > 56)) + { + /* suffice to return exp(x)-1 */ + y = one - (e - x); + if (k == 1024) + { + y = y * 2.0 * 0x1p1023; + } + else + { + y = y * twopk.dbl; + } + return y - one; + } + t.dbl = one; + if (k < 20) + { + t.as_int.hi = (0x3ff00000 - (0x200000 >> k)); /* t=1-2^-k */ + y = t.dbl - (e - x); + y = y * twopk.dbl; + } + else + { + t.as_int.hi = ((0x3ff - k) << 20); /* 2^-k */ + y = x - (e + t.dbl); + y += one; + y = y * twopk.dbl; + } + } + return y; +} /* expm1 */ + +#undef one +#undef huge +#undef tiny +#undef o_threshold +#undef ln2_hi +#undef ln2_lo +#undef invln2 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 +#undef Q5 diff --git a/jerry-libm/fmod.c b/jerry-libm/fmod.c index 7a74bf3f..0c335e45 100644 --- a/jerry-libm/fmod.c +++ b/jerry-libm/fmod.c @@ -53,7 +53,7 @@ fmod (double x, double y) if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y = 0, or x not finite */ ((hy | ((ly | -ly) >> 31)) > 0x7ff00000)) /* or y is NaN */ { - return (x * y) / (x * y); + return NAN; } if (hx <= hy) { @@ -123,7 +123,7 @@ fmod (double x, double y) n = -1022 - ix; if (n <= 31) { - hx = (hx << n) | (lx >> (32 - n)); + hx = (((unsigned int) hx) << n) | (lx >> (32 - n)); lx <<= n; } else @@ -141,7 +141,7 @@ fmod (double x, double y) n = -1022 - iy; if (n <= 31) { - hy = (hy << n) | (ly >> (32 - n)); + hy = (((unsigned int) hy) << n) | (ly >> (32 - n)); ly <<= n; } else diff --git a/jerry-libm/include/math.h b/jerry-libm/include/math.h index 496c2426..9a0a682f 100644 --- a/jerry-libm/include/math.h +++ b/jerry-libm/include/math.h @@ -56,13 +56,28 @@ double asin (double); double atan (double); double atan2 (double, double); +/* Hyperbolic functions. */ +double cosh (double x); +double sinh (double x); +double tanh (double x); + +/* Inverse hyperbolic functions */ +double acosh (double); +double asinh (double); +double atanh (double); + /* Exponential and logarithmic functions. */ double exp (double); +double expm1 (double); double log (double); +double log1p (double); +double log2 (double); +double log10 (double); /* Power functions. */ double pow (double, double); double sqrt (double); +double cbrt (double); /* Rounding and remainder functions. */ double ceil (double); diff --git a/jerry-libm/jerry-libm-internal.h b/jerry-libm/jerry-libm-internal.h index fb29c7f4..d03e63d5 100644 --- a/jerry-libm/jerry-libm-internal.h +++ b/jerry-libm/jerry-libm-internal.h @@ -30,7 +30,6 @@ /* Sometimes it's necessary to define __LITTLE_ENDIAN explicitly but these catch some common cases. */ - #ifndef __LITTLE_ENDIAN /* Check if compiler has byte order macro. Some older versions do not. * If byte order is supported and set to little or target is among common @@ -89,11 +88,24 @@ double cos (double x); double sin (double x); double tan (double x); +double cosh (double x); +double sinh (double x); +double tanh (double x); + +double acosh (double x); +double asinh (double x); +double atanh (double x); + double exp (double x); +double expm1 (double x); double log (double x); +double log1p (double x); +double log2 (double x); +double log10 (double); double pow (double x, double y); double sqrt (double x); +double cbrt (double); double ceil (double x); double fabs (double x); diff --git a/jerry-libm/log10.c b/jerry-libm/log10.c new file mode 100644 index 00000000..d8de89a9 --- /dev/null +++ b/jerry-libm/log10.c @@ -0,0 +1,116 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_log10.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* log10(x) + * Return the base 10 logarithm of x + * + * Method : + * Let log10_2hi = leading 40 bits of log10(2) and + * log10_2lo = log10(2) - log10_2hi, + * ivln10 = 1/log(10) rounded. + * Then + * n = ilogb(x), + * if(n<0) n = n+1; + * x = scalbn(x,-n); + * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x)) + * + * Note 1: + * To guarantee log10(10**n)=n, where 10**n is normal, the rounding + * mode must set to Round-to-Nearest. + * Note 2: + * [1/log(10)] rounded to 53 bits has error .198 ulps; + * log10 is monotonic at all binary break points. + * + * Special cases: + * log10(x) is NaN with signal if x < 0; + * log10(+INF) is +INF with no signal; log10(0) is -INF with signal; + * log10(NaN) is that NaN with no signal; + * log10(10**N) = N for N=0,1,...,22. + * + * Constants: + * The hexadecimal values are the intended ones for the following constants. + * The decimal values may be used, provided that the compiler will convert + * from decimal to binary accurately enough to produce the hexadecimal values + * shown. + */ + +#define zero 0.0 +#define two54 1.80143985094819840000e+16 /* 0x43500000, 0x00000000 */ +#define ivln10 4.34294481903251816668e-01 /* 0x3FDBCB7B, 0x1526E50E */ +#define log10_2hi 3.01029995663611771306e-01 /* 0x3FD34413, 0x509F6000 */ +#define log10_2lo 3.69423907715893078616e-13 /* 0x3D59FEF3, 0x11F12B36 */ + +double +log10 (double x) +{ + double y, z; + int i, k, hx; + unsigned lx; + double_accessor temp; + + hx = __HI (x); /* high word of x */ + lx = __LO (x); /* low word of x */ + + k = 0; + if (hx < 0x00100000) + { + /* x < 2**-1022 */ + if (((hx & 0x7fffffff) | lx) == 0) + { + /* log(+-0)=-inf */ + return -two54 / zero; + } + if (hx < 0) + { + /* log(-#) = NaN */ + return (x - x) / zero; + } + k -= 54; + x *= two54; /* subnormal number, scale up x */ + hx = __HI (x); /* high word of x */ + } + if (hx >= 0x7ff00000) + { + return x + x; + } + k += (hx >> 20) - 1023; + i = ((unsigned) k & 0x80000000) >> 31; + hx = (hx & 0x000fffff) | ((0x3ff - i) << 20); + y = (double) (k + i); + temp.dbl = x; + temp.as_int.hi = hx; + z = y * log10_2lo + ivln10 * log (temp.dbl); + return z + y * log10_2hi; +} /* log10 */ + +#undef zero +#undef two54 +#undef ivln10 +#undef log10_2hi +#undef log10_2lo diff --git a/jerry-libm/log1p.c b/jerry-libm/log1p.c new file mode 100644 index 00000000..a7e7c64b --- /dev/null +++ b/jerry-libm/log1p.c @@ -0,0 +1,245 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_log1p.c 5.1 93/09/24 + */ + +#include "jerry-libm-internal.h" + +/* log1p(x) + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log1p(f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s + * (the values of Lp1 to Lp7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lp1*s +...+Lp7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log1p(f) = f - (hfsq - s*(hfsq+R)). + * + * 3. Finally, log1p(x) = k*ln2 + log1p(f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#define zero 0.0 +#define ln2_hi 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */ +#define ln2_lo 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */ +#define two54 1.80143985094819840000e+16 /* 43500000 00000000 */ +#define Lp1 6.666666666666735130e-01 /* 3FE55555 55555593 */ +#define Lp2 3.999999999940941908e-01 /* 3FD99999 9997FA04 */ +#define Lp3 2.857142874366239149e-01 /* 3FD24924 94229359 */ +#define Lp4 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */ +#define Lp5 1.818357216161805012e-01 /* 3FC74664 96CB03DE */ +#define Lp6 1.531383769920937332e-01 /* 3FC39A09 D078C69F */ +#define Lp7 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */ + +double +log1p (double x) +{ + double hfsq, f, c, s, z, R; + double_accessor u; + int k, hx, hu, ax; + + hx = __HI (x); + ax = hx & 0x7fffffff; + c = 0; + k = 1; + if (hx < 0x3FDA827A) + { + /* 1+x < sqrt(2)+ */ + if (ax >= 0x3ff00000) + { + /* x <= -1.0 */ + if (x == -1.0) + { + /* log1p(-1) = +inf */ + return -two54 / zero; + } + else + { + /* log1p(x<-1) = NaN */ + return NAN; + } + } + if (ax < 0x3e200000) + { /* |x| < 2**-29 */ + if ((two54 + x > zero) /* raise inexact */ + && (ax < 0x3c900000)) /* |x| < 2**-54 */ + { + return x; + } + else + { + return x - x * x * 0.5; + } + } + if ((hx > 0) || hx <= ((int) 0xbfd2bec4)) + { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + f = x; + hu = 1; + } + } + if (hx >= 0x7ff00000) + { + return x + x; + } + if (k != 0) + { + if (hx < 0x43400000) + { + u.dbl = 1.0 + x; + hu = u.as_int.hi; + k = (hu >> 20) - 1023; + c = (k > 0) ? 1.0 - (u.dbl - x) : x - (u.dbl - 1.0); /* correction term */ + c /= u.dbl; + } + else + { + u.dbl = x; + hu = u.as_int.hi; + k = (hu >> 20) - 1023; + c = 0; + } + hu &= 0x000fffff; + /* + * The approximation to sqrt(2) used in thresholds is not + * critical. However, the ones used above must give less + * strict bounds than the one here so that the k==0 case is + * never reached from here, since here we have committed to + * using the correction term but don't use it if k==0. + */ + if (hu < 0x6a09e) + { + /* u ~< sqrt(2) */ + u.as_int.hi = hu | 0x3ff00000; /* normalize u */ + } + else + { + k += 1; + u.as_int.hi = hu | 0x3fe00000; /* normalize u/2 */ + hu = (0x00100000 - hu) >> 2; + } + f = u.dbl - 1.0; + } + hfsq = 0.5 * f * f; + if (hu == 0) + { + /* |f| < 2**-20 */ + if (f == zero) + { + if (k == 0) + { + return zero; + } + else + { + c += k * ln2_lo; + return k * ln2_hi + c; + } + } + R = hfsq * (1.0 - 0.66666666666666666 * f); + if (k == 0) + { + return f - R; + } + else + { + return k * ln2_hi - ((R - (k * ln2_lo + c)) - f); + } + } + s = f / (2.0 + f); + z = s * s; + R = z * (Lp1 + + z * (Lp2 + z * (Lp3 + z * (Lp4 + z * (Lp5 + z * (Lp6 + z * Lp7)))))); + if (k == 0) + { + return f - (hfsq - s * (hfsq + R)); + } + else + { + return k * ln2_hi - ((hfsq - (s * (hfsq + R) + (k * ln2_lo + c))) - f); + } +} /* log1p */ + +#undef zero +#undef ln2_hi +#undef ln2_lo +#undef two54 +#undef Lp1 +#undef Lp2 +#undef Lp3 +#undef Lp4 +#undef Lp5 +#undef Lp6 +#undef Lp7 diff --git a/jerry-libm/log2.c b/jerry-libm/log2.c new file mode 100644 index 00000000..841048bd --- /dev/null +++ b/jerry-libm/log2.c @@ -0,0 +1,160 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_log2.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* log2(x) + * Return the base 2 logarithm of x. See e_log.c and k_log.h for most + * comments. + * + * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel, + * then does the combining and scaling steps + * log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k + * in not-quite-routine extra precision. + */ + +#define zero 0.0 +#define two54 1.80143985094819840000e+16 /* 0x43500000, 0x00000000 */ +#define ivln2hi 1.44269504072144627571e+00 /* 0x3FF71547, 0x65200000 */ +#define ivln2lo 1.67517131648865118353e-10 /* 0x3DE705FC, 0x2EEFA200 */ +#define Lg1 6.666666666666735130e-01 /* 0x3FE55555, 0x55555593 */ +#define Lg2 3.999999999940941908e-01 /* 0x3FD99999, 0x9997FA04 */ +#define Lg3 2.857142874366239149e-01 /* 0x3FD24924, 0x94229359 */ +#define Lg4 2.222219843214978396e-01 /* 0x3FCC71C5, 0x1D8E78AF */ +#define Lg5 1.818357216161805012e-01 /* 0x3FC74664, 0x96CB03DE */ +#define Lg6 1.531383769920937332e-01 /* 0x3FC39A09, 0xD078C69F */ +#define Lg7 1.479819860511658591e-01 /* 0x3FC2F112, 0xDF3E5244 */ + +double +log2 (double x) +{ + double f, hfsq, hi, lo, r, val_hi, val_lo, w, y; + int i, k, hx; + unsigned int lx; + double_accessor temp; + + hx = __HI (x); /* high word of x */ + lx = __LO (x); /* low word of x */ + + k = 0; + if (hx < 0x00100000) + { /* x < 2**-1022 */ + if (((hx & 0x7fffffff) | lx) == 0) + { + return -two54 / zero; /* log(+-0)=-inf */ + } + if (hx < 0) + { + return (x - x) / zero; /* log(-#) = NaN */ + } + k -= 54; + x *= two54; /* subnormal number, scale up x */ + hx = __HI (x); /* high word of x */ + } + if (hx >= 0x7ff00000) + { + return x + x; + } + if (hx == 0x3ff00000 && lx == 0) + { + return zero; /* log(1) = +0 */ + } + k += (hx >> 20) - 1023; + hx &= 0x000fffff; + i = (hx + 0x95f64) & 0x100000; + temp.dbl = x; + temp.as_int.hi = hx | (i ^ 0x3ff00000); /* normalize x or x/2 */ + k += (i >> 20); + y = (double) k; + f = temp.dbl - 1.0; + hfsq = 0.5 * f * f; + double s, z, R, t1, t2; + + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + R = t2 + t1; + r = s * (hfsq + R); + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + hi = f - hfsq; + temp.dbl = hi; + temp.as_int.lo = 0; + + lo = (f - hi) - hfsq + r; + val_hi = hi * ivln2hi; + val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} /* log2 */ + +#undef zero +#undef two54 +#undef ivln2hi +#undef ivln2lo +#undef Lg1 +#undef Lg2 +#undef Lg3 +#undef Lg4 +#undef Lg5 +#undef Lg6 +#undef Lg7 diff --git a/jerry-libm/pow.c b/jerry-libm/pow.c index 581876c1..a33b9b8f 100644 --- a/jerry-libm/pow.c +++ b/jerry-libm/pow.c @@ -254,12 +254,12 @@ pow (double x, double y) } } - n = (hx >> 31) + 1; + n = (hx < 0) ? 0 : 1; /* (x<0)**(non-int) is NaN */ if ((n | yisint) == 0) { - return (x - x) / (x - x); + return NAN; } s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ diff --git a/jerry-libm/sinh.c b/jerry-libm/sinh.c new file mode 100644 index 00000000..5439c3a5 --- /dev/null +++ b/jerry-libm/sinh.c @@ -0,0 +1,115 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)e_sinh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* __sinh(x) + * Method: + * mathematically sinh(x) if defined to be (exp(x) - exp(-x)) / 2 + * 1. Replace x by |x| (sinh(-x) = -sinh(x)). + * 2. + * E + E/(E+1) + * 0 <= x <= 22 : sinh(x) := -------------, E = expm1(x) + * 2 + * + * 22 <= x <= lnovft : sinh(x) := exp(x) / 2 + * lnovft <= x <= ln2ovft: sinh(x) := exp(x / 2) / 2 * exp(x / 2) + * ln2ovft < x : sinh(x) := x * shuge (overflow) + * + * Special cases: + * sinh(x) is |x| if x is +INF, -INF, or NaN. + * only sinh(0) = 0 is exact for finite x. + */ + +#define one 1.0 +#define half 0.5 +#define shuge 1.0e307 + +double +sinh (double x) +{ + double t, w, h; + int ix, jx; + unsigned lx; + + /* High word of |x|. */ + jx = __HI (x); + ix = jx & 0x7fffffff; + + /* x is INF or NaN */ + if (ix >= 0x7ff00000) + { + return x + x; + } + + h = 0.5; + if (jx < 0) + { + h = -h; + } + /* |x| in [0,22], return sign(x) * 0.5 * (E + E / (E + 1))) */ + if (ix < 0x40360000) + { + /* |x| < 22 */ + if (ix < 0x3e300000) + { + /* |x| < 2**-28 */ + if (shuge + x > one) + { + /* sinh(tiny) = tiny with inexact */ + return x; + } + } + t = expm1 (fabs (x)); + if (ix < 0x3ff00000) + { + return h * (2.0 * t - t * t / (t + one)); + } + return h * (t + t / (t + one)); + } + + /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix < 0x40862E42) + { + return h * exp (fabs (x)); + } + /* |x| in [log(maxdouble), overflowthresold] */ + lx = ((1 >> 29) + (unsigned int) x); + if (ix < 0x408633CE || ((ix == 0x408633ce) && (lx <= (unsigned) 0x8fb9f87d))) + { + w = exp (0.5 * fabs (x)); + t = h * w; + return t * w; + } + + /* |x| > overflowthresold, sinh(x) overflow */ + return x * shuge; +} /* sinh */ + +#undef one +#undef half +#undef huge diff --git a/jerry-libm/sqrt.c b/jerry-libm/sqrt.c index fd45a6f5..cdd54887 100644 --- a/jerry-libm/sqrt.c +++ b/jerry-libm/sqrt.c @@ -125,7 +125,7 @@ sqrt (double x) } else if (ix0 < 0) /* sqrt(-ve) = sNaN */ { - return (x - x) / (x - x); + return NAN; } } /* normalize x */ @@ -275,7 +275,6 @@ A. sqrt(x) by Newton Iteration ------------------------------------------------------ msb lsb msb lsb ...order - ------------------------ ------------------------ x0: |s| e | f1 | x1: | f2 | ------------------------ ------------------------ @@ -307,7 +306,6 @@ A. sqrt(x) by Newton Iteration y := (y+x/y)/2 ... almost 35 sig. bits y := y-(y-x/y)/2 ... within 1 ulp - Remark 1. Another way to improve y to within 1 ulp is: @@ -320,7 +318,6 @@ A. sqrt(x) by Newton Iteration 2 3y + x - This formula has one division fewer than the one above; however, it requires more multiplications and additions. Also x must be scaled in advance to avoid spurious overflow in evaluating the @@ -367,7 +364,6 @@ A. sqrt(x) by Newton Iteration Square root of +inf, +-0, or NaN is itself; Square root of a negative number is NaN with invalid signal. - B. sqrt(x) by Reciproot Iteration (1) Initial approximation diff --git a/jerry-libm/tanh.c b/jerry-libm/tanh.c new file mode 100644 index 00000000..b7ab527f --- /dev/null +++ b/jerry-libm/tanh.c @@ -0,0 +1,117 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_tanh.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* tanh(x) + * Return the Hyperbolic Tangent of x + * + * Method: + * x -x + * e - e + * 0. tanh(x) is defined to be ----------- + * x -x + * e + e + * + * 1. reduce x to non-negative by tanh(-x) = -tanh(x). + * 2. 0 <= x <= 2**-55 : tanh(x) := x * (one + x) + * + * -t + * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) + * t + 2 + * + * 2 + * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t = expm1(2x) + * t + 2 + * + * 22.0 < x <= INF : tanh(x) := 1. + * + * Special cases: + * tanh(NaN) is NaN; + * only tanh(0) = 0 is exact for finite x. + */ +#define one 1.0 +#define two 2.0 +#define tiny 1.0e-300 + +double +tanh (double x) +{ + double t, z; + int jx, ix; + + /* High word of |x|. */ + jx = __HI (x); + ix = jx & 0x7fffffff; + + /* x is INF or NaN */ + if (ix >= 0x7ff00000) + { + if (jx >= 0) + { + /* tanh(+-inf) = +-1 */ + return one / x + one; + } + else + { + /* tanh(NaN) = NaN */ + return one / x - one; + } + } + + /* |x| < 22 */ + if (ix < 0x40360000) + { + /* |x| < 2**-55 */ + if (ix < 0x3c800000) + { + /* tanh(small) = small */ + return x * (one + x); + } + if (ix >= 0x3ff00000) + { + /* |x| >= 1 */ + t = expm1 (two * fabs (x)); + z = one - two / (t + two); + } + else + { + t = expm1 (-two * fabs (x)); + z = -t / (t + two); + } + } + else + { + /* |x| > 22, return +-1 */ + z = one - tiny; /* raised inexact flag */ + } + return (jx >= 0) ? z : -z; +} /* tanh */ + +#undef one +#undef two +#undef tiny diff --git a/jerry-main/benchmarking.c b/jerry-main/benchmarking.c index 28546566..d4c1be5c 100644 --- a/jerry-main/benchmarking.c +++ b/jerry-main/benchmarking.c @@ -50,7 +50,6 @@ int gettimeofday (struct timeval *tv, } /* gettimeofday */ #endif /* __GNUC__ */ - int rand (void); /** diff --git a/jerry-main/cli.c b/jerry-main/cli.c index 1f8c878f..1f14ed86 100644 --- a/jerry-main/cli.c +++ b/jerry-main/cli.c @@ -112,7 +112,7 @@ cli_consume_option (cli_state_t *state_p) /**< state of the command line option state_p->arg = arg; - if (arg[0] != '-') + if (arg[0] != '-' || arg[1] == '\0') { return CLI_OPT_DEFAULT; } diff --git a/jerry-main/libfuzzer.c b/jerry-main/libfuzzer.c index 9b007c58..10de4506 100644 --- a/jerry-main/libfuzzer.c +++ b/jerry-main/libfuzzer.c @@ -17,7 +17,6 @@ #include "jerryscript.h" - int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) { srand (0); diff --git a/jerry-main/main-unix-snapshot.c b/jerry-main/main-unix-snapshot.c index 37aaab9f..9abde709 100644 --- a/jerry-main/main-unix-snapshot.c +++ b/jerry-main/main-unix-snapshot.c @@ -439,7 +439,7 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ fwrite (output_buffer, sizeof (uint8_t), snapshot_size, snapshot_file_p); fclose (snapshot_file_p); - printf ("Created snapshot file: '%s' (%lu bytes)\n", output_file_name_p, (unsigned long) snapshot_size); + printf ("Created snapshot file: '%s' (%zu bytes)\n", output_file_name_p, snapshot_size); jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_OK; diff --git a/jerry-main/main-unix-test.c b/jerry-main/main-unix-test.c index 3db77b95..0c8fd9ca 100644 --- a/jerry-main/main-unix-test.c +++ b/jerry-main/main-unix-test.c @@ -72,7 +72,12 @@ int main (int argc, char **argv) { - srand ((unsigned) jerry_port_get_current_time ()); + union + { + double d; + unsigned u; + } now = { .d = jerry_port_get_current_time () }; + srand (now.u); if (argc <= 1 || (argc == 2 && (!strcmp ("-h", argv[1]) || !strcmp ("--help", argv[1])))) { print_help (argv[0]); diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 61f1073a..367f5096 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -53,6 +53,12 @@ static const uint32_t * read_file (const char *file_name, size_t *out_size_p) { + if (file_name == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file, missing filename\n"); + return NULL; + } + FILE *file; if (!strcmp ("-", file_name)) { @@ -274,7 +280,6 @@ register_js_function (const char *name_p, /**< name of the function */ jerry_release_value (result_val); } /* register_js_function */ - /** * Runs the source code received by jerry_debugger_wait_for_client_source. * @@ -304,7 +309,6 @@ wait_for_source_callback (const jerry_char_t *resource_name_p, /**< resource nam return ret_val; } /* wait_for_source_callback */ - /** * Command line option IDs */ @@ -325,7 +329,8 @@ typedef enum OPT_EXEC_SNAP, OPT_EXEC_SNAP_FUNC, OPT_LOG_LEVEL, - OPT_NO_PROMPT + OPT_NO_PROMPT, + OPT_CALL_ON_EXIT } main_opt_id_t; /** @@ -365,8 +370,10 @@ static const cli_opt_t main_opts[] = .help = "set log level (0-3)"), CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt", .help = "don't print prompt in REPL mode"), + CLI_OPT_DEF (.id = OPT_CALL_ON_EXIT, .longopt = "call-on-exit", .meta = "STRING", + .help = "invoke the specified function when the process is just about to exit"), CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE", - .help = "input JS file(s)") + .help = "input JS file(s) (If file is -, read standard input.)") }; /** @@ -459,13 +466,19 @@ init_engine (jerry_init_flag_t flags, /**< initialized flags for the engine */ register_js_function ("assert", jerryx_handler_assert); register_js_function ("gc", jerryx_handler_gc); register_js_function ("print", jerryx_handler_print); + register_js_function ("resourceName", jerryx_handler_resource_name); } /* init_engine */ int main (int argc, char **argv) { - srand ((unsigned) jerry_port_get_current_time ()); + union + { + double d; + unsigned u; + } now = { .d = jerry_port_get_current_time () }; + srand (now.u); JERRY_VLA (const char *, file_names, argc); int files_counter = 0; @@ -487,6 +500,8 @@ main (int argc, bool is_wait_mode = false; bool no_prompt = false; + const char *exit_cb = NULL; + cli_state_t cli_state = cli_init (main_opts, argc - 1, argv + 1); for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state)) { @@ -529,6 +544,11 @@ main (int argc, } break; } + case OPT_CALL_ON_EXIT: + { + exit_cb = cli_consume_string (&cli_state); + break; + } case OPT_SHOW_RE_OP: { if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg)) @@ -880,33 +900,44 @@ main (int argc, } /* Evaluate the line */ - jerry_value_t ret_val_eval = jerry_eval (buffer, len, JERRY_PARSE_NO_OPTS); + jerry_value_t ret_val = jerry_parse (NULL, + 0, + buffer, + len, + JERRY_PARSE_NO_OPTS); - if (!jerry_value_is_error (ret_val_eval)) + if (!jerry_value_is_error (ret_val)) + { + jerry_value_t func_val = ret_val; + ret_val = jerry_run (func_val); + jerry_release_value (func_val); + } + + if (!jerry_value_is_error (ret_val)) { /* Print return value */ - const jerry_value_t args[] = { ret_val_eval }; + const jerry_value_t args[] = { ret_val }; jerry_value_t ret_val_print = jerryx_handler_print (jerry_create_undefined (), jerry_create_undefined (), args, 1); jerry_release_value (ret_val_print); - jerry_release_value (ret_val_eval); - ret_val_eval = jerry_run_all_enqueued_jobs (); + jerry_release_value (ret_val); + ret_val = jerry_run_all_enqueued_jobs (); - if (jerry_value_is_error (ret_val_eval)) + if (jerry_value_is_error (ret_val)) { - ret_val_eval = jerry_get_value_from_error (ret_val_eval, true); - print_unhandled_exception (ret_val_eval); + ret_val = jerry_get_value_from_error (ret_val, true); + print_unhandled_exception (ret_val); } } else { - ret_val_eval = jerry_get_value_from_error (ret_val_eval, true); - print_unhandled_exception (ret_val_eval); + ret_val = jerry_get_value_from_error (ret_val, true); + print_unhandled_exception (ret_val); } - jerry_release_value (ret_val_eval); + jerry_release_value (ret_val); } } } @@ -934,6 +965,32 @@ main (int argc, jerry_release_value (ret_value); + if (exit_cb != NULL) + { + jerry_value_t global = jerry_get_global_object (); + jerry_value_t fn_str = jerry_create_string ((jerry_char_t *) exit_cb); + jerry_value_t callback_fn = jerry_get_property (global, fn_str); + + jerry_release_value (global); + jerry_release_value (fn_str); + + if (jerry_value_is_function (callback_fn)) + { + jerry_value_t ret_val = jerry_call_function (callback_fn, jerry_create_undefined (), NULL, 0); + + if (jerry_value_is_error (ret_val)) + { + ret_val = jerry_get_value_from_error (ret_val, true); + print_unhandled_exception (ret_val); + ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + jerry_release_value (ret_val); + } + + jerry_release_value (callback_fn); + } + jerry_cleanup (); #if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) free (context_p); diff --git a/jerry-port/default/BUILD.gn b/jerry-port/default/BUILD.gn index 26e26b02..7df0d7c4 100755 --- a/jerry-port/default/BUILD.gn +++ b/jerry-port/default/BUILD.gn @@ -1,37 +1,35 @@ -# Copyright (c) 2020 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build/lite/config/component/lite_component.gni") -import("//third_party/jerryscript/engine.gni") - -lite_component("jerry-port-default") { - features = [ - ":jerry-port-default_shared", - ] -} - -lite_library("jerry-port-default_shared") { - target_type = "shared_library" - sources = [ - "default-date.c", - "default-module.c", - "default-fatal.c", - "default-io.c", - "default-debugger.c", - "default-external-context.c", - ] - include_dirs = [ - "include", - "${core_path}/include", - ] -} +# Copyright (c) 2020 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/lite/config/component/lite_component.gni") +import("//third_party/jerryscript/engine.gni") + +lite_component("jerry-port-default") { + features = [ ":jerry-port-default_shared" ] +} + +lite_library("jerry-port-default_shared") { + target_type = "shared_library" + sources = [ + "default-date.c", + "default-debugger.c", + "default-external-context.c", + "default-fatal.c", + "default-io.c", + "default-module.c", + ] + include_dirs = [ + "include", + "${core_path}/include", + ] +} diff --git a/jerry-port/default/default-date.c b/jerry-port/default/default-date.c index 61ea6487..2cd20616 100755 --- a/jerry-port/default/default-date.c +++ b/jerry-port/default/default-date.c @@ -50,7 +50,6 @@ static void UnixTimeToFileTime (LONGLONG t, LPFILETIME pft) } /* UnixTimeToFileTime */ #endif /* _WIN32 */ - /** * Default implementation of jerry_port_get_local_time_zone_adjustment. Uses the 'tm_gmtoff' field * of 'struct tm' (a GNU extension) filled by 'localtime_r' if available on the diff --git a/targets/curie_bsp/jerry_app/quark/main.c b/targets/curie_bsp/jerry_app/quark/main.c index 2aee9143..2975bbb0 100644 --- a/targets/curie_bsp/jerry_app/quark/main.c +++ b/targets/curie_bsp/jerry_app/quark/main.c @@ -136,7 +136,8 @@ void eval_jerry_script (int argc, char *argv[], struct tcmd_handler_ctx *ctx) void jerry_start () { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init (JERRY_INIT_EMPTY); jerry_value_t global_obj_val = jerry_get_global_object (); jerry_value_t print_func_name_val = jerry_create_string ((jerry_char_t *) "print"); diff --git a/targets/esp8266/user/jerry_run.c b/targets/esp8266/user/jerry_run.c index ab70ff76..e7fff4c3 100644 --- a/targets/esp8266/user/jerry_run.c +++ b/targets/esp8266/user/jerry_run.c @@ -26,7 +26,8 @@ static const char* fn_sys_loop_name = "sysloop"; void js_entry () { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init (JERRY_INIT_EMPTY); js_register_functions (); diff --git a/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp b/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp index 1acf2f16..4c70be88 100644 --- a/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp +++ b/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp @@ -68,7 +68,8 @@ static int load_javascript() { } int jsmbed_js_init() { - srand ((unsigned) jerry_port_get_current_time()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init_flag_t flags = JERRY_INIT_EMPTY; jerry_init(flags); diff --git a/targets/mbedos5/source/jerry_port_mbed.c b/targets/mbedos5/source/jerry_port_mbed.c index 35726471..687b0f89 100644 --- a/targets/mbedos5/source/jerry_port_mbed.c +++ b/targets/mbedos5/source/jerry_port_mbed.c @@ -79,7 +79,7 @@ jerry_port_get_current_time (void) * are within the mentioned 71 mins. Above that interval we can assume * that the milliseconds part of the time is negligibe. */ - if (curr_time - last_time > (time_t)(((uint32_t)-1) / 1000000)) { + if (curr_time - last_time > (time_t) (((uint32_t) - 1) / 1000000)) { skew = 0; } else if (last_tick > curr_tick) { skew = (skew + 33) % 1000; diff --git a/targets/riot-stm32f4/source/main-riotos.c b/targets/riot-stm32f4/source/main-riotos.c index d77aa274..28b9df84 100644 --- a/targets/riot-stm32f4/source/main-riotos.c +++ b/targets/riot-stm32f4/source/main-riotos.c @@ -98,7 +98,8 @@ const shell_command_t shell_commands[] = { int main (void) { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); printf ("You are running RIOT on a(n) %s board.\n", RIOT_BOARD); printf ("This board features a(n) %s MCU.\n", RIOT_MCU); diff --git a/targets/zephyr/Makefile.travis b/targets/zephyr/Makefile.travis index b2ae3d56..9e03e594 100644 --- a/targets/zephyr/Makefile.travis +++ b/targets/zephyr/Makefile.travis @@ -23,7 +23,7 @@ all: # Install tools via apt. install-apt-get-deps: - sudo apt-get install -q -y gperf dfu-util device-tree-compiler python3-ply python3-pip + sudo apt-get install -q -y gperf dfu-util device-tree-compiler # Install Zephyr SDK. install-zephyr-sdk: @@ -33,13 +33,13 @@ install-zephyr-sdk: # Fetch Zephyr Project repository and install python dependencies. install-zephyr: git clone https://github.com/zephyrproject-rtos/zephyr.git ../zephyr -b v1.14-branch - pip3 install --user -U pip - pip3 install --user -U setuptools - pip3 install --user -r ../zephyr/scripts/requirements.txt + pip3 install -U pip + pip3 install -U setuptools + pip3 install -r ../zephyr/scripts/requirements.txt # Install recent CMake install-cmake: - pip install --user cmake + pip install cmake cmake --version # Perform all the necessary (JerryScript-independent) installation steps. diff --git a/targets/zephyr/src/main-zephyr.c b/targets/zephyr/src/main-zephyr.c index 6ea0b846..e250f9d3 100644 --- a/targets/zephyr/src/main-zephyr.c +++ b/targets/zephyr/src/main-zephyr.c @@ -79,7 +79,8 @@ static int shell_cmd_handler (char *source_buffer) void main (void) { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); uint32_t zephyr_ver = sys_kernel_version_get (); printf ("JerryScript build: " __DATE__ " " __TIME__ "\n"); printf ("JerryScript API %d.%d.%d\n", JERRY_API_MAJOR_VERSION, JERRY_API_MINOR_VERSION, JERRY_API_PATCH_VERSION); diff --git a/tests/.gitattributes b/tests/.gitattributes new file mode 100644 index 00000000..6246e49c --- /dev/null +++ b/tests/.gitattributes @@ -0,0 +1,2 @@ +*.js text eol=lf +jerry/windows-line-ending.js text eol=crlf diff --git a/tests/debugger/do_eval_at.cmd b/tests/debugger/do_eval_at.cmd index 85bb5d43..095ef155 100644 --- a/tests/debugger/do_eval_at.cmd +++ b/tests/debugger/do_eval_at.cmd @@ -4,14 +4,14 @@ n eval_at 0 b b do_eval_at.js:20 n -scopes +scope eval_at 0 b eval_at 1 b eval_at 0 b=20 eval_at 1 b=100 n eval_at 0 a -scopes +scope eval_at 0 b eval_at -1 b eval_at 65536 b diff --git a/tests/debugger/do_eval_at.expected b/tests/debugger/do_eval_at.expected index b0db16fe..3e724a4d 100644 --- a/tests/debugger/do_eval_at.expected +++ b/tests/debugger/do_eval_at.expected @@ -12,7 +12,7 @@ Stopped at tests/debugger/do_eval_at.js:23 Breakpoint 1 at tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1) (jerry-debugger) n Stopped at breakpoint:1 tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1) -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | local 1 | global @@ -28,7 +28,7 @@ level | type Stopped at tests/debugger/do_eval_at.js:25 (jerry-debugger) eval_at 0 a 23 -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | global (jerry-debugger) eval_at 0 b diff --git a/tests/debugger/do_help.expected b/tests/debugger/do_help.expected index 26cde448..4e38137b 100644 --- a/tests/debugger/do_help.expected +++ b/tests/debugger/do_help.expected @@ -4,10 +4,10 @@ Stopped at tests/debugger/do_help.js:15 Documented commands (type help ): ======================================== -abort c e finish n s step -b continue eval help next scopes throw -backtrace delete eval_at list quit scroll variables -break display exception memstats res source -bt dump f ms restart src +EOF bt dump f ms restart src +abort c e finish n s step +b continue eval help next scope throw +backtrace delete eval_at list quit scroll variables +break display exception memstats res source (jerry-debugger) quit diff --git a/tests/debugger/do_scope.cmd b/tests/debugger/do_scope.cmd new file mode 100644 index 00000000..d19987b7 --- /dev/null +++ b/tests/debugger/do_scope.cmd @@ -0,0 +1,19 @@ +scope +b do_scope.js:22 +c +scope +c +scope +b do_scope.js:28 +c +scope +b do_scope.js:31 +c +scope +b do_scope.js:33 +c +scope +b do_scope.js:35 +c +scope +c diff --git a/tests/debugger/do_scope.expected b/tests/debugger/do_scope.expected new file mode 100644 index 00000000..c595056b --- /dev/null +++ b/tests/debugger/do_scope.expected @@ -0,0 +1,63 @@ +Connecting to: localhost:5001 +Stopped at tests/debugger/do_scope.js:15 +(jerry-debugger) scope +level | type +0 | global +(jerry-debugger) b do_scope.js:22 +Breakpoint 1 at tests/debugger/do_scope.js:22 (in f() at line:17, col:1) +(jerry-debugger) c +Exception throw detected (to disable automatic stop type exception 0) +Exception hint: error +Stopped at tests/debugger/do_scope.js:19 (in f() at line:17, col:1) +(jerry-debugger) scope +level | type +0 | local +1 | global +(jerry-debugger) c +Stopped at breakpoint:1 tests/debugger/do_scope.js:22 (in f() at line:17, col:1) +(jerry-debugger) scope +level | type +0 | catch +1 | local +2 | global +(jerry-debugger) b do_scope.js:28 +Breakpoint 2 at tests/debugger/do_scope.js:28 (in function() at line:27, col:4) +(jerry-debugger) c +Stopped at breakpoint:2 tests/debugger/do_scope.js:28 (in function() at line:27, col:4) +(jerry-debugger) scope +level | type +0 | local +1 | closure +2 | global +(jerry-debugger) b do_scope.js:31 +Breakpoint 3 at tests/debugger/do_scope.js:31 (in function() at line:27, col:4) +(jerry-debugger) c +Stopped at breakpoint:3 tests/debugger/do_scope.js:31 (in function() at line:27, col:4) +(jerry-debugger) scope +level | type +0 | with +1 | local +2 | closure +3 | global +(jerry-debugger) b do_scope.js:33 +Breakpoint 4 at tests/debugger/do_scope.js:33 (in function() at line:27, col:4) +(jerry-debugger) c +Stopped at breakpoint:4 tests/debugger/do_scope.js:33 (in function() at line:27, col:4) +(jerry-debugger) scope +level | type +0 | with +1 | with +2 | local +3 | closure +4 | global +(jerry-debugger) b do_scope.js:35 +Breakpoint 5 at tests/debugger/do_scope.js:35 (in function() at line:27, col:4) +(jerry-debugger) c +Stopped at breakpoint:5 tests/debugger/do_scope.js:35 (in function() at line:27, col:4) +(jerry-debugger) scope +level | type +0 | with +1 | local +2 | closure +3 | global +(jerry-debugger) c diff --git a/tests/debugger/do_scopes.js b/tests/debugger/do_scope.js similarity index 100% rename from tests/debugger/do_scopes.js rename to tests/debugger/do_scope.js diff --git a/tests/debugger/do_scopes.cmd b/tests/debugger/do_scopes.cmd deleted file mode 100644 index 69a869c9..00000000 --- a/tests/debugger/do_scopes.cmd +++ /dev/null @@ -1,19 +0,0 @@ -scopes -b do_scopes.js:22 -c -scopes -c -scopes -b do_scopes.js:28 -c -scopes -b do_scopes.js:31 -c -scopes -b do_scopes.js:33 -c -scopes -b do_scopes.js:35 -c -scopes -c diff --git a/tests/debugger/do_scopes.expected b/tests/debugger/do_scopes.expected deleted file mode 100644 index 84e761d3..00000000 --- a/tests/debugger/do_scopes.expected +++ /dev/null @@ -1,63 +0,0 @@ -Connecting to: localhost:5001 -Stopped at tests/debugger/do_scopes.js:15 -(jerry-debugger) scopes -level | type -0 | global -(jerry-debugger) b do_scopes.js:22 -Breakpoint 1 at tests/debugger/do_scopes.js:22 (in f() at line:17, col:1) -(jerry-debugger) c -Exception throw detected (to disable automatic stop type exception 0) -Exception hint: error -Stopped at tests/debugger/do_scopes.js:19 (in f() at line:17, col:1) -(jerry-debugger) scopes -level | type -0 | local -1 | global -(jerry-debugger) c -Stopped at breakpoint:1 tests/debugger/do_scopes.js:22 (in f() at line:17, col:1) -(jerry-debugger) scopes -level | type -0 | catch -1 | local -2 | global -(jerry-debugger) b do_scopes.js:28 -Breakpoint 2 at tests/debugger/do_scopes.js:28 (in function() at line:27, col:4) -(jerry-debugger) c -Stopped at breakpoint:2 tests/debugger/do_scopes.js:28 (in function() at line:27, col:4) -(jerry-debugger) scopes -level | type -0 | local -1 | closure -2 | global -(jerry-debugger) b do_scopes.js:31 -Breakpoint 3 at tests/debugger/do_scopes.js:31 (in function() at line:27, col:4) -(jerry-debugger) c -Stopped at breakpoint:3 tests/debugger/do_scopes.js:31 (in function() at line:27, col:4) -(jerry-debugger) scopes -level | type -0 | with -1 | local -2 | closure -3 | global -(jerry-debugger) b do_scopes.js:33 -Breakpoint 4 at tests/debugger/do_scopes.js:33 (in function() at line:27, col:4) -(jerry-debugger) c -Stopped at breakpoint:4 tests/debugger/do_scopes.js:33 (in function() at line:27, col:4) -(jerry-debugger) scopes -level | type -0 | with -1 | with -2 | local -3 | closure -4 | global -(jerry-debugger) b do_scopes.js:35 -Breakpoint 5 at tests/debugger/do_scopes.js:35 (in function() at line:27, col:4) -(jerry-debugger) c -Stopped at breakpoint:5 tests/debugger/do_scopes.js:35 (in function() at line:27, col:4) -(jerry-debugger) scopes -level | type -0 | with -1 | local -2 | closure -3 | global -(jerry-debugger) c diff --git a/tests/debugger/do_src.expected b/tests/debugger/do_src.expected index 18e80a65..b023ef3c 100644 --- a/tests/debugger/do_src.expected +++ b/tests/debugger/do_src.expected @@ -17,5 +17,7 @@ Stopped at tests/debugger/do_src.js:21 (jerry-debugger) step Stopped at :2 (in f() at line:1, col:5) (jerry-debugger) src + 1 f = function f() { + 2 > print('F2') } (jerry-debugger) c out: F2 diff --git a/tests/debugger/do_variables.cmd b/tests/debugger/do_variables.cmd index a9b02082..93d182e9 100644 --- a/tests/debugger/do_variables.cmd +++ b/tests/debugger/do_variables.cmd @@ -1,27 +1,27 @@ -scopes +scope variables variables 1 variables 0 b tests/debugger/do_variables.js:20 c -scopes +scope variables 0 variables 1 variables 2 b tests/debugger/do_variables.js:30 c -scopes +scope variables 1 variables 0 b tests/debugger/do_variables.js:33 c c -scopes +scope variables 0 variables 1 b tests/debugger/do_variables.js:50 c -scopes +scope variables 0 variables 1 variables 2 diff --git a/tests/debugger/do_variables.expected b/tests/debugger/do_variables.expected index b450d205..3d500a71 100644 --- a/tests/debugger/do_variables.expected +++ b/tests/debugger/do_variables.expected @@ -1,73 +1,77 @@ Connecting to: localhost:5001 Stopped at tests/debugger/do_variables.js:15 -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | global (jerry-debugger) variables -name | type | value -f | Function | -addX | Function | -z | undefined | undefined -c | undefined | undefined -print | Function | -gc | Function | -assert | Function | +name | type | value +f | Function | +addX | Function | +z | undefined | undefined +c | undefined | undefined +resourceName | Function | +print | Function | +gc | Function | +assert | Function | (jerry-debugger) variables 1 name | type | value (jerry-debugger) variables 0 -name | type | value -f | Function | -addX | Function | -z | undefined | undefined -c | undefined | undefined -print | Function | -gc | Function | -assert | Function | +name | type | value +f | Function | +addX | Function | +z | undefined | undefined +c | undefined | undefined +resourceName | Function | +print | Function | +gc | Function | +assert | Function | (jerry-debugger) b tests/debugger/do_variables.js:20 Breakpoint 1 at tests/debugger/do_variables.js:20 (in function() at line:19, col:10) (jerry-debugger) c Stopped at breakpoint:1 tests/debugger/do_variables.js:20 (in function() at line:19, col:10) -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | local 1 | closure 2 | global (jerry-debugger) variables 0 name | type | value -n | Number | 9 b | undefined | undefined +n | Number | 9 (jerry-debugger) variables 1 name | type | value x | Number | 3 (jerry-debugger) variables 2 -name | type | value -addThree | Function | -f | Function | -addX | Function | -z | Number | 5 -c | Number | 4 -print | Function | -gc | Function | -assert | Function | +name | type | value +addThree | Function | +f | Function | +addX | Function | +z | Number | 5 +c | Number | 4 +resourceName | Function | +print | Function | +gc | Function | +assert | Function | (jerry-debugger) b tests/debugger/do_variables.js:30 Breakpoint 2 at tests/debugger/do_variables.js:30 (in f() at line:28, col:1) (jerry-debugger) c Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1) -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | local 1 | global (jerry-debugger) variables 1 -name | type | value -d | Number | 12 -addThree | Function | -f | Function | -addX | Function | -z | Number | 5 -c | Number | 4 -print | Function | -gc | Function | -assert | Function | +name | type | value +d | Number | 12 +addThree | Function | +f | Function | +addX | Function | +z | Number | 5 +c | Number | 4 +resourceName | Function | +print | Function | +gc | Function | +assert | Function | (jerry-debugger) variables 0 name | type | value b | undefined | undefined @@ -83,7 +87,7 @@ Exception hint: error Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1) (jerry-debugger) c Stopped at breakpoint:3 tests/debugger/do_variables.js:33 (in f() at line:28, col:1) -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | catch 1 | local @@ -102,7 +106,7 @@ c | undefined | undefined Breakpoint 4 at tests/debugger/do_variables.js:50 (in function() at line:46, col:4) (jerry-debugger) c Stopped at breakpoint:4 tests/debugger/do_variables.js:50 (in function() at line:46, col:4) -(jerry-debugger) scopes +(jerry-debugger) scope level | type 0 | with 1 | local diff --git a/tests/jerry-test-suite/07/07.06/07.06.01/07.06.01-001.js b/tests/jerry-test-suite/07/07.06/07.06.01/07.06.01-001.js index d0e33f88..23e8d133 100644 --- a/tests/jerry-test-suite/07/07.06/07.06.01/07.06.01-001.js +++ b/tests/jerry-test-suite/07/07.06/07.06.01/07.06.01-001.js @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -var let = 1; +var package = 1; diff --git a/tests/jerry-test-suite/es2015/15.03.04.02-001.js b/tests/jerry-test-suite/es2015/15.03.04.02-001.js new file mode 100644 index 00000000..bf15596d --- /dev/null +++ b/tests/jerry-test-suite/es2015/15.03.04.02-001.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(Function.prototype.toString.hasOwnProperty('length')); +assert(delete Function.prototype.toString.length); +assert(!Function.prototype.toString.hasOwnProperty('length')); diff --git a/tests/jerry-test-suite/es2015/15.03.04.02-004.js b/tests/jerry-test-suite/es2015/15.03.04.02-004.js new file mode 100644 index 00000000..bf15596d --- /dev/null +++ b/tests/jerry-test-suite/es2015/15.03.04.02-004.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(Function.prototype.toString.hasOwnProperty('length')); +assert(delete Function.prototype.toString.length); +assert(!Function.prototype.toString.hasOwnProperty('length')); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js index 0b3218aa..b5f194be 100644 --- a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js @@ -13,4 +13,4 @@ * limitations under the License. */ -assert (Promise.prototype.length === 1); +assert (Promise.length === 1); diff --git a/tests/jerry-test-suite/13/13.02/13.02-002.js b/tests/jerry-test-suite/es5.1/13.02-002.js similarity index 100% rename from tests/jerry-test-suite/13/13.02/13.02-002.js rename to tests/jerry-test-suite/es5.1/13.02-002.js diff --git a/tests/jerry-test-suite/15/15.03/15.03.04/15.03.04.02/15.03.04.02-001.js b/tests/jerry-test-suite/es5.1/15.03.04.02-001.js similarity index 100% rename from tests/jerry-test-suite/15/15.03/15.03.04/15.03.04.02/15.03.04.02-001.js rename to tests/jerry-test-suite/es5.1/15.03.04.02-001.js diff --git a/tests/jerry-test-suite/15/15.03/15.03.04/15.03.04.02/15.03.04.02-004.js b/tests/jerry-test-suite/es5.1/15.03.04.02-004.js similarity index 100% rename from tests/jerry-test-suite/15/15.03/15.03.04/15.03.04.02/15.03.04.02-004.js rename to tests/jerry-test-suite/es5.1/15.03.04.02-004.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-004.js b/tests/jerry-test-suite/es5.1/15.07.03.01-004.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-004.js rename to tests/jerry-test-suite/es5.1/15.07.03.01-004.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-008.js b/tests/jerry-test-suite/es5.1/15.07.03.01-008.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-008.js rename to tests/jerry-test-suite/es5.1/15.07.03.01-008.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-009.js b/tests/jerry-test-suite/es5.1/15.07.03.01-009.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-009.js rename to tests/jerry-test-suite/es5.1/15.07.03.01-009.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-010.js b/tests/jerry-test-suite/es5.1/15.07.03.01-010.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-010.js rename to tests/jerry-test-suite/es5.1/15.07.03.01-010.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-011.js b/tests/jerry-test-suite/es5.1/15.07.03.01-011.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.03/15.07.03.01/15.07.03.01-011.js rename to tests/jerry-test-suite/es5.1/15.07.03.01-011.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04-001.js b/tests/jerry-test-suite/es5.1/15.07.04-001.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04-001.js rename to tests/jerry-test-suite/es5.1/15.07.04-001.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04-002.js b/tests/jerry-test-suite/es5.1/15.07.04-002.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04-002.js rename to tests/jerry-test-suite/es5.1/15.07.04-002.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.02/15.07.04.02-006.js b/tests/jerry-test-suite/es5.1/15.07.04.02-006.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.02/15.07.04.02-006.js rename to tests/jerry-test-suite/es5.1/15.07.04.02-006.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.02/15.07.04.02-008.js b/tests/jerry-test-suite/es5.1/15.07.04.02-008.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.02/15.07.04.02-008.js rename to tests/jerry-test-suite/es5.1/15.07.04.02-008.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-001.js b/tests/jerry-test-suite/es5.1/15.07.04.05-001.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-001.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-001.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-002.js b/tests/jerry-test-suite/es5.1/15.07.04.05-002.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-002.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-002.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-003.js b/tests/jerry-test-suite/es5.1/15.07.04.05-003.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-003.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-003.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-004.js b/tests/jerry-test-suite/es5.1/15.07.04.05-004.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-004.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-004.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-005.js b/tests/jerry-test-suite/es5.1/15.07.04.05-005.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-005.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-005.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-006.js b/tests/jerry-test-suite/es5.1/15.07.04.05-006.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-006.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-006.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-007.js b/tests/jerry-test-suite/es5.1/15.07.04.05-007.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-007.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-007.js diff --git a/tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-008.js b/tests/jerry-test-suite/es5.1/15.07.04.05-008.js similarity index 100% rename from tests/jerry-test-suite/15/15.07/15.07.04/15.07.04.05/15.07.04.05-008.js rename to tests/jerry-test-suite/es5.1/15.07.04.05-008.js diff --git a/tests/jerry-test-suite/es51-profile-list b/tests/jerry-test-suite/es51-profile-list deleted file mode 100644 index 42d0ceda..00000000 --- a/tests/jerry-test-suite/es51-profile-list +++ /dev/null @@ -1,1468 +0,0 @@ -./06/06-001.js -./06/06-002.js -./06/06-003.js -./06/06-004.js -./06/06-005.js -./07/07.06/07.06.01/07.06.01-001.js -./07/07.08/07.08.05/07.08.05-001.js -./07/07.09/07.09-001.js -./07/07.09/07.09-002.js -./07/07.09/07.09-003.js -./07/07.09/07.09-004.js -./07/07.09/07.09-005.js -./07/07.09/07.09-006.js -./07/07.09/07.09-007.js -./07/07.09/07.09-008.js -./07/07.09/07.09-009.js -./07/07.09/07.09-010.js -./08/08.01/08.01-001.js -./08/08.01/08.01-002.js -./08/08.01/08.01-003.js -./08/08.01/08.01-004.js -./08/08.01/08.01-005.js -./08/08.01/08.01-006.js -./08/08.01/08.01-007.js -./08/08.01/08.01-008.js -./08/08.01/08.01-009.js -./08/08.01/08.01-010.js -./08/08.01/08.01-011.js -./08/08.02/08.02-001.js -./08/08.02/08.02-002.js -./08/08.03/08.03-001.js -./08/08.03/08.03-002.js -./08/08.03/08.03-003.js -./08/08.03/08.03-004.js -./08/08.04/08.04-001.js -./08/08.04/08.04-002.js -./08/08.04/08.04-003.js -./08/08.04/08.04-004.js -./08/08.04/08.04-005.js -./08/08.04/08.04-006.js -./08/08.04/08.04-007.js -./08/08.04/08.04-008.js -./08/08.04/08.04-009.js -./08/08.04/08.04-010.js -./08/08.04/08.04-011.js -./08/08.04/08.04-012.js -./08/08.04/08.04-013.js -./08/08.04/08.04-014.js -./08/08.04/08.04-015.js -./08/08.04/08.04-016.js -./08/08.04/08.04-017.js -./08/08.05/08.05-001.js -./08/08.05/08.05-002.js -./08/08.05/08.05-003.js -./08/08.12/08.12.02/08.12.02-001.js -./10/10.03/10.03.01/10.03.01-001.js -./11/11.01/11.01.05/11.01.05-001.js -./11/11.01/11.01.05/11.01.05-002.js -./11/11.01/11.01.05/11.01.05-003.js -./11/11.01/11.01.05/11.01.05-004.js -./11/11.01/11.01.05/11.01.05-005.js -./11/11.01/11.01.05/11.01.05-006.js -./11/11.01/11.01.05/11.01.05-007.js -./11/11.01/11.01.05/11.01.05-008.js -./11/11.01/11.01.06/11.01.06-001.js -./11/11.01/11.01.06/11.01.06-002.js -./11/11.01/11.01.06/11.01.06-003.js -./11/11.01/11.01.06/11.01.06-004.js -./11/11.01/11.01.06/11.01.06-005.js -./11/11.01/11.01.06/11.01.06-006.js -./11/11.01/11.01.06/11.01.06-009.js -./11/11.02/11.02.01/11.02.01-001.js -./11/11.02/11.02.01/11.02.01-002.js -./11/11.02/11.02.01/11.02.01-003.js -./11/11.02/11.02.01/11.02.01-004.js -./11/11.02/11.02.01/11.02.01-007.js -./11/11.02/11.02.01/11.02.01-008.js -./11/11.02/11.02.01/11.02.01-009.js -./11/11.02/11.02.01/11.02.01-010.js -./11/11.02/11.02.01/11.02.01-011.js -./11/11.02/11.02.02/11.02.02-001.js -./11/11.02/11.02.02/11.02.02-002.js -./11/11.02/11.02.02/11.02.02-003.js -./11/11.02/11.02.02/11.02.02-004.js -./11/11.02/11.02.02/11.02.02-005.js -./11/11.02/11.02.02/11.02.02-006.js -./11/11.02/11.02.02/11.02.02-007.js -./11/11.02/11.02.02/11.02.02-008.js -./11/11.02/11.02.02/11.02.02-009.js -./11/11.02/11.02.03/11.02.03-006.js -./11/11.02/11.02.03/11.02.03-007.js -./11/11.02/11.02.03/11.02.03-008.js -./11/11.02/11.02.03/11.02.03-017.js -./11/11.02/11.02.03/11.02.03-021.js -./11/11.02/11.02.04/11.02.04-001.js -./11/11.02/11.02.04/11.02.04-002.js -./11/11.02/11.02.04/11.02.04-003.js -./11/11.02/11.02.04/11.02.04-004.js -./11/11.02/11.02.04/11.02.04-005.js -./11/11.02/11.02.04/11.02.04-006.js -./11/11.02/11.02.04/11.02.04-007.js -./11/11.02/11.02.04/11.02.04-008.js -./11/11.02/11.02.04/11.02.04-009.js -./11/11.02/11.02.04/11.02.04-010.js -./11/11.02/11.02.04/11.02.04-011.js -./11/11.02/11.02.04/11.02.04-012.js -./11/11.02/11.02.04/11.02.04-013.js -./11/11.02/11.02.04/11.02.04-014.js -./11/11.02/11.02.04/11.02.04-016.js -./11/11.02/11.02.04/11.02.04-017.js -./11/11.02/11.02.04/11.02.04-018.js -./11/11.02/11.02.04/11.02.04-019.js -./11/11.03/11.03.01/11.03.01-005.js -./11/11.03/11.03.01/11.03.01-006.js -./11/11.03/11.03.01/11.03.01-007.js -./11/11.03/11.03.01/11.03.01-008.js -./11/11.03/11.03.01/11.03.01-009.js -./11/11.03/11.03.01/11.03.01-010.js -./11/11.03/11.03.01/11.03.01-011.js -./11/11.03/11.03.01/11.03.01-012.js -./11/11.03/11.03.01/11.03.01-013.js -./11/11.03/11.03.01/11.03.01-014.js -./11/11.03/11.03.01/11.03.01-015.js -./11/11.03/11.03.01/11.03.01-016.js -./11/11.03/11.03.02/11.03.02-005.js -./11/11.03/11.03.02/11.03.02-006.js -./11/11.03/11.03.02/11.03.02-007.js -./11/11.03/11.03.02/11.03.02-008.js -./11/11.03/11.03.02/11.03.02-009.js -./11/11.03/11.03.02/11.03.02-010.js -./11/11.03/11.03.02/11.03.02-011.js -./11/11.03/11.03.02/11.03.02-012.js -./11/11.03/11.03.02/11.03.02-013.js -./11/11.03/11.03.02/11.03.02-014.js -./11/11.03/11.03.02/11.03.02-015.js -./11/11.03/11.03.02/11.03.02-016.js -./11/11.04/11.04.01/11.04.01-001.js -./11/11.04/11.04.01/11.04.01-002.js -./11/11.04/11.04.01/11.04.01-003.js -./11/11.04/11.04.01/11.04.01-004.js -./11/11.04/11.04.01/11.04.01-005.js -./11/11.04/11.04.01/11.04.01-006.js -./11/11.04/11.04.01/11.04.01-007.js -./11/11.04/11.04.01/11.04.01-008.js -./11/11.04/11.04.01/11.04.01-009.js -./11/11.04/11.04.01/11.04.01-010.js -./11/11.04/11.04.01/11.04.01-011.js -./11/11.04/11.04.01/11.04.01-012.js -./11/11.04/11.04.01/11.04.01-013.js -./11/11.04/11.04.01/11.04.01-017.js -./11/11.04/11.04.02/11.04.02-001.js -./11/11.04/11.04.02/11.04.02-002.js -./11/11.04/11.04.03/11.04.03-001.js -./11/11.04/11.04.03/11.04.03-002.js -./11/11.04/11.04.03/11.04.03-003.js -./11/11.04/11.04.03/11.04.03-004.js -./11/11.04/11.04.03/11.04.03-005.js -./11/11.04/11.04.03/11.04.03-006.js -./11/11.04/11.04.03/11.04.03-007.js -./11/11.04/11.04.03/11.04.03-008.js -./11/11.04/11.04.03/11.04.03-009.js -./11/11.04/11.04.03/11.04.03-010.js -./11/11.04/11.04.03/11.04.03-011.js -./11/11.04/11.04.03/11.04.03-012.js -./11/11.04/11.04.03/11.04.03-013.js -./11/11.04/11.04.03/11.04.03-016.js -./11/11.04/11.04.04/11.04.04-001.js -./11/11.04/11.04.04/11.04.04-002.js -./11/11.04/11.04.04/11.04.04-004.js -./11/11.04/11.04.04/11.04.04-005.js -./11/11.04/11.04.04/11.04.04-006.js -./11/11.04/11.04.04/11.04.04-007.js -./11/11.04/11.04.04/11.04.04-008.js -./11/11.04/11.04.04/11.04.04-009.js -./11/11.04/11.04.04/11.04.04-010.js -./11/11.04/11.04.04/11.04.04-011.js -./11/11.04/11.04.04/11.04.04-012.js -./11/11.04/11.04.05/11.04.05-001.js -./11/11.04/11.04.05/11.04.05-002.js -./11/11.04/11.04.05/11.04.05-004.js -./11/11.04/11.04.05/11.04.05-005.js -./11/11.04/11.04.05/11.04.05-006.js -./11/11.04/11.04.05/11.04.05-007.js -./11/11.04/11.04.05/11.04.05-008.js -./11/11.04/11.04.05/11.04.05-009.js -./11/11.04/11.04.05/11.04.05-010.js -./11/11.04/11.04.05/11.04.05-011.js -./11/11.04/11.04.05/11.04.05-012.js -./11/11.04/11.04.06/11.04.06-001.js -./11/11.04/11.04.06/11.04.06-002.js -./11/11.04/11.04.06/11.04.06-003.js -./11/11.04/11.04.06/11.04.06-004.js -./11/11.04/11.04.06/11.04.06-005.js -./11/11.04/11.04.06/11.04.06-006.js -./11/11.04/11.04.06/11.04.06-007.js -./11/11.04/11.04.06/11.04.06-008.js -./11/11.04/11.04.06/11.04.06-009.js -./11/11.04/11.04.06/11.04.06-010.js -./11/11.04/11.04.06/11.04.06-011.js -./11/11.04/11.04.06/11.04.06-012.js -./11/11.04/11.04.06/11.04.06-013.js -./11/11.04/11.04.06/11.04.06-014.js -./11/11.04/11.04.06/11.04.06-015.js -./11/11.04/11.04.06/11.04.06-016.js -./11/11.04/11.04.06/11.04.06-017.js -./11/11.04/11.04.06/11.04.06-018.js -./11/11.04/11.04.06/11.04.06-019.js -./11/11.04/11.04.06/11.04.06-020.js -./11/11.04/11.04.06/11.04.06-021.js -./11/11.04/11.04.06/11.04.06-022.js -./11/11.04/11.04.06/11.04.06-023.js -./11/11.04/11.04.06/11.04.06-024.js -./11/11.04/11.04.06/11.04.06-025.js -./11/11.04/11.04.06/11.04.06-026.js -./11/11.04/11.04.06/11.04.06-027.js -./11/11.04/11.04.06/11.04.06-028.js -./11/11.04/11.04.07/11.04.07-001.js -./11/11.04/11.04.07/11.04.07-002.js -./11/11.04/11.04.07/11.04.07-003.js -./11/11.04/11.04.07/11.04.07-004.js -./11/11.04/11.04.07/11.04.07-005.js -./11/11.04/11.04.07/11.04.07-006.js -./11/11.04/11.04.07/11.04.07-007.js -./11/11.04/11.04.07/11.04.07-008.js -./11/11.04/11.04.07/11.04.07-009.js -./11/11.04/11.04.07/11.04.07-010.js -./11/11.04/11.04.07/11.04.07-011.js -./11/11.04/11.04.07/11.04.07-012.js -./11/11.04/11.04.07/11.04.07-013.js -./11/11.04/11.04.07/11.04.07-014.js -./11/11.04/11.04.07/11.04.07-015.js -./11/11.04/11.04.07/11.04.07-016.js -./11/11.04/11.04.07/11.04.07-017.js -./11/11.04/11.04.07/11.04.07-018.js -./11/11.04/11.04.07/11.04.07-019.js -./11/11.04/11.04.07/11.04.07-020.js -./11/11.04/11.04.07/11.04.07-021.js -./11/11.04/11.04.07/11.04.07-022.js -./11/11.04/11.04.07/11.04.07-023.js -./11/11.04/11.04.07/11.04.07-024.js -./11/11.04/11.04.07/11.04.07-025.js -./11/11.04/11.04.07/11.04.07-026.js -./11/11.04/11.04.07/11.04.07-027.js -./11/11.04/11.04.07/11.04.07-028.js -./11/11.04/11.04.07/11.04.07-029.js -./11/11.04/11.04.07/11.04.07-030.js -./11/11.04/11.04.07/11.04.07-031.js -./11/11.04/11.04.07/11.04.07-032.js -./11/11.04/11.04.07/11.04.07-033.js -./11/11.04/11.04.08/11.04.08-001.js -./11/11.04/11.04.08/11.04.08-002.js -./11/11.04/11.04.08/11.04.08-003.js -./11/11.04/11.04.08/11.04.08-004.js -./11/11.04/11.04.08/11.04.08-005.js -./11/11.04/11.04.08/11.04.08-006.js -./11/11.04/11.04.08/11.04.08-007.js -./11/11.04/11.04.08/11.04.08-008.js -./11/11.04/11.04.08/11.04.08-009.js -./11/11.04/11.04.08/11.04.08-010.js -./11/11.04/11.04.08/11.04.08-011.js -./11/11.04/11.04.08/11.04.08-012.js -./11/11.04/11.04.08/11.04.08-013.js -./11/11.04/11.04.08/11.04.08-014.js -./11/11.04/11.04.08/11.04.08-015.js -./11/11.04/11.04.08/11.04.08-016.js -./11/11.04/11.04.08/11.04.08-017.js -./11/11.04/11.04.08/11.04.08-018.js -./11/11.04/11.04.08/11.04.08-019.js -./11/11.04/11.04.08/11.04.08-020.js -./11/11.04/11.04.08/11.04.08-021.js -./11/11.04/11.04.08/11.04.08-022.js -./11/11.04/11.04.09/11.04.09-001.js -./11/11.04/11.04.09/11.04.09-002.js -./11/11.04/11.04.09/11.04.09-003.js -./11/11.04/11.04.09/11.04.09-004.js -./11/11.04/11.04.09/11.04.09-005.js -./11/11.04/11.04.09/11.04.09-006.js -./11/11.04/11.04.09/11.04.09-007.js -./11/11.04/11.04.09/11.04.09-008.js -./11/11.04/11.04.09/11.04.09-009.js -./11/11.04/11.04.09/11.04.09-010.js -./11/11.04/11.04.09/11.04.09-011.js -./11/11.04/11.04.09/11.04.09-012.js -./11/11.04/11.04.09/11.04.09-013.js -./11/11.04/11.04.09/11.04.09-014.js -./11/11.04/11.04.09/11.04.09-015.js -./11/11.04/11.04.09/11.04.09-016.js -./11/11.04/11.04.09/11.04.09-017.js -./11/11.04/11.04.09/11.04.09-018.js -./11/11.04/11.04.09/11.04.09-019.js -./11/11.04/11.04.09/11.04.09-020.js -./11/11.05/11.05.01/11.05.01-001.js -./11/11.05/11.05.01/11.05.01-002.js -./11/11.05/11.05.01/11.05.01-003.js -./11/11.05/11.05.01/11.05.01-004.js -./11/11.05/11.05.01/11.05.01-005.js -./11/11.05/11.05.01/11.05.01-006.js -./11/11.05/11.05.01/11.05.01-007.js -./11/11.05/11.05.01/11.05.01-008.js -./11/11.05/11.05.01/11.05.01-009.js -./11/11.05/11.05.01/11.05.01-010.js -./11/11.05/11.05.01/11.05.01-011.js -./11/11.05/11.05.01/11.05.01-012.js -./11/11.05/11.05.01/11.05.01-013.js -./11/11.05/11.05.01/11.05.01-014.js -./11/11.05/11.05.01/11.05.01-015.js -./11/11.05/11.05.01/11.05.01-016.js -./11/11.05/11.05.01/11.05.01-017.js -./11/11.05/11.05.01/11.05.01-018.js -./11/11.05/11.05.01/11.05.01-019.js -./11/11.05/11.05.01/11.05.01-020.js -./11/11.05/11.05.01/11.05.01-021.js -./11/11.05/11.05.01/11.05.01-022.js -./11/11.05/11.05.01/11.05.01-023.js -./11/11.05/11.05.01/11.05.01-024.js -./11/11.05/11.05.01/11.05.01-025.js -./11/11.05/11.05.01/11.05.01-026.js -./11/11.05/11.05.01/11.05.01-027.js -./11/11.05/11.05.01/11.05.01-028.js -./11/11.05/11.05.01/11.05.01-029.js -./11/11.05/11.05.01/11.05.01-030.js -./11/11.05/11.05.01/11.05.01-031.js -./11/11.05/11.05.01/11.05.01-032.js -./11/11.05/11.05.01/11.05.01-033.js -./11/11.05/11.05.01/11.05.01-034.js -./11/11.05/11.05.01/11.05.01-035.js -./11/11.05/11.05.01/11.05.01-036.js -./11/11.05/11.05.01/11.05.01-037.js -./11/11.05/11.05.01/11.05.01-038.js -./11/11.05/11.05.01/11.05.01-039.js -./11/11.05/11.05.01/11.05.01-040.js -./11/11.05/11.05.01/11.05.01-041.js -./11/11.05/11.05.01/11.05.01-042.js -./11/11.05/11.05.01/11.05.01-043.js -./11/11.05/11.05.01/11.05.01-044.js -./11/11.05/11.05.01/11.05.01-045.js -./11/11.05/11.05.01/11.05.01-046.js -./11/11.05/11.05.01/11.05.01-047.js -./11/11.05/11.05.01/11.05.01-048.js -./11/11.05/11.05.01/11.05.01-049.js -./11/11.05/11.05.01/11.05.01-050.js -./11/11.05/11.05.01/11.05.01-051.js -./11/11.05/11.05.01/11.05.01-052.js -./11/11.05/11.05.01/11.05.01-053.js -./11/11.05/11.05.01/11.05.01-054.js -./11/11.05/11.05.01/11.05.01-055.js -./11/11.05/11.05.01/11.05.01-056.js -./11/11.05/11.05.01/11.05.01-057.js -./11/11.05/11.05.01/11.05.01-058.js -./11/11.05/11.05.01/11.05.01-059.js -./11/11.05/11.05.01/11.05.01-060.js -./11/11.05/11.05.01/11.05.01-061.js -./11/11.05/11.05.01/11.05.01-062.js -./11/11.05/11.05.01/11.05.01-063.js -./11/11.05/11.05.01/11.05.01-064.js -./11/11.05/11.05.01/11.05.01-065.js -./11/11.05/11.05.01/11.05.01-066.js -./11/11.05/11.05.01/11.05.01-067.js -./11/11.05/11.05.01/11.05.01-068.js -./11/11.05/11.05.01/11.05.01-069.js -./11/11.05/11.05.01/11.05.01-070.js -./11/11.05/11.05.01/11.05.01-071.js -./11/11.05/11.05.01/11.05.01-072.js -./11/11.05/11.05.01/11.05.01-073.js -./11/11.05/11.05.01/11.05.01-074.js -./11/11.05/11.05.01/11.05.01-075.js -./11/11.05/11.05.01/11.05.01-076.js -./11/11.05/11.05.01/11.05.01-077.js -./11/11.05/11.05.01/11.05.01-078.js -./11/11.05/11.05.01/11.05.01-079.js -./11/11.05/11.05.01/11.05.01-080.js -./11/11.05/11.05.01/11.05.01-081.js -./11/11.05/11.05.01/11.05.01-082.js -./11/11.05/11.05.01/11.05.01-083.js -./11/11.05/11.05.01/11.05.01-084.js -./11/11.05/11.05.01/11.05.01-085.js -./11/11.05/11.05.01/11.05.01-086.js -./11/11.05/11.05.01/11.05.01-087.js -./11/11.05/11.05.01/11.05.01-088.js -./11/11.05/11.05.01/11.05.01-089.js -./11/11.05/11.05.01/11.05.01-090.js -./11/11.05/11.05.02/11.05.02-001.js -./11/11.05/11.05.02/11.05.02-002.js -./11/11.05/11.05.02/11.05.02-003.js -./11/11.05/11.05.02/11.05.02-004.js -./11/11.05/11.05.02/11.05.02-005.js -./11/11.05/11.05.02/11.05.02-006.js -./11/11.05/11.05.02/11.05.02-007.js -./11/11.05/11.05.02/11.05.02-008.js -./11/11.05/11.05.02/11.05.02-009.js -./11/11.05/11.05.02/11.05.02-010.js -./11/11.05/11.05.02/11.05.02-011.js -./11/11.05/11.05.02/11.05.02-012.js -./11/11.05/11.05.02/11.05.02-013.js -./11/11.05/11.05.02/11.05.02-014.js -./11/11.05/11.05.02/11.05.02-015.js -./11/11.05/11.05.02/11.05.02-016.js -./11/11.05/11.05.02/11.05.02-017.js -./11/11.05/11.05.02/11.05.02-018.js -./11/11.05/11.05.02/11.05.02-019.js -./11/11.05/11.05.02/11.05.02-020.js -./11/11.05/11.05.02/11.05.02-021.js -./11/11.05/11.05.02/11.05.02-022.js -./11/11.05/11.05.02/11.05.02-023.js -./11/11.05/11.05.02/11.05.02-024.js -./11/11.05/11.05.02/11.05.02-025.js -./11/11.05/11.05.02/11.05.02-026.js -./11/11.05/11.05.02/11.05.02-027.js -./11/11.05/11.05.02/11.05.02-028.js -./11/11.05/11.05.02/11.05.02-029.js -./11/11.05/11.05.02/11.05.02-030.js -./11/11.05/11.05.02/11.05.02-031.js -./11/11.05/11.05.02/11.05.02-032.js -./11/11.05/11.05.02/11.05.02-033.js -./11/11.05/11.05.02/11.05.02-034.js -./11/11.05/11.05.02/11.05.02-035.js -./11/11.05/11.05.02/11.05.02-036.js -./11/11.05/11.05.02/11.05.02-037.js -./11/11.05/11.05.02/11.05.02-038.js -./11/11.05/11.05.02/11.05.02-039.js -./11/11.05/11.05.02/11.05.02-040.js -./11/11.05/11.05.02/11.05.02-041.js -./11/11.05/11.05.02/11.05.02-042.js -./11/11.05/11.05.02/11.05.02-043.js -./11/11.05/11.05.02/11.05.02-044.js -./11/11.05/11.05.02/11.05.02-045.js -./11/11.05/11.05.02/11.05.02-046.js -./11/11.05/11.05.02/11.05.02-047.js -./11/11.05/11.05.02/11.05.02-048.js -./11/11.05/11.05.02/11.05.02-049.js -./11/11.05/11.05.02/11.05.02-050.js -./11/11.05/11.05.02/11.05.02-051.js -./11/11.05/11.05.02/11.05.02-052.js -./11/11.05/11.05.02/11.05.02-053.js -./11/11.05/11.05.02/11.05.02-054.js -./11/11.05/11.05.02/11.05.02-055.js -./11/11.05/11.05.02/11.05.02-056.js -./11/11.05/11.05.02/11.05.02-057.js -./11/11.05/11.05.02/11.05.02-058.js -./11/11.05/11.05.02/11.05.02-059.js -./11/11.05/11.05.02/11.05.02-060.js -./11/11.05/11.05.02/11.05.02-061.js -./11/11.05/11.05.02/11.05.02-062.js -./11/11.05/11.05.02/11.05.02-063.js -./11/11.05/11.05.02/11.05.02-064.js -./11/11.05/11.05.02/11.05.02-065.js -./11/11.05/11.05.02/11.05.02-066.js -./11/11.05/11.05.02/11.05.02-067.js -./11/11.05/11.05.02/11.05.02-068.js -./11/11.05/11.05.02/11.05.02-069.js -./11/11.05/11.05.02/11.05.02-070.js -./11/11.05/11.05.02/11.05.02-071.js -./11/11.05/11.05.02/11.05.02-072.js -./11/11.05/11.05.02/11.05.02-073.js -./11/11.05/11.05.02/11.05.02-074.js -./11/11.05/11.05.02/11.05.02-075.js -./11/11.05/11.05.02/11.05.02-076.js -./11/11.05/11.05.02/11.05.02-077.js -./11/11.05/11.05.02/11.05.02-078.js -./11/11.05/11.05.02/11.05.02-079.js -./11/11.05/11.05.02/11.05.02-080.js -./11/11.05/11.05.02/11.05.02-081.js -./11/11.05/11.05.02/11.05.02-082.js -./11/11.05/11.05.02/11.05.02-083.js -./11/11.05/11.05.02/11.05.02-084.js -./11/11.05/11.05.02/11.05.02-085.js -./11/11.05/11.05.02/11.05.02-086.js -./11/11.05/11.05.02/11.05.02-087.js -./11/11.05/11.05.02/11.05.02-088.js -./11/11.05/11.05.02/11.05.02-089.js -./11/11.05/11.05.02/11.05.02-090.js -./11/11.05/11.05.03/11.05.03-001.js -./11/11.05/11.05.03/11.05.03-002.js -./11/11.05/11.05.03/11.05.03-003.js -./11/11.05/11.05.03/11.05.03-004.js -./11/11.05/11.05.03/11.05.03-005.js -./11/11.05/11.05.03/11.05.03-006.js -./11/11.05/11.05.03/11.05.03-007.js -./11/11.05/11.05.03/11.05.03-008.js -./11/11.05/11.05.03/11.05.03-009.js -./11/11.05/11.05.03/11.05.03-010.js -./11/11.05/11.05.03/11.05.03-011.js -./11/11.05/11.05.03/11.05.03-012.js -./11/11.05/11.05.03/11.05.03-013.js -./11/11.05/11.05.03/11.05.03-014.js -./11/11.05/11.05.03/11.05.03-015.js -./11/11.05/11.05.03/11.05.03-016.js -./11/11.05/11.05.03/11.05.03-017.js -./11/11.05/11.05.03/11.05.03-018.js -./11/11.05/11.05.03/11.05.03-019.js -./11/11.05/11.05.03/11.05.03-020.js -./11/11.05/11.05.03/11.05.03-021.js -./11/11.05/11.05.03/11.05.03-022.js -./11/11.05/11.05.03/11.05.03-023.js -./11/11.05/11.05.03/11.05.03-024.js -./11/11.05/11.05.03/11.05.03-025.js -./11/11.05/11.05.03/11.05.03-026.js -./11/11.05/11.05.03/11.05.03-027.js -./11/11.05/11.05.03/11.05.03-028.js -./11/11.05/11.05.03/11.05.03-029.js -./11/11.05/11.05.03/11.05.03-030.js -./11/11.06/11.06.01/11.06.01-001.js -./11/11.06/11.06.01/11.06.01-002.js -./11/11.06/11.06.01/11.06.01-003.js -./11/11.06/11.06.01/11.06.01-004.js -./11/11.06/11.06.01/11.06.01-005.js -./11/11.06/11.06.01/11.06.01-006.js -./11/11.06/11.06.01/11.06.01-007.js -./11/11.06/11.06.01/11.06.01-008.js -./11/11.06/11.06.01/11.06.01-009.js -./11/11.06/11.06.01/11.06.01-010.js -./11/11.06/11.06.01/11.06.01-011.js -./11/11.06/11.06.01/11.06.01-012.js -./11/11.06/11.06.01/11.06.01-013.js -./11/11.06/11.06.01/11.06.01-014.js -./11/11.06/11.06.01/11.06.01-015.js -./11/11.06/11.06.01/11.06.01-016.js -./11/11.06/11.06.01/11.06.01-017.js -./11/11.06/11.06.01/11.06.01-018.js -./11/11.06/11.06.02/11.06.02-001.js -./11/11.06/11.06.02/11.06.02-002.js -./11/11.06/11.06.02/11.06.02-003.js -./11/11.06/11.06.02/11.06.02-004.js -./11/11.06/11.06.02/11.06.02-005.js -./11/11.06/11.06.02/11.06.02-006.js -./11/11.06/11.06.02/11.06.02-007.js -./11/11.06/11.06.02/11.06.02-008.js -./11/11.06/11.06.02/11.06.02-009.js -./11/11.06/11.06.02/11.06.02-010.js -./11/11.06/11.06.02/11.06.02-011.js -./11/11.06/11.06.02/11.06.02-012.js -./11/11.06/11.06.02/11.06.02-013.js -./11/11.06/11.06.02/11.06.02-014.js -./11/11.06/11.06.02/11.06.02-015.js -./11/11.06/11.06.02/11.06.02-016.js -./11/11.06/11.06.02/11.06.02-017.js -./11/11.06/11.06.03/11.06.03-001.js -./11/11.06/11.06.03/11.06.03-002.js -./11/11.06/11.06.03/11.06.03-003.js -./11/11.06/11.06.03/11.06.03-004.js -./11/11.06/11.06.03/11.06.03-005.js -./11/11.06/11.06.03/11.06.03-006.js -./11/11.06/11.06.03/11.06.03-007.js -./11/11.06/11.06.03/11.06.03-008.js -./11/11.06/11.06.03/11.06.03-009.js -./11/11.06/11.06.03/11.06.03-010.js -./11/11.06/11.06.03/11.06.03-011.js -./11/11.06/11.06.03/11.06.03-012.js -./11/11.06/11.06.03/11.06.03-013.js -./11/11.06/11.06.03/11.06.03-014.js -./11/11.06/11.06.03/11.06.03-015.js -./11/11.06/11.06.03/11.06.03-016.js -./11/11.06/11.06.03/11.06.03-017.js -./11/11.06/11.06.03/11.06.03-018.js -./11/11.06/11.06.03/11.06.03-019.js -./11/11.06/11.06.03/11.06.03-020.js -./11/11.06/11.06.03/11.06.03-021.js -./11/11.06/11.06.03/11.06.03-022.js -./11/11.06/11.06.03/11.06.03-023.js -./11/11.06/11.06.03/11.06.03-024.js -./11/11.06/11.06.03/11.06.03-025.js -./11/11.07/11.07.01/11.07.01-001.js -./11/11.07/11.07.01/11.07.01-003.js -./11/11.07/11.07.01/11.07.01-004.js -./11/11.07/11.07.01/11.07.01-005.js -./11/11.07/11.07.01/11.07.01-006.js -./11/11.07/11.07.01/11.07.01-007.js -./11/11.07/11.07.01/11.07.01-008.js -./11/11.07/11.07.01/11.07.01-009.js -./11/11.07/11.07.02/11.07.02-001.js -./11/11.07/11.07.02/11.07.02-002.js -./11/11.07/11.07.02/11.07.02-003.js -./11/11.07/11.07.02/11.07.02-004.js -./11/11.07/11.07.02/11.07.02-005.js -./11/11.07/11.07.02/11.07.02-006.js -./11/11.07/11.07.02/11.07.02-007.js -./11/11.07/11.07.02/11.07.02-008.js -./11/11.07/11.07.02/11.07.02-009.js -./11/11.07/11.07.03/11.07.03-001.js -./11/11.07/11.07.03/11.07.03-002.js -./11/11.07/11.07.03/11.07.03-003.js -./11/11.07/11.07.03/11.07.03-004.js -./11/11.07/11.07.03/11.07.03-005.js -./11/11.07/11.07.03/11.07.03-006.js -./11/11.07/11.07.03/11.07.03-007.js -./11/11.08/11.08.01/11.08.01-001.js -./11/11.08/11.08.01/11.08.01-002.js -./11/11.08/11.08.01/11.08.01-003.js -./11/11.08/11.08.01/11.08.01-004.js -./11/11.08/11.08.01/11.08.01-005.js -./11/11.08/11.08.01/11.08.01-006.js -./11/11.08/11.08.02/11.08.02-001.js -./11/11.08/11.08.02/11.08.02-002.js -./11/11.08/11.08.02/11.08.02-003.js -./11/11.08/11.08.02/11.08.02-004.js -./11/11.08/11.08.02/11.08.02-005.js -./11/11.08/11.08.02/11.08.02-006.js -./11/11.08/11.08.03/11.08.03-001.js -./11/11.08/11.08.03/11.08.03-002.js -./11/11.08/11.08.03/11.08.03-003.js -./11/11.08/11.08.03/11.08.03-004.js -./11/11.08/11.08.03/11.08.03-005.js -./11/11.08/11.08.03/11.08.03-006.js -./11/11.08/11.08.03/11.08.03-007.js -./11/11.08/11.08.03/11.08.03-008.js -./11/11.08/11.08.03/11.08.03-009.js -./11/11.08/11.08.03/11.08.03-010.js -./11/11.08/11.08.03/11.08.03-011.js -./11/11.08/11.08.04/11.08.04-001.js -./11/11.08/11.08.04/11.08.04-002.js -./11/11.08/11.08.04/11.08.04-003.js -./11/11.08/11.08.04/11.08.04-004.js -./11/11.08/11.08.04/11.08.04-005.js -./11/11.08/11.08.04/11.08.04-006.js -./11/11.08/11.08.04/11.08.04-007.js -./11/11.08/11.08.04/11.08.04-008.js -./11/11.08/11.08.04/11.08.04-009.js -./11/11.08/11.08.06/11.08.06-001.js -./11/11.08/11.08.06/11.08.06-002.js -./11/11.08/11.08.06/11.08.06-003.js -./11/11.08/11.08.06/11.08.06-004.js -./11/11.08/11.08.06/11.08.06-005.js -./11/11.08/11.08.06/11.08.06-006.js -./11/11.08/11.08.06/11.08.06-007.js -./11/11.08/11.08.07/11.08.07-001.js -./11/11.08/11.08.07/11.08.07-002.js -./11/11.08/11.08.07/11.08.07-003.js -./11/11.08/11.08.07/11.08.07-004.js -./11/11.08/11.08.07/11.08.07-005.js -./11/11.08/11.08.07/11.08.07-007.js -./11/11.08/11.08.07/11.08.07-008.js -./11/11.08/11.08.07/11.08.07-009.js -./11/11.08/11.08.07/11.08.07-010.js -./11/11.08/11.08.07/11.08.07-011.js -./11/11.08/11.08.07/11.08.07-012.js -./11/11.08/11.08.07/11.08.07-013.js -./11/11.08/11.08.07/11.08.07-014.js -./11/11.09/11.09.01/11.09.01-001.js -./11/11.09/11.09.01/11.09.01-002.js -./11/11.09/11.09.01/11.09.01-003.js -./11/11.09/11.09.01/11.09.01-004.js -./11/11.09/11.09.01/11.09.01-005.js -./11/11.09/11.09.01/11.09.01-006.js -./11/11.09/11.09.01/11.09.01-007.js -./11/11.09/11.09.01/11.09.01-008.js -./11/11.09/11.09.01/11.09.01-009.js -./11/11.09/11.09.01/11.09.01-010.js -./11/11.09/11.09.01/11.09.01-011.js -./11/11.09/11.09.01/11.09.01-012.js -./11/11.09/11.09.01/11.09.01-013.js -./11/11.09/11.09.01/11.09.01-014.js -./11/11.09/11.09.01/11.09.01-015.js -./11/11.09/11.09.01/11.09.01-016.js -./11/11.09/11.09.01/11.09.01-017.js -./11/11.09/11.09.01/11.09.01-018.js -./11/11.09/11.09.01/11.09.01-019.js -./11/11.09/11.09.01/11.09.01-020.js -./11/11.09/11.09.01/11.09.01-021.js -./11/11.09/11.09.01/11.09.01-022.js -./11/11.09/11.09.01/11.09.01-023.js -./11/11.09/11.09.01/11.09.01-024.js -./11/11.09/11.09.01/11.09.01-025.js -./11/11.09/11.09.01/11.09.01-026.js -./11/11.09/11.09.01/11.09.01-027.js -./11/11.09/11.09.01/11.09.01-028.js -./11/11.09/11.09.01/11.09.01-029.js -./11/11.09/11.09.01/11.09.01-030.js -./11/11.09/11.09.01/11.09.01-031.js -./11/11.09/11.09.01/11.09.01-032.js -./11/11.09/11.09.01/11.09.01-033.js -./11/11.09/11.09.01/11.09.01-034.js -./11/11.09/11.09.01/11.09.01-035.js -./11/11.09/11.09.01/11.09.01-036.js -./11/11.09/11.09.01/11.09.01-037.js -./11/11.09/11.09.01/11.09.01-038.js -./11/11.09/11.09.02/11.09.02-001.js -./11/11.09/11.09.02/11.09.02-002.js -./11/11.09/11.09.02/11.09.02-003.js -./11/11.09/11.09.02/11.09.02-004.js -./11/11.09/11.09.02/11.09.02-005.js -./11/11.09/11.09.02/11.09.02-006.js -./11/11.09/11.09.02/11.09.02-007.js -./11/11.09/11.09.02/11.09.02-008.js -./11/11.09/11.09.02/11.09.02-009.js -./11/11.09/11.09.02/11.09.02-010.js -./11/11.09/11.09.02/11.09.02-011.js -./11/11.09/11.09.02/11.09.02-012.js -./11/11.09/11.09.02/11.09.02-013.js -./11/11.09/11.09.02/11.09.02-014.js -./11/11.09/11.09.02/11.09.02-015.js -./11/11.09/11.09.02/11.09.02-016.js -./11/11.09/11.09.02/11.09.02-017.js -./11/11.09/11.09.02/11.09.02-018.js -./11/11.09/11.09.02/11.09.02-019.js -./11/11.09/11.09.02/11.09.02-020.js -./11/11.09/11.09.02/11.09.02-021.js -./11/11.09/11.09.02/11.09.02-022.js -./11/11.09/11.09.02/11.09.02-023.js -./11/11.09/11.09.02/11.09.02-024.js -./11/11.09/11.09.02/11.09.02-025.js -./11/11.09/11.09.02/11.09.02-026.js -./11/11.09/11.09.02/11.09.02-027.js -./11/11.09/11.09.02/11.09.02-028.js -./11/11.09/11.09.02/11.09.02-029.js -./11/11.09/11.09.02/11.09.02-030.js -./11/11.09/11.09.02/11.09.02-031.js -./11/11.09/11.09.02/11.09.02-032.js -./11/11.09/11.09.02/11.09.02-033.js -./11/11.09/11.09.02/11.09.02-034.js -./11/11.09/11.09.02/11.09.02-035.js -./11/11.09/11.09.02/11.09.02-036.js -./11/11.09/11.09.02/11.09.02-037.js -./11/11.09/11.09.02/11.09.02-038.js -./11/11.09/11.09.04/11.09.04-001.js -./11/11.09/11.09.04/11.09.04-002.js -./11/11.09/11.09.04/11.09.04-003.js -./11/11.09/11.09.04/11.09.04-004.js -./11/11.09/11.09.04/11.09.04-005.js -./11/11.09/11.09.04/11.09.04-006.js -./11/11.09/11.09.04/11.09.04-007.js -./11/11.09/11.09.04/11.09.04-008.js -./11/11.09/11.09.04/11.09.04-009.js -./11/11.09/11.09.04/11.09.04-010.js -./11/11.09/11.09.04/11.09.04-011.js -./11/11.09/11.09.04/11.09.04-012.js -./11/11.09/11.09.04/11.09.04-013.js -./11/11.09/11.09.04/11.09.04-014.js -./11/11.09/11.09.04/11.09.04-015.js -./11/11.09/11.09.04/11.09.04-016.js -./11/11.09/11.09.04/11.09.04-017.js -./11/11.09/11.09.04/11.09.04-018.js -./11/11.09/11.09.04/11.09.04-019.js -./11/11.09/11.09.04/11.09.04-020.js -./11/11.09/11.09.04/11.09.04-021.js -./11/11.09/11.09.04/11.09.04-022.js -./11/11.09/11.09.04/11.09.04-023.js -./11/11.09/11.09.04/11.09.04-024.js -./11/11.09/11.09.04/11.09.04-025.js -./11/11.09/11.09.05/11.09.05-001.js -./11/11.09/11.09.05/11.09.05-002.js -./11/11.09/11.09.05/11.09.05-003.js -./11/11.09/11.09.05/11.09.05-004.js -./11/11.09/11.09.05/11.09.05-005.js -./11/11.09/11.09.05/11.09.05-006.js -./11/11.09/11.09.05/11.09.05-007.js -./11/11.09/11.09.05/11.09.05-008.js -./11/11.09/11.09.05/11.09.05-009.js -./11/11.09/11.09.05/11.09.05-010.js -./11/11.09/11.09.05/11.09.05-011.js -./11/11.09/11.09.05/11.09.05-012.js -./11/11.09/11.09.05/11.09.05-013.js -./11/11.09/11.09.05/11.09.05-014.js -./11/11.09/11.09.05/11.09.05-015.js -./11/11.09/11.09.05/11.09.05-016.js -./11/11.09/11.09.05/11.09.05-017.js -./11/11.09/11.09.05/11.09.05-018.js -./11/11.09/11.09.05/11.09.05-019.js -./11/11.09/11.09.05/11.09.05-020.js -./11/11.09/11.09.05/11.09.05-021.js -./11/11.09/11.09.05/11.09.05-022.js -./11/11.09/11.09.05/11.09.05-023.js -./11/11.09/11.09.05/11.09.05-024.js -./11/11.09/11.09.05/11.09.05-025.js -./11/11.10/11.10-001.js -./11/11.10/11.10-002.js -./11/11.10/11.10-003.js -./11/11.10/11.10-004.js -./11/11.10/11.10-005.js -./11/11.10/11.10-006.js -./11/11.10/11.10-007.js -./11/11.10/11.10-008.js -./11/11.10/11.10-009.js -./11/11.10/11.10-010.js -./11/11.10/11.10-011.js -./11/11.10/11.10-012.js -./11/11.10/11.10-013.js -./11/11.10/11.10-014.js -./11/11.10/11.10-015.js -./11/11.10/11.10-016.js -./11/11.10/11.10-017.js -./11/11.10/11.10-018.js -./11/11.11/11.11-001.js -./11/11.11/11.11-002.js -./11/11.11/11.11-003.js -./11/11.11/11.11-004.js -./11/11.11/11.11-005.js -./11/11.11/11.11-006.js -./11/11.11/11.11-007.js -./11/11.11/11.11-008.js -./11/11.11/11.11-009.js -./11/11.11/11.11-010.js -./11/11.11/11.11-011.js -./11/11.11/11.11-012.js -./11/11.11/11.11-013.js -./11/11.11/11.11-014.js -./11/11.11/11.11-015.js -./11/11.11/11.11-016.js -./11/11.11/11.11-017.js -./11/11.11/11.11-018.js -./11/11.11/11.11-019.js -./11/11.11/11.11-020.js -./11/11.11/11.11-021.js -./11/11.11/11.11-022.js -./11/11.11/11.11-023.js -./11/11.11/11.11-024.js -./11/11.11/11.11-025.js -./11/11.11/11.11-026.js -./11/11.11/11.11-027.js -./11/11.12/11.12-001.js -./11/11.12/11.12-002.js -./11/11.12/11.12-003.js -./11/11.12/11.12-004.js -./11/11.12/11.12-005.js -./11/11.12/11.12-008.js -./11/11.12/11.12-012.js -./11/11.13/11.13.01/11.13.01-001.js -./11/11.13/11.13.02/11.13.02-001.js -./11/11.13/11.13.02/11.13.02-002.js -./11/11.13/11.13.02/11.13.02-003.js -./11/11.13/11.13.02/11.13.02-004.js -./11/11.13/11.13.02/11.13.02-005.js -./11/11.13/11.13.02/11.13.02-006.js -./11/11.13/11.13.02/11.13.02-007.js -./11/11.13/11.13.02/11.13.02-008.js -./11/11.13/11.13.02/11.13.02-009.js -./11/11.13/11.13.02/11.13.02-010.js -./11/11.13/11.13.02/11.13.02-011.js -./11/11.13/11.13.02/11.13.02-012.js -./11/11.13/11.13.02/11.13.02-013.js -./11/11.13/11.13.02/11.13.02-014.js -./11/11.13/11.13.02/11.13.02-039.js -./11/11.13/11.13.02/11.13.02-040.js -./11/11.13/11.13.02/11.13.02-041.js -./11/11.13/11.13.02/11.13.02-042.js -./11/11.13/11.13.02/11.13.02-043.js -./11/11.13/11.13.02/11.13.02-044.js -./11/11.13/11.13.02/11.13.02-045.js -./11/11.13/11.13.02/11.13.02-046.js -./11/11.13/11.13.02/11.13.02-047.js -./11/11.13/11.13.02/11.13.02-048.js -./11/11.13/11.13.02/11.13.02-049.js -./11/11.13/11.13.02/11.13.02-050.js -./11/11.13/11.13.02/11.13.02-051.js -./11/11.14/11.14-001.js -./11/11.14/11.14-002.js -./12/12.01/12.01-001.js -./12/12.01/12.01-002.js -./12/12.01/12.01-003.js -./12/12.01/12.01-004.js -./12/12.01/12.01-005.js -./12/12.02/12.02-001.js -./12/12.02/12.02-002.js -./12/12.02/12.02-003.js -./12/12.02/12.02-004.js -./12/12.02/12.02-005.js -./12/12.02/12.02-006.js -./12/12.02/12.02-007.js -./12/12.02/12.02-008.js -./12/12.02/12.02-009.js -./12/12.02/12.02-010.js -./12/12.02/12.02.01/12.02.01-001.js -./12/12.02/12.02.01/12.02.01-002.js -./12/12.02/12.02-011.js -./12/12.02/12.02-012.js -./12/12.02/12.02-013.js -./12/12.02/12.02-014.js -./12/12.02/12.02-015.js -./12/12.02/12.02-016.js -./12/12.02/12.02-018.js -./12/12.02/12.02-019.js -./12/12.02/12.02-020.js -./12/12.02/12.02-021.js -./12/12.02/12.02-022.js -./12/12.03/12.03-001.js -./12/12.03/12.03-002.js -./12/12.03/12.03-003.js -./12/12.04/12.04-001.js -./12/12.04/12.04-002.js -./12/12.04/12.04-003.js -./12/12.04/12.04-004.js -./12/12.05/12.05-001.js -./12/12.05/12.05-002.js -./12/12.05/12.05-003.js -./12/12.05/12.05-004.js -./12/12.05/12.05-005.js -./12/12.05/12.05-006.js -./12/12.05/12.05-007.js -./12/12.05/12.05-008.js -./12/12.06/12.06.01/12.06.01-001.js -./12/12.06/12.06.01/12.06.01-002.js -./12/12.06/12.06.01/12.06.01-003.js -./12/12.06/12.06.01/12.06.01-004.js -./12/12.06/12.06.01/12.06.01-005.js -./12/12.06/12.06.01/12.06.01-006.js -./12/12.06/12.06.01/12.06.01-007.js -./12/12.06/12.06.01/12.06.01-008.js -./12/12.06/12.06.01/12.06.01-009.js -./12/12.06/12.06.01/12.06.01-010.js -./12/12.06/12.06.02/12.06.02-001.js -./12/12.06/12.06.02/12.06.02-002.js -./12/12.06/12.06.02/12.06.02-003.js -./12/12.06/12.06.02/12.06.02-004.js -./12/12.06/12.06.02/12.06.02-005.js -./12/12.06/12.06.02/12.06.02-006.js -./12/12.06/12.06.02/12.06.02-007.js -./12/12.06/12.06.02/12.06.02-008.js -./12/12.06/12.06.03/12.06.03-001.js -./12/12.06/12.06.03/12.06.03-002.js -./12/12.06/12.06.03/12.06.03-003.js -./12/12.06/12.06.03/12.06.03-004.js -./12/12.06/12.06.03/12.06.03-005.js -./12/12.06/12.06.03/12.06.03-006.js -./12/12.06/12.06.03/12.06.03-007.js -./12/12.06/12.06.03/12.06.03-008.js -./12/12.06/12.06.03/12.06.03-009.js -./12/12.06/12.06.03/12.06.03-010.js -./12/12.06/12.06.03/12.06.03-011.js -./12/12.06/12.06.04/12.06.04-001.js -./12/12.06/12.06.04/12.06.04-002.js -./12/12.06/12.06.04/12.06.04-003.js -./12/12.06/12.06.04/12.06.04-004.js -./12/12.06/12.06.04/12.06.04-005.js -./12/12.06/12.06.04/12.06.04-006.js -./12/12.06/12.06.04/12.06.04-007.js -./12/12.07/12.07-001.js -./12/12.07/12.07-002.js -./12/12.07/12.07-003.js -./12/12.07/12.07-004.js -./12/12.07/12.07-005.js -./12/12.07/12.07-006.js -./12/12.07/12.07-007.js -./12/12.07/12.07-008.js -./12/12.07/12.07-009.js -./12/12.07/12.07-010.js -./12/12.07/12.07-011.js -./12/12.07/12.07-012.js -./12/12.07/12.07-013.js -./12/12.07/12.07-014.js -./12/12.07/12.07-015.js -./12/12.07/12.07-016.js -./12/12.08/12.08-001.js -./12/12.08/12.08-002.js -./12/12.08/12.08-003.js -./12/12.08/12.08-004.js -./12/12.08/12.08-005.js -./12/12.08/12.08-006.js -./12/12.08/12.08-007.js -./12/12.08/12.08-008.js -./12/12.08/12.08-009.js -./12/12.08/12.08-010.js -./12/12.08/12.08-011.js -./12/12.08/12.08-012.js -./12/12.08/12.08-013.js -./12/12.08/12.08-014.js -./12/12.08/12.08-015.js -./12/12.08/12.08-016.js -./12/12.08/12.08-017.js -./12/12.08/12.08-018.js -./12/12.09/12.09-001.js -./12/12.09/12.09-002.js -./12/12.09/12.09-003.js -./12/12.09/12.09-004.js -./12/12.09/12.09-005.js -./12/12.09/12.09-006.js -./12/12.10/12.10-001.js -./12/12.10/12.10-002.js -./12/12.10/12.10-003.js -./12/12.10/12.10-004.js -./12/12.10/12.10-005.js -./12/12.10/12.10-006.js -./12/12.10/12.10-007.js -./12/12.11/12.11-001.js -./12/12.11/12.11-002.js -./12/12.11/12.11-003.js -./12/12.11/12.11-004.js -./12/12.11/12.11-005.js -./12/12.11/12.11-006.js -./12/12.11/12.11-007.js -./12/12.12/12.12-001.js -./12/12.12/12.12-002.js -./12/12.12/12.12-003.js -./12/12.12/12.12-004.js -./12/12.12/12.12-005.js -./12/12.12/12.12-006.js -./12/12.12/12.12-007.js -./12/12.12/12.12-008.js -./12/12.12/12.12-009.js -./12/12.12/12.12-010.js -./12/12.13/12.13-001.js -./12/12.13/12.13-002.js -./12/12.13/12.13-003.js -./12/12.14/12.14-001.js -./12/12.14/12.14-002.js -./12/12.14/12.14-003.js -./12/12.14/12.14-004.js -./12/12.14/12.14-005.js -./12/12.14/12.14-006.js -./13/13-001.js -./13/13-002.js -./13/13-003.js -./13/13-004.js -./13/13-005.js -./13/13-006.js -./13/13-007.js -./13/13-008.js -./13/13-009.js -./13/13-010.js -./13/13.01/13.01-001.js -./13/13-011.js -./13/13-012.js -./13/13-013.js -./13/13.02/13.02-001.js -./13/13.02/13.02-002.js -./13/13.02/13.02-003.js -./13/13.02/13.02-004.js -./13/13.02/13.02-005.js -./13/13.02/13.02-006.js -./13/13.02/13.02-007.js -./13/13.02/13.02-008.js -./15/15.02/15.02.01/15.02.01-001.js -./15/15.02/15.02.01/15.02.01-002.js -./15/15.02/15.02.01/15.02.01-003.js -./15/15.02/15.02.01/15.02.01-004.js -./15/15.02/15.02.01/15.02.01-005.js -./15/15.02/15.02.01/15.02.01-006.js -./15/15.02/15.02.01/15.02.01-007.js -./15/15.02/15.02.01/15.02.01-008.js -./15/15.02/15.02.01/15.02.01-009.js -./15/15.02/15.02.01/15.02.01-010.js -./15/15.02/15.02.02/15.02.02-001.js -./15/15.02/15.02.02/15.02.02-002.js -./15/15.02/15.02.02/15.02.02-003.js -./15/15.02/15.02.02/15.02.02-004.js -./15/15.02/15.02.02/15.02.02-005.js -./15/15.02/15.02.02/15.02.02-006.js -./15/15.02/15.02.02/15.02.02-007.js -./15/15.02/15.02.02/15.02.02-008.js -./15/15.02/15.02.02/15.02.02-009.js -./15/15.02/15.02.02/15.02.02-010.js -./15/15.02/15.02.03/15.02.03-001.js -./15/15.02/15.02.03/15.02.03-002.js -./15/15.02/15.02.03/15.02.03-003.js -./15/15.02/15.02.03/15.02.03-004.js -./15/15.02/15.02.03/15.02.03-005.js -./15/15.02/15.02.03/15.02.03-006.js -./15/15.02/15.02.03/15.02.03-007.js -./15/15.02/15.02.03/15.02.03-008.js -./15/15.02/15.02.03/15.02.03-009.js -./15/15.02/15.02.03/15.02.03-010.js -./15/15.02/15.02.03/15.02.03-011.js -./15/15.02/15.02.03/15.02.03-012.js -./15/15.02/15.02.03/15.02.03-013.js -./15/15.02/15.02.03/15.02.03-014.js -./15/15.02/15.02.03/15.02.03-015.js -./15/15.02/15.02.03/15.02.03-016.js -./15/15.02/15.02.03/15.02.03-017.js -./15/15.02/15.02.03/15.02.03-018.js -./15/15.02/15.02.03/15.02.03-019.js -./15/15.02/15.02.03/15.02.03-020.js -./15/15.02/15.02.03/15.02.03-021.js -./15/15.02/15.02.04/15.02.04-001.js -./15/15.02/15.02.04/15.02.04-002.js -./15/15.02/15.02.04/15.02.04.01/15.02.04.01-001.js -./15/15.02/15.02.04/15.02.04.01/15.02.04.01-002.js -./15/15.02/15.02.04/15.02.04.02/15.02.04.02-001.js -./15/15.02/15.02.04/15.02.04.02/15.02.04.02-002.js -./15/15.02/15.02.04/15.02.04.02/15.02.04.02-003.js -./15/15.02/15.02.04/15.02.04.02/15.02.04.02-004.js -./15/15.02/15.02.04/15.02.04.03/15.02.04.03-001.js -./15/15.02/15.02.04/15.02.04.03/15.02.04.03-002.js -./15/15.02/15.02.04/15.02.04.03/15.02.04.03-003.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-001.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-002.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-003.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-004.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-005.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-006.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-007.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-008.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-009.js -./15/15.02/15.02.04/15.02.04.04/15.02.04.04-010.js -./15/15.02/15.02.04/15.02.04.05/15.02.04.05-001.js -./15/15.02/15.02.04/15.02.04.05/15.02.04.05-002.js -./15/15.02/15.02.04/15.02.04.05/15.02.04.05-003.js -./15/15.02/15.02.04/15.02.04.05/15.02.04.05-004.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-001.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-002.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-003.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-004.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-005.js -./15/15.02/15.02.04/15.02.04.06/15.02.04.06-006.js -./15/15.02/15.02.04/15.02.04.07/15.02.04.07-001.js -./15/15.02/15.02.04/15.02.04.07/15.02.04.07-002.js -./15/15.02/15.02.04/15.02.04.07/15.02.04.07-003.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-001.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-002.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-004.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-005.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-007.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-008.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-009.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-010.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-011.js -./15/15.03/15.03.02/15.03.02.01/15.03.02.01-012s.js -./15/15.03/15.03.03/15.03.03-001.js -./15/15.03/15.03.03/15.03.03-002.js -./15/15.03/15.03.03/15.03.03-003.js -./15/15.03/15.03.03/15.03.03-004.js -./15/15.03/15.03.03/15.03.03.01/15.03.03.01-001.js -./15/15.03/15.03.03/15.03.03.01/15.03.03.01-002.js -./15/15.03/15.03.03/15.03.03.01/15.03.03.01-003.js -./15/15.03/15.03.03/15.03.03.01/15.03.03.01-004.js -./15/15.03/15.03.03/15.03.03.02/15.03.03.02-001.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-001.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-002.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-003.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-004.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-005.js -./15/15.03/15.03.04/15.03.04.02/15.03.04.02-006.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-001.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-002.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-003.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-004.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-005.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-006.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-007.js -./15/15.04/15.04.02/15.04.02.01/15.04.02.01-008.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-001.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-002.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-003.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-004.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-005.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-006.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-007.js -./15/15.04/15.04.02/15.04.02.02/15.04.02.02-008.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-001.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-002.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-003.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-004.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-005.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-006.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-007.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-008.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-009.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-010.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-011.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-012.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-013.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-014.js -./15/15.05/15.05.01/15.05.01.01/15.05.01.01-015.js -./15/15.05/15.05.02/15.05.02.01/15.05.02.01-001.js -./15/15.05/15.05.02/15.05.02.01/15.05.02.01-002.js -./15/15.05/15.05.03/15.05.03.01/15.05.03.01-001.js -./15/15.05/15.05.03/15.05.03.01/15.05.03.01-002.js -./15/15.05/15.05.03/15.05.03.02/15.05.03.02-001.js -./15/15.05/15.05.03/15.05.03.02/15.05.03.02-002.js -./15/15.05/15.05.04/15.05.04.01/15.05.04.01-001.js -./15/15.05/15.05.04/15.05.04.02/15.05.04.02-001.js -./15/15.05/15.05.04/15.05.04.02/15.05.04.02-002.js -./15/15.05/15.05.04/15.05.04.03/15.05.04.03-001.js -./15/15.05/15.05.04/15.05.04.04/15.05.04.04-001.js -./15/15.05/15.05.04/15.05.04.04/15.05.04.04-002.js -./15/15.05/15.05.04/15.05.04.04/15.05.04.04-003.js -./15/15.05/15.05.04/15.05.04.04/15.05.04.04-004.js -./15/15.05/15.05.04/15.05.04.05/15.05.04.05-001.js -./15/15.05/15.05.04/15.05.04.05/15.05.04.05-002.js -./15/15.05/15.05.04/15.05.04.05/15.05.04.05-003.js -./15/15.05/15.05.04/15.05.04.05/15.05.04.05-004.js -./15/15.05/15.05.04/15.05.04.06/15.05.04.06-001.js -./15/15.05/15.05.04/15.05.04.06/15.05.04.06-002.js -./15/15.05/15.05.04/15.05.04.06/15.05.04.06-003.js -./15/15.05/15.05.04/15.05.04.06/15.05.04.06-004.js -./15/15.05/15.05.04/15.05.04.07/15.05.04.07-001.js -./15/15.05/15.05.04/15.05.04.07/15.05.04.07-002.js -./15/15.05/15.05.04/15.05.04.07/15.05.04.07-003.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-001.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-002.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-003.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-004.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-005.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-006.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-007.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-008.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-009.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-010.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-011.js -./15/15.06/15.06.01/15.06.01.01/15.06.01.01-012.js -./15/15.06/15.06.02/15.06.02.01/15.06.02.01-001.js -./15/15.06/15.06.02/15.06.02.01/15.06.02.01-002.js -./15/15.06/15.06.03/15.06.03.01/15.06.03.01-001.js -./15/15.06/15.06.04/15.06.04.01/15.06.04.01-001.js -./15/15.06/15.06.04/15.06.04.02/15.06.04.02-001.js -./15/15.06/15.06.04/15.06.04.02/15.06.04.02-002.js -./15/15.06/15.06.04/15.06.04.02/15.06.04.02-003.js -./15/15.06/15.06.04/15.06.04.03/15.06.04.03-001.js -./15/15.07/15.07-001.js -./15/15.07/15.07-002.js -./15/15.07/15.07.01/15.07.01-001.js -./15/15.07/15.07.01/15.07.01-002.js -./15/15.07/15.07.01/15.07.01-003.js -./15/15.07/15.07.01/15.07.01-004.js -./15/15.07/15.07.01/15.07.01-005.js -./15/15.07/15.07.01/15.07.01-006.js -./15/15.07/15.07.01/15.07.01-007.js -./15/15.07/15.07.01/15.07.01-008.js -./15/15.07/15.07.01/15.07.01-009.js -./15/15.07/15.07.01/15.07.01-010.js -./15/15.07/15.07.02/15.07.02-001.js -./15/15.07/15.07.02/15.07.02-002.js -./15/15.07/15.07.02/15.07.02-003.js -./15/15.07/15.07.02/15.07.02-004.js -./15/15.07/15.07.02/15.07.02-005.js -./15/15.07/15.07.02/15.07.02-006.js -./15/15.07/15.07.02/15.07.02-007.js -./15/15.07/15.07.02/15.07.02-008.js -./15/15.07/15.07.02/15.07.02-009.js -./15/15.07/15.07.02/15.07.02-010.js -./15/15.07/15.07.02/15.07.02-011.js -./15/15.07/15.07.03/15.07.03-001.js -./15/15.07/15.07.03/15.07.03-002.js -./15/15.07/15.07.03/15.07.03-003.js -./15/15.07/15.07.03/15.07.03-004.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-001.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-002.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-003.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-004.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-005.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-006.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-007.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-008.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-009.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-010.js -./15/15.07/15.07.03/15.07.03.01/15.07.03.01-011.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-001.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-002.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-003.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-004.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-005.js -./15/15.07/15.07.03/15.07.03.02/15.07.03.02-006.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-001.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-002.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-003.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-004.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-005.js -./15/15.07/15.07.03/15.07.03.03/15.07.03.03-006.js -./15/15.07/15.07.03/15.07.03.04/15.07.03.04-001.js -./15/15.07/15.07.03/15.07.03.04/15.07.03.04-002.js -./15/15.07/15.07.03/15.07.03.04/15.07.03.04-003.js -./15/15.07/15.07.03/15.07.03.04/15.07.03.04-004.js -./15/15.07/15.07.03/15.07.03.04/15.07.03.04-005.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-001.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-002.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-003.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-004.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-005.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-006.js -./15/15.07/15.07.03/15.07.03.05/15.07.03.05-007.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-001.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-002.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-003.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-004.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-005.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-006.js -./15/15.07/15.07.03/15.07.03.06/15.07.03.06-007.js -./15/15.07/15.07.04/15.07.04-001.js -./15/15.07/15.07.04/15.07.04-002.js -./15/15.07/15.07.04/15.07.04-003.js -./15/15.07/15.07.04/15.07.04.01/15.07.04.01-001.js -./15/15.07/15.07.04/15.07.04.01/15.07.04.01-002.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-001.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-003.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-004.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-005.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-006.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-008.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-009.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-010.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-011.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-012.js -./15/15.07/15.07.04/15.07.04.02/15.07.04.02-013.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-001.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-002.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-003.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-004.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-005.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-006.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-007.js -./15/15.07/15.07.04/15.07.04.05/15.07.04.05-008.js -./15/15.08/15.08.02/15.08.02.01/15.08.02.01-001.js -./15/15.08/15.08.02/15.08.02.01/15.08.02.01-002.js -./15/15.08/15.08.02/15.08.02.01/15.08.02.01-003.js -./15/15.08/15.08.02/15.08.02.01/15.08.02.01-004.js -./15/15.08/15.08.02/15.08.02.01/15.08.02.01-005.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-001.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-002.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-003.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-004.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-005.js -./15/15.08/15.08.02/15.08.02.02/15.08.02.02-006.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-001.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-002.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-003.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-004.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-005.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-006.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-007.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-008.js -./15/15.08/15.08.02/15.08.02.03/15.08.02.03-009.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-001.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-002.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-003.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-004.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-005.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-006.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-007.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-008.js -./15/15.08/15.08.02/15.08.02.04/15.08.02.04-009.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-001.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-002.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-003.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-004.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-005.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-006.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-007.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-008.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-009.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-010.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-011.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-012.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-013.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-014.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-015.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-016.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-017.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-018.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-019.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-020.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-021.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-022.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-023.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-024.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-025.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-026.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-027.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-028.js -./15/15.08/15.08.02/15.08.02.05/15.08.02.05-029.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-001.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-002.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-003.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-004.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-005.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-006.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-007.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-008.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-009.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-010.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-011.js -./15/15.08/15.08.02/15.08.02.06/15.08.02.06-012.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-001.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-002.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-003.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-004.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-005.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-006.js -./15/15.08/15.08.02/15.08.02.07/15.08.02.07-007.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-001.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-002.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-003.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-004.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-005.js -./15/15.08/15.08.02/15.08.02.08/15.08.02.08-006.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-001.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-002.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-003.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-004.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-005.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-006.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-007.js -./15/15.08/15.08.02/15.08.02.09/15.08.02.09-008.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-001.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-002.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-003.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-004.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-005.js -./15/15.08/15.08.02/15.08.02.10/15.08.02.10-006.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-001.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-002.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-003.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-004.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-005.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-006.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-007.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-008.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-009.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-010.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-011.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-012.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-013.js -./15/15.08/15.08.02/15.08.02.11/15.08.02.11-014.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-001.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-002.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-003.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-004.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-005.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-006.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-007.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-008.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-009.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-010.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-011.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-012.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-013.js -./15/15.08/15.08.02/15.08.02.12/15.08.02.12-014.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-001.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-002.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-003.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-004.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-005.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-006.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-007.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-008.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-009.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-010.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-011.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-012.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-013.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-014.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-015.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-016.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-017.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-018.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-019.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-020.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-021.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-022.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-023.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-024.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-025.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-026.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-027.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-028.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-029.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-030.js -./15/15.08/15.08.02/15.08.02.13/15.08.02.13-031.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-001.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-002.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-003.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-004.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-005.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-006.js -./15/15.08/15.08.02/15.08.02.15/15.08.02.15-007.js -./15/15.08/15.08.02/15.08.02.16/15.08.02.16-001.js -./15/15.08/15.08.02/15.08.02.16/15.08.02.16-002.js -./15/15.08/15.08.02/15.08.02.16/15.08.02.16-003.js -./15/15.08/15.08.02/15.08.02.16/15.08.02.16-004.js -./15/15.08/15.08.02/15.08.02.16/15.08.02.16-005.js -./15/15.08/15.08.02/15.08.02.17/15.08.02.17-001.js -./15/15.08/15.08.02/15.08.02.17/15.08.02.17-002.js -./15/15.08/15.08.02/15.08.02.17/15.08.02.17-003.js -./15/15.08/15.08.02/15.08.02.17/15.08.02.17-004.js -./15/15.08/15.08.02/15.08.02.17/15.08.02.17-005.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-001.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-002.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-003.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-004.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-005.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-006.js -./15/15.08/15.08.02/15.08.02.18/15.08.02.18-007.js diff --git a/tests/jerry/arguments.js b/tests/jerry/arguments.js index a9b3193f..b1014d59 100644 --- a/tests/jerry/arguments.js +++ b/tests/jerry/arguments.js @@ -129,3 +129,17 @@ fn_expr (1); (function () { var a = [arguments]; })(); + +function nested_args() +{ + var a; + for (var i = 0; i < 1; i++) + { + if (i == 0) + { + a = arguments[i]; + } + } + assert(a === 3); +} +nested_args(3); diff --git a/tests/jerry/arithmetic-parse.js b/tests/jerry/arithmetic-parse.js index 81e6c5fa..15544bc9 100644 --- a/tests/jerry/arithmetic-parse.js +++ b/tests/jerry/arithmetic-parse.js @@ -41,3 +41,52 @@ parse ("a =% b"); parse ("c = a+"); parse ("c = a-"); + +parse("a++\n()"); +parse("a--\n.b"); + +assert((-2 .toString()) === -2); + +Number.prototype[0] = 123; +assert(-2[0] === -123); + +function f() { + var a = 0; + function g() {} + + try { + eval ("g(this, 'a' = 1)"); + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } + + try { + eval ("g(this, 'a' += 1)"); + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } + + assert (a === 0); +} +f(); + +function g(a, b) +{ + assert(b === "undefined"); +} +g(this, typeof undeclared_var) + +function h() +{ + var done = false; + var o = { a: function () { done = (this === o) } } + function f() {} + + with (o) { + f(this, a()); + } + assert(done); +} +h(); diff --git a/tests/jerry/array-prototype-indexof.js b/tests/jerry/array-prototype-indexof.js index ee77f802..5e1f7fde 100644 --- a/tests/jerry/array-prototype-indexof.js +++ b/tests/jerry/array-prototype-indexof.js @@ -86,3 +86,33 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +// Remove the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.indexOf(4, { + valueOf: function() { + array.length = 0; + } +}) + +assert(value === -1); + +// Extend the buffer +var array = [1, 2, 3]; +var value = array.indexOf(2, { + valueOf: function() { + array.length = 5; + } +}) + +assert(value === 1); + +// Reduce the buffer +var array = [1, 2, 3, 4, 5, 6, 7]; +var value = array.indexOf(6, { + valueOf: function() { + array.length = 5; + } +}) + +assert(value === -1); diff --git a/tests/jerry/array-prototype-lastindexof.js b/tests/jerry/array-prototype-lastindexof.js index 4aa2c5f4..76f236c1 100644 --- a/tests/jerry/array-prototype-lastindexof.js +++ b/tests/jerry/array-prototype-lastindexof.js @@ -69,3 +69,33 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +// Remove the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.lastIndexOf(4, { + valueOf: function() { + array.length = 0; + } +}) + +assert(value === -1); + +// Extend the buffer +var array = [1, 2, 3]; +var value = array.lastIndexOf(1, { + valueOf: function() { + array.length = 5; + } +}) + +assert(value === 0); + +// Reduce the buffer +var array = [1, 2, 3, 4, 5, 6, 7]; +var value = array.indexOf(5, { + valueOf: function() { + array.length = 2; + } +}) + +assert(value === -1); diff --git a/tests/jerry/array-prototype-push.js b/tests/jerry/array-prototype-push.js index 3c83838a..b7bda5ed 100644 --- a/tests/jerry/array-prototype-push.js +++ b/tests/jerry/array-prototype-push.js @@ -53,7 +53,6 @@ try { } assert(a.length === 4294967295) - var o = { length : 4294967294, push : Array.prototype.push }; assert(o.push("x") === 4294967295); assert(o.length === 4294967295); @@ -67,14 +66,6 @@ try { assert(o.length === 4294967296); assert(o[4294967295] === "y"); -try { - assert(o.push("z") === 1); -} catch (e) { - assert(false); -} -assert(o.length === 1); -assert(o[0] === "z"); - /* ES v5.1 15.4.4.7.5. Checking behavior when array is non-extensible while pushing */ var arr = []; diff --git a/tests/jerry/array-prototype-reduce-right.js b/tests/jerry/array-prototype-reduce-right.js index a9a71cb2..9b3ca5fa 100644 --- a/tests/jerry/array-prototype-reduce-right.js +++ b/tests/jerry/array-prototype-reduce-right.js @@ -34,14 +34,6 @@ try { assert(e instanceof TypeError); } -try { - var arg2; - [].reduceRight(func, arg2); - assert(false); -} catch(e) { - assert(e instanceof TypeError); -} - try { var a = new Array(); a.length = 10; @@ -54,6 +46,8 @@ try { // various checks assert([].reduceRight(func, 1) === 1); +assert([].reduceRight(func, undefined) === undefined); + assert([0].reduceRight(func) === 0); assert([0, 1].reduceRight(func) === 1); diff --git a/tests/jerry/array-prototype-reduce.js b/tests/jerry/array-prototype-reduce.js index 6193ec7f..908818a6 100644 --- a/tests/jerry/array-prototype-reduce.js +++ b/tests/jerry/array-prototype-reduce.js @@ -39,6 +39,8 @@ catch(e) { // various checks assert ([].reduce(func, 1) === 1); +assert ([].reduce(func, undefined) === undefined); + assert ([0].reduce(func) === 0); assert ([0, 1].reduce(func) === 1); diff --git a/tests/jerry/array-prototype-slice.js b/tests/jerry/array-prototype-slice.js index 1ba2f9fc..ad2736f8 100644 --- a/tests/jerry/array-prototype-slice.js +++ b/tests/jerry/array-prototype-slice.js @@ -151,3 +151,41 @@ try { assert (e.message === "foo"); assert (e instanceof ReferenceError); } + +function array_check(result_array, expected_array) { + assert(result_array instanceof Array); + assert(result_array.length === expected_array.length); + for (var idx = 0; idx < expected_array.length; idx++) { + assert(result_array[idx] === expected_array[idx]); + } +} + +// Remove the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.slice(4, { + valueOf: function() { + array.length = 0; + } +}) + +array_check(value, []); + +// Extend the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.slice(6, { + valueOf: function() { + array.length = 10; + } +}) + +array_check(value, []); + +// Reduce the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.slice(1, { + valueOf: function() { + array.length = 3; + } +}) + +array_check(value, []); diff --git a/tests/jerry/date-construct.js b/tests/jerry/date-construct.js index 16e93dea..426d66eb 100644 --- a/tests/jerry/date-construct.js +++ b/tests/jerry/date-construct.js @@ -13,7 +13,6 @@ // limitations under the License. assert (Date.length == 7); -assert (Object.prototype.toString.call (Date.prototype) === '[object Date]'); var d; @@ -28,8 +27,6 @@ catch (e) assert (e.message === "foo"); } -assert (isNaN(Date.prototype.valueOf.call(Date.prototype))); - d = new Date("abcd"); assert (isNaN(d.valueOf())); diff --git a/tests/jerry/date-parse.js b/tests/jerry/date-parse.js index 7eb5450d..9de761a4 100644 --- a/tests/jerry/date-parse.js +++ b/tests/jerry/date-parse.js @@ -59,7 +59,19 @@ var wrongFormats = ["", "-02015-01-01", "002015-01-01", "+0002015-01-01", - "-0002015-01-01"]; + "-0002015-01-01", + "2015-01T00:00:00.000-03X00", + "2015-01-01T00-03:00", + "Fri Jan 01 1 00:00:00 GMT+0000", + "Fri Jan 01 11 00:00:00 GMT+0000", + "Fri Jan 01 111 00:00:00 GMT+0000", + "Fri Jan 01 1234567 00:00:00 GMT+0000", + "Fri Jan 01 +1000 00:00:00 GMT+0000", + "Fri Jan 01 -1 00:00:00 GMT+0000", + "Fri Jan 01 -11 00:00:00 GMT+0000", + "Fri Jan 01 -111 00:00:00 GMT+0000", + "Fri Jan 01 -1234567 00:00:00 GMT+0000", + "Thu Apr 10 1997"]; for (i in wrongFormats) { var d = Date.parse(wrongFormats[i]); @@ -123,3 +135,37 @@ assert (Date.parse("9999-12-31T23:59:59.999Z") == 253402300799999) assert (Date.parse("+010000-01-01T00:00:00.000Z") == 253402300800000) assert (Date.parse("+275760-09-13T00:00:00.000Z") == 8640000000000000) assert (Date.parse("+275760-09-13T00:00:00.001Z") == 8640000000000001) + +// Date.toString() format +assert (Date.parse("Tue Apr 20 -271821 00:00:00 GMT+0000") == -8640000000000000) +assert (Date.parse("Fri Dec 31 -0001 23:59:59 GMT+0000") == -62167219201000) +assert (Date.parse("Sat Jan 01 0000 00:00:00 GMT+0000") == -62167219200000) +assert (Date.parse("Thu Dec 31 0009 23:59:59 GMT+0000") == -61851600001000) +assert (Date.parse("Fri Jan 01 0010 00:00:00 GMT+0000") == -61851600000000) +assert (Date.parse("Thu Dec 31 0099 23:59:59 GMT+0000") == -59011459201000) +assert (Date.parse("Fri Jan 01 0100 00:00:00 GMT+0000") == -59011459200000) +assert (Date.parse("Tue Dec 31 0999 23:59:59 GMT+0000") == -30610224001000) +assert (Date.parse("Wed Jan 01 1000 00:00:00 GMT+0000") == -30610224000000) +assert (Date.parse("Wed Dec 31 1969 23:59:59 GMT+0000") == -1000) +assert (Date.parse("Thu Jan 01 1970 00:00:00 GMT+0000") == 0) +assert (Date.parse("Thu Jan 01 1970 00:00:01 GMT+0000") == 1000) +assert (Date.parse("Fri Dec 31 9999 23:59:59 GMT+0000") == 253402300799000) +assert (Date.parse("Sat Jan 01 10000 00:00:00 GMT+0000") == 253402300800000) +assert (Date.parse("Sat Sep 13 275760 00:00:00 GMT+0000") == 8640000000000000) + +// Date.toUTCString() format +assert (Date.parse("Tue, 20 Apr -271821 00:00:00 GMT") == -8640000000000000) +assert (Date.parse("Fri, 31 Dec -0001 23:59:59 GMT") == -62167219201000) +assert (Date.parse("Sat, 01 Jan 0000 00:00:00 GMT") == -62167219200000) +assert (Date.parse("Thu, 31 Dec 0009 23:59:59 GMT") == -61851600001000) +assert (Date.parse("Fri, 01 Jan 0010 00:00:00 GMT") == -61851600000000) +assert (Date.parse("Thu, 31 Dec 0099 23:59:59 GMT") == -59011459201000) +assert (Date.parse("Fri, 01 Jan 0100 00:00:00 GMT") == -59011459200000) +assert (Date.parse("Tue, 31 Dec 0999 23:59:59 GMT") == -30610224001000) +assert (Date.parse("Wed, 01 Jan 1000 00:00:00 GMT") == -30610224000000) +assert (Date.parse("Wed, 31 Dec 1969 23:59:59 GMT") == -1000) +assert (Date.parse("Thu, 01 Jan 1970 00:00:00 GMT") == 0) +assert (Date.parse("Thu, 01 Jan 1970 00:00:01 GMT") == 1000) +assert (Date.parse("Fri, 31 Dec 9999 23:59:59 GMT") == 253402300799000) +assert (Date.parse("Sat, 01 Jan 10000 00:00:00 GMT") == 253402300800000) +assert (Date.parse("Sat, 13 Sep 275760 00:00:00 GMT") == 8640000000000000) diff --git a/tests/jerry/date-setters.js b/tests/jerry/date-setters.js index b2ea396a..f712e11e 100644 --- a/tests/jerry/date-setters.js +++ b/tests/jerry/date-setters.js @@ -241,19 +241,3 @@ assert (isNaN (d.setMonth())); assert (isNaN (d.setUTCMonth())); assert (isNaN (d.setFullYear())); assert (isNaN (d.setUTCFullYear())); - -assert (isNaN (Date.prototype.setTime())); -assert (isNaN (Date.prototype.setMilliseconds())); -assert (isNaN (Date.prototype.setUTCMilliseconds())); -assert (isNaN (Date.prototype.setSeconds())); -assert (isNaN (Date.prototype.setUTCSeconds())); -assert (isNaN (Date.prototype.setMinutes())); -assert (isNaN (Date.prototype.setUTCMinutes())); -assert (isNaN (Date.prototype.setHours())); -assert (isNaN (Date.prototype.setUTCHours())); -assert (isNaN (Date.prototype.setDate())); -assert (isNaN (Date.prototype.getUTCDate())); -assert (isNaN (Date.prototype.setMonth())); -assert (isNaN (Date.prototype.setUTCMonth())); -assert (isNaN (Date.prototype.setFullYear())); -assert (isNaN (Date.prototype.setUTCFullYear())); diff --git a/tests/jerry/date-tostring.js b/tests/jerry/date-tostring.js index f0267690..b2335fb2 100644 --- a/tests/jerry/date-tostring.js +++ b/tests/jerry/date-tostring.js @@ -19,8 +19,8 @@ assert (new Date (2015, 7, 1, 0, Infinity, 0) == "Invalid Date"); assert (new Date (NaN, 1, 1, 0, 0, 0) == "Invalid Date"); assert (new Date (2015, NaN, 1, 0, 0, 0) == "Invalid Date"); assert (new Date (2015, 7, 1, 0, NaN, 0) == "Invalid Date"); -assert (/Fri Feb 13 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}:\d{2}/.test (new Date ("2015-02-13"))); -assert (/Wed Jul 08 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}:\d{2}/.test (new Date ("2015-07-08T11:29:05.023"))); +assert (/Fri Feb 13 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}\d{2}/.test (new Date ("2015-02-13"))); +assert (/Wed Jul 08 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}\d{2}/.test (new Date ("2015-07-08T11:29:05.023"))); try { @@ -33,12 +33,12 @@ catch (e) } var date = new Date(0); -assert (/Thu Jan 01 1970 \d{2}:\d{2}:\d{2} GMT\+\d{2}:\d{2}/.test (date.toString())); +assert (/Thu Jan 01 1970 \d{2}:\d{2}:\d{2} GMT\+\d{2}\d{2}/.test (date.toString())); assert (date.toUTCString() === "Thu, 01 Jan 1970 00:00:00 GMT"); assert (date.toISOString() === "1970-01-01T00:00:00.000Z"); date = new Date("2015-08-12T09:40:20.000Z") -assert (/Wed Aug 12 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}:\d{2}/.test (date.toString())); +assert (/Wed Aug 12 2015 \d{2}:\d{2}:\d{2} GMT\+\d{2}\d{2}/.test (date.toString())); assert (date.toUTCString() === "Wed, 12 Aug 2015 09:40:20 GMT"); assert (date.toISOString() === "2015-08-12T09:40:20.000Z"); @@ -145,26 +145,26 @@ assert (new Date ("2015-07-08T11:29:05.023Z").toISOString() == "2015-07-08T11:29 // corner cases assert (new Date (-8640000000000001).toString() == "Invalid Date") -assert (new Date (-8640000000000000).toString() == "Tue Apr 20 -271821 00:00:00 GMT+00:00") +assert (new Date (-8640000000000000).toString() == "Tue Apr 20 -271821 00:00:00 GMT+0000") -assert (new Date(-62167219200001).toString() == "Fri Dec 31 -0001 23:59:59 GMT+00:00") -assert (new Date(-62167219200000).toString() == "Sat Jan 01 0000 00:00:00 GMT+00:00") +assert (new Date(-62167219200001).toString() == "Fri Dec 31 -0001 23:59:59 GMT+0000") +assert (new Date(-62167219200000).toString() == "Sat Jan 01 0000 00:00:00 GMT+0000") -assert (new Date(-61851600000001).toString() == "Thu Dec 31 0009 23:59:59 GMT+00:00") -assert (new Date(-61851600000000).toString() == "Fri Jan 01 0010 00:00:00 GMT+00:00") +assert (new Date(-61851600000001).toString() == "Thu Dec 31 0009 23:59:59 GMT+0000") +assert (new Date(-61851600000000).toString() == "Fri Jan 01 0010 00:00:00 GMT+0000") -assert (new Date(-59011459200001).toString() == "Thu Dec 31 0099 23:59:59 GMT+00:00") -assert (new Date(-59011459200000).toString() == "Fri Jan 01 0100 00:00:00 GMT+00:00") +assert (new Date(-59011459200001).toString() == "Thu Dec 31 0099 23:59:59 GMT+0000") +assert (new Date(-59011459200000).toString() == "Fri Jan 01 0100 00:00:00 GMT+0000") -assert (new Date(-30610224000001).toString() == "Tue Dec 31 0999 23:59:59 GMT+00:00") -assert (new Date(-30610224000000).toString() == "Wed Jan 01 1000 00:00:00 GMT+00:00") +assert (new Date(-30610224000001).toString() == "Tue Dec 31 0999 23:59:59 GMT+0000") +assert (new Date(-30610224000000).toString() == "Wed Jan 01 1000 00:00:00 GMT+0000") -assert (new Date(-1).toString() == "Wed Dec 31 1969 23:59:59 GMT+00:00") -assert (new Date(0).toString() == "Thu Jan 01 1970 00:00:00 GMT+00:00") -assert (new Date(1).toString() == "Thu Jan 01 1970 00:00:00 GMT+00:00") +assert (new Date(-1).toString() == "Wed Dec 31 1969 23:59:59 GMT+0000") +assert (new Date(0).toString() == "Thu Jan 01 1970 00:00:00 GMT+0000") +assert (new Date(1).toString() == "Thu Jan 01 1970 00:00:00 GMT+0000") -assert (new Date(253402300799999).toString() == "Fri Dec 31 9999 23:59:59 GMT+00:00") -assert (new Date(253402300800000).toString() == "Sat Jan 01 10000 00:00:00 GMT+00:00") +assert (new Date(253402300799999).toString() == "Fri Dec 31 9999 23:59:59 GMT+0000") +assert (new Date(253402300800000).toString() == "Sat Jan 01 10000 00:00:00 GMT+0000") -assert (new Date (8640000000000000).toString() == "Sat Sep 13 275760 00:00:00 GMT+00:00") +assert (new Date (8640000000000000).toString() == "Sat Sep 13 275760 00:00:00 GMT+0000") assert (new Date (8640000000000001).toString() == "Invalid Date") diff --git a/tests/jerry/es2015/argument-spread.js b/tests/jerry/es2015/argument-spread.js new file mode 100644 index 00000000..3d159954 --- /dev/null +++ b/tests/jerry/es2015/argument-spread.js @@ -0,0 +1,111 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax + +function mustThrow(str) { + try { + eval(str); + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } +} + +function assertArrayEqual(actual, expected) { + assert(actual.length === expected.length); + + for (var i = 0; i < actual.length; i++) { + assert(actual[i] === expected[i]); + } +} + +// Spread syntax +function sum(x, y, z) { + return x + y + z; +} + +const numbers = [1, 2, 3]; + +assert(sum(...numbers) === 6); + +// Replace apply() +function myFunction (v, w, x, y, z) { + return v + w + x + y + z; +} +var args = [0, 1]; + +assert(myFunction (-1, ...args, 2, ...[3]) == 5); + +// Apply for new +var dateFields = [1970, 0, 1]; +var d = new Date(...dateFields); + +assert(d.toString().substring(0, 24) === "Thu Jan 01 1970 00:00:00"); + +function applyAndNew(constructor, args) { + function partial () { + return constructor.apply (this, args); + }; + if (typeof constructor.prototype === "object") { + partial.prototype = Object.create(constructor.prototype); + } + return partial; +} + +function myConstructor () { + assertArrayEqual(arguments, myArguments); + this.prop1 = "val1"; + this.prop2 = "val2"; +}; + +var myArguments = ["hi", "how", "are", "you", "mr", null]; +var myConstructorWithArguments = applyAndNew(myConstructor, myArguments); + +var obj = new myConstructorWithArguments; +assert(Object.keys(obj).length === 2); +assert(obj.prop1 === "val1"); +assert(obj.prop2 === "val2"); + +// Test spread prop call +var o = { f(a,b,c) { return a + b + c }, + g(a,b) { throw new TypeError ("5") } + }; + +assert (o.f(...["a", "b", "c"]) === "abc"); + +mustThrow ("o.g (...[1,2])") + +// Test spread super call +class MyArray extends Array { + constructor(...args) { + super(...args); + } +} + +var array = new MyArray(1, 2, 3); +assertArrayEqual(array, [1,2,3]); +assert(array instanceof MyArray); +assert(array instanceof Array); + +function argumentOrderTest() { + var result = [] + for (i = 0; i < arguments.length; i++) { + result.push(arguments[i]); + } + + return result; +} + +assertArrayEqual(argumentOrderTest(1, 2, ...[3, 4]), [1, 2, 3, 4]); diff --git a/tests/jerry/es2015/arguments-iterator.js b/tests/jerry/es2015/arguments-iterator.js new file mode 100644 index 00000000..d98499ab --- /dev/null +++ b/tests/jerry/es2015/arguments-iterator.js @@ -0,0 +1,50 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var arrayPrototypeValues = Array.prototype.values; + +function f_mapped() { + assert(typeof arguments[Symbol.iterator] === 'function'); + assert(arguments[Symbol.iterator] === arrayPrototypeValues); + assert(Object.hasOwnProperty.call(arguments, Symbol.iterator)); + + let sum = 0; + for (a of arguments) { + sum += a; + } + return sum; +}; + +function f_unmapped(b = 2) { + assert(typeof arguments[Symbol.iterator] === 'function'); + assert(arguments[Symbol.iterator] === arrayPrototypeValues); + assert(Object.hasOwnProperty.call(arguments, Symbol.iterator)); + + let sum = 0; + for (a of arguments) { + sum += a; + } + return sum; +}; + +assert(f_mapped(1, 2, 3, 4, 5) === 15); +assert(f_unmapped(1, 2, 3, 4, 5) === 15); + +Object.defineProperty(Array.prototype, "values", { get : function () { + /* should not be executed */ + assert(false); +}}); + +assert(f_mapped(1, 2, 3, 4, 5) === 15); +assert(f_unmapped(1, 2, 3, 4, 5) === 15); diff --git a/tests/jerry/es2015/array-from.js b/tests/jerry/es2015/array-from.js new file mode 100644 index 00000000..5e144790 --- /dev/null +++ b/tests/jerry/es2015/array-from.js @@ -0,0 +1,344 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Some methods are taken from v8/test/mjsunit/mjsunit.js + +function classOf(object) { + // Argument must not be null or undefined. + var string = Object.prototype.toString.call(object); + // String has format [object ]. + return string.substring(8, string.length - 1); +} + +/** + * Compares two objects for key/value equality. + * Returns true if they are equal, false otherwise. + */ +function deepObjectEquals(a, b) { + var aProps = Object.keys(a); + aProps.sort(); + var bProps = Object.keys(b); + bProps.sort(); + if (!deepEquals(aProps, bProps)) { + return false; + } + for (var i = 0; i < aProps.length; i++) { + if (!deepEquals(a[aProps[i]], b[aProps[i]])) { + return false; + } + } + return true; +} + +var assertInstanceof = function assertInstanceof(obj, type) { + if (!(obj instanceof type)) { + var actualTypeName = null; + var actualConstructor = Object.getPrototypeOf(obj).constructor; + if (typeof actualConstructor == "function") { + actualTypeName = actualConstructor.name || String(actualConstructor); + } print("Object <" + obj + "> is not an instance of <" + (type.name || type) + ">" + (actualTypeName ? " but of < " + actualTypeName + ">" : "")); + } +}; + +function deepEquals(a, b) { + if (a === b) { + if (a === 0) return (1 / a) === (1 / b); + return true; + } + if (typeof a != typeof b) return false; + if (typeof a == "number") return isNaN(a) && isNaN(b); + if (typeof a !== "object" && typeof a !== "function") return false; + var objectClass = classOf(a); + if (objectClass !== classOf(b)) return false; + if (objectClass === "RegExp") { + return (a.toString() === b.toString()); + } + if (objectClass === "Function") return false; + if (objectClass === "Array") { + var elementCount = 0; + if (a.length != b.length) { + return false; + } + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) + return false; + } + return true; + } + if (objectClass == "String" || objectClass == "Number" || objectClass == "Boolean" || objectClass == "Date") { + if (a.valueOf() !== b.valueOf()) return false; + } + return deepObjectEquals(a, b); +} + +var assertEquals = function assertEquals(expected, found, name_opt) { + if (!deepEquals(found, expected)) { + assert(false); + } +}; + +function assertArrayLikeEquals(value, expected, type) { + assertInstanceof(value, type); + assert(expected.length === value.length); + for (var i=0; i { throw 5 }); + assert(false); + } catch (e) { + assert(e === 5); + } + + return closed; +} +assert(close1()); + +function close2() { + var closed = false; + var iter = __createIterableObject([1, 2, 3], { + 'return': function() { closed = true; throw 6 } + }); + + try { + Array.from(iter, x => { throw 5 }); + assert(false); + } catch (e) { + assert(e === 5); + } + + return closed; +} +assert(close2()); + diff --git a/tests/jerry/es2015/array-isarray.js b/tests/jerry/es2015/array-isarray.js new file mode 100644 index 00000000..af492333 --- /dev/null +++ b/tests/jerry/es2015/array-isarray.js @@ -0,0 +1,48 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(Array.isArray([]) === true); +assert(Array.isArray([1]) === true); +assert(Array.isArray(new Array()) === true); +assert(Array.isArray(new Array('a', 'b', 'c', 'd')) === true); +assert(Array.isArray(new Array(3)) === true); +assert(Array.isArray(Array.prototype) === true); +assert(Array.isArray(new Proxy([], {})) === true); + +assert(Array.isArray() === false); +assert(Array.isArray({}) === false); +assert(Array.isArray(null) === false); +assert(Array.isArray(undefined) === false); +assert(Array.isArray(17) === false); +assert(Array.isArray('Array') === false); +assert(Array.isArray(true) === false); +assert(Array.isArray(false) === false); +assert(Array.isArray(new Uint8Array(32)) === false); +assert(Array.isArray({ __proto__: Array.prototype }) === false); + +var revocable = Proxy.revocable ({}, {}); +var proxy = revocable.proxy; +revocable.revoke(); + +try { + Array.isArray(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var revocable = Proxy.revocable ([], {}); +var proxy = revocable.proxy; + +assert(Array.isArray(proxy) === true); diff --git a/tests/jerry/es2015/array-new-target-support.js b/tests/jerry/es2015/array-new-target-support.js new file mode 100644 index 00000000..5165300f --- /dev/null +++ b/tests/jerry/es2015/array-new-target-support.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function F (){} +var obj = Reflect.construct (Array, [], F); +obj[2] = 'foo'; +assert (obj.length === 3 && obj instanceof F); + +try { + Reflect.construct (Array, [-1], F); +} catch (e) { + assert (e instanceof RangeError); +} + +var o = new Proxy (function f () {}, { get (t,p,r) { if (p == "prototype") { throw "Kitten" } Reflect.get (...arguments) }}) + +try { + Reflect.construct (Array, [], o) +} catch (e) { + assert (e === "Kitten"); +} diff --git a/tests/jerry/es2015/array-of.js b/tests/jerry/es2015/array-of.js new file mode 100644 index 00000000..6276337f --- /dev/null +++ b/tests/jerry/es2015/array-of.js @@ -0,0 +1,78 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test with regular inputs +var array1 = Array.of(1, 2, 3, 4, 5); +assert(array1.length === 5); +assert(array1[2] === 3); + +// Test with no input +var array2 = Array.of(); +assert(array2.length === 0); +assert(array2[0] === undefined); + +// Test when an input is another array +var array3 = Array.of(array1, 6, 7); +assert(array3.length === 3); +assert(array3[0] instanceof Array); +assert(array3[0][3] === 4); +assert(array3[2] === 7); + +// Test with undefined +var array4 = Array.of(undefined); +assert(array4.length === 1); +assert(array4[0] === undefined); + +// Test when input is an object +var obj = { + 0: 0, + 1: 1 +}; + +var array5 = Array.of(obj, 2, 3); +assert(array5[0] instanceof Object); +assert(array5[0][0] === 0); +assert(array5[0][1] === 1); +assert(array5[2] === 3); + +// Test with array holes +var array6 = Array.of.apply(null, [,,undefined]); +assert(array6.length === 3); +assert(array6[0] === undefined); + +// Test with another class +var hits = 0; +function Test() { + hits++; +} +Test.of = Array.of; + +hits = 0; +var array6 = Test.of(1, 2); +assert(hits === 1); +assert(array6.length === 2); +assert(array6[1] === 2); + +// Test with bounded builtin function +var boundedBuiltinFn = Array.of.bind(Array); +var array7 = Array.of.call(boundedBuiltinFn, boundedBuiltinFn); +assert(array7.length === 1); +assert(array7[0] === boundedBuiltinFn); + +// Test superficial features +var desc = Object.getOwnPropertyDescriptor(Array, "of"); +assert(desc.configurable === true); +assert(desc.writable === true); +assert(desc.enumerable === false); +assert(Array.of.length === 0); diff --git a/tests/jerry/es2015/array-pattern.js b/tests/jerry/es2015/array-pattern.js new file mode 100644 index 00000000..c2e3a90a --- /dev/null +++ b/tests/jerry/es2015/array-pattern.js @@ -0,0 +1,313 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +function assertArrayEqual (actual, expected) { + assert (actual.length === expected.length); + + for (var i = 0; i < actual.length; i++) { + assert (actual[i] === expected[i]); + } +} + +function mustThrow (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +} + +checkSyntax ("var [a]"); +checkSyntax ("var [a, o.a]"); +checkSyntax ("var [a, ...b,]"); +checkSyntax ("var [a, ...b = 4]"); +checkSyntax ("var [a, ...[b] = 4]"); +checkSyntax ("var [let]"); +checkSyntax ("var [get = []"); +checkSyntax ("var [get : 5]"); +checkSyntax ("var [[a = {},]"); +checkSyntax ("let [a,a] = []"); +checkSyntax ("let [a, ...a] = []"); +checkSyntax ("const [a,a] = []"); +checkSyntax ("const [a, ...a] = []"); +checkSyntax ("[new Object()] = []"); +checkSyntax ("[Object()] = []"); +checkSyntax ("[(a, b, d, c)] = []"); +checkSyntax ("[super] = []"); +checkSyntax ("[this] = []"); +checkSyntax ("[()] = []"); +checkSyntax ("try { let [$] = $;"); +checkSyntax ("let a, [ b.c ] = [6];"); +checkSyntax ("let [(a)] = [1]"); + +mustThrow ("var [a] = 4"); +mustThrow ("var [a] = 5"); +mustThrow ("var [a] = {}"); +mustThrow ("var [a] = { get [Symbol.iterator] () { throw new TypeError } }"); +mustThrow ("var [a] = { [Symbol.iterator] () {} }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return {} } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next: 5 } } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next: 5 } } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { get next() { throw new TypeError } } } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next () { } } } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next () { } } } }"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next () { return { get value () { throw new TypeError }}}}}}"); +mustThrow ("var [a] = { [Symbol.iterator] () { return { next () { return { get done () { throw new TypeError }}}}}}"); + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment + +// Basic variable assignment +(function () { + var foo = ["one", "two", "three"]; + + var [red, yellow, green] = foo; + assert (red === "one"); + assert (yellow === "two"); + assert (green === "three"); +}) (); + +// Assignment separate from declaration +(function () { + var a, b; + + [a, b] = [1, 2]; + assert (a === 1); + assert (b === 2); +}) (); + +// Default values +(function () { + var a, b; + [a = 5, b = 7] = [1]; + + assert (a === 1); + assert (b === 7); +}) (); + +// Swapping variables +(function () { + var a = 1; + var b = 3; + + [a, b] = [b, a]; + assert (a === 3); + assert (b === 1); + + var arr = [1,2,3]; + [arr[2], arr[1]] = [arr[1], arr[2]]; + assertArrayEqual (arr, [1, 3, 2]); +}) (); + +// Parsing an array returned from a function +(function () { + function f() { + return [1, 2]; + } + + var a, b; + [a, b] = f(); + assert (a === 1); + assert (b === 2); +}) (); + +// Ignoring some returned values +(function () { + function f() { + return [1, 2, 3]; + } + + var a, b; + [a, ,b] = f(); + assert (a === 1); + assert (b === 3); +}) (); + +// Ignoring some returned values +(function () { + var [a, ...b] = [1, 2, 3]; + assert (a === 1); + assertArrayEqual (b, [2, 3]); +}) (); + +// Unpacking values from a regular expression match +(function () { + function parseProtocol(url) { + var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url); + if (!parsedURL) { + return false; + } + + var [, protocol, fullhost, fullpath] = parsedURL; + return protocol; + } + + assert (parseProtocol("https://developer.mozilla.org/en-US/Web/JavaScript") === "https"); +}) (); + +// Test inner patterns I. +(function () { + let [a, [b, [c = 4, d = 5]], [e] = [6]] = [1, [2, [3,undefined]]]; + + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 5); + assert (e === 6); +}) (); + +// Test inner patterns II. +(function () { + var o = {}; + [a, b, c, o.a = 4, o.b, o.c = 3] = ["1", "2", "3", undefined, "8", "6"]; + + assert (a === "1"); + assert (b === "2"); + assert (c === "3"); + assert (o.a === 4); + assert (o.b === "8"); + assert (o.c === "6"); +}) (); + +// Test rest element I. +(function () { + var o = {}; + [...o.a] = ["1", "2", "3"]; + + assertArrayEqual (o.a, ["1", "2", "3"]); +}) (); + +// Test rest element II. +(function () { + [...[a,b,c]] = ["1", "2", "3"]; + + assert (a === "1"); + assert (b === "2"); + assert (c === "3"); +}) (); + +// Test inner object pattern I. +(function () { + [{f : a, g : b}, , , ...[c, d, e]] = [{ f : "1", g : "2"}, 3, 4, 5, 6, 7]; + + assert (a === "1"); + assert (b === "2"); + assert (c === 5); + assert (d === 6); + assert (e === 7); +}) (); + +// Multiple declaration +(function () { + var [a] = [1], [b] = [2]; + + assert (a === 1); + assert (b === 2); +}) (); + +// Force the creation of lexical environment I. +(function () { + const [a] = [1]; + eval(); + + assert (a === 1); +}) (); + +// Force the creation of lexical environment II. +(function () { + let [a] = [1]; + eval(); + + assert (a === 1); +}) (); + +// Check the parsing of AssignmentElement +(function () { + var a = 6; + [((a))] = [7]; + assert (a === 7); +}) (); + +// Test iterator closing +function __createIterableObject (arr, methods) { + methods = methods || {}; + if (typeof Symbol !== 'function' || !Symbol.iterator) { + return {}; + } + arr.length++; + var iterator = { + next: function() { + return { value: arr.shift(), done: arr.length <= 0 }; + }, + 'return': methods['return'], + 'throw': methods['throw'] + }; + var iterable = {}; + iterable[Symbol.iterator] = function () { return iterator; }; + return iterable; +}; + +(function () { + var closed = false; + var iter = __createIterableObject([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + var [a, b] = iter; + assert (closed === true); + assert (a === 1); + assert (b === 2); +}) (); + +mustThrow ("var iter = __createIterableObject([], " + + "{ get 'return'() { throw new TypeError() }});" + + "var [a] = iter"); + +mustThrow ("var iter = __createIterableObject([], " + + "{ 'return': 5 });" + + "var [a] = iter"); + +mustThrow ("var iter = __createIterableObject([], " + + "{ 'return': function() { return 5; }});" + + "var [a] = iter"); + +mustThrow ("try { throw 5 } catch (e) {" + + "var iter = __createIterableObject([], " + + "{ get 'return'() { throw new TypeError() }});" + + "var [a] = iter }"); + +mustThrow ("try { throw 5 } catch (e) {" + + "var iter = __createIterableObject([], " + + "{ 'return': 5 });" + + "var [a] = iter }"); + +mustThrow ("try { throw 5 } catch (e) {" + + "var iter = __createIterableObject([], " + + "{ 'return': function() { return 5; }});" + + "var [a] = iter }"); + +try { + eval ("var a = 0; 1 + [a] = [1]"); + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/array-prototype-copywithin.js b/tests/jerry/es2015/array-prototype-copywithin.js new file mode 100644 index 00000000..ddf1ed4d --- /dev/null +++ b/tests/jerry/es2015/array-prototype-copywithin.js @@ -0,0 +1,119 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = {}; + +// Checking behavior with normal inputs +var array = ["foo", 1, "bar", obj, 2, "baz"]; +assert(array.copyWithin(2,0,6).toString() === "foo,1,foo,1,bar,[object Object]"); +assert(array.copyWithin(0,1,3).toString() === "1,foo,foo,1,bar,[object Object]"); +assert(array.copyWithin(3,0,4).toString() === "1,foo,foo,1,foo,foo"); + +// Checking behavior with default inputs +var array = ["foo", 1, "bar", obj, 2, "baz"]; +assert(array.copyWithin().toString() === "foo,1,bar,[object Object],2,baz"); +assert(array.copyWithin(2).toString() === "foo,1,foo,1,bar,[object Object]"); +assert(array.copyWithin(1,4).toString() === "foo,bar,[object Object],1,bar,[object Object]"); + +// Checking behavior when argument is negative or bigger then length +var array = ["foo", 1, "bar", obj, 2, "baz"]; +assert(array.copyWithin(12,3,-3).toString() === "foo,1,bar,[object Object],2,baz"); +assert(array.copyWithin(-2,-4,3).toString() === "foo,1,bar,[object Object],bar,baz"); +assert(array.copyWithin(1,-5,30).toString() === "foo,1,bar,[object Object],bar,baz"); + +// Checking behavior with undefined, NaN, +/- Infinity +var array = ["foo", 1, "bar", obj, 2, "baz"]; +assert(array.copyWithin(undefined).toString() === "foo,1,bar,[object Object],2,baz"); +assert(array.copyWithin(2, NaN).toString()=== "foo,1,foo,1,bar,[object Object]"); +assert(array.copyWithin(2,undefined,5).toString() === "foo,1,foo,1,foo,1"); + +var array = ["foo", 1, "bar", obj, 2, "baz"]; +assert(array.copyWithin(Infinity,2,NaN).toString() === "foo,1,bar,[object Object],2,baz"); +assert(array.copyWithin(Infinity,-Infinity,4).toString()=== "foo,1,bar,[object Object],2,baz"); +assert(array.copyWithin(NaN,0,3).toString() === "foo,1,bar,[object Object],2,baz"); + +// Checking behavior when no length property defined +var obj = { copyWithin : Array.prototype.copyWithin }; + +obj.copyWithin(); +assert(obj.length === undefined); + +// Checking behavior when unable to get length +var obj = { copyWithin : Array.prototype.copyWithin }; +Object.defineProperty(obj, 'length', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + obj.copyWithin(1); + assert(false) +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +// Checking behavior when unable to get element +var obj = { copyWithin : Array.prototype.copyWithin, length : 5 }; +Object.defineProperty(obj, '2', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + obj.copyWithin(2); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +// Checking behavior when a property is not defined +var obj = { '0' : 2, '2' : "foo", length : 3, copyWithin : Array.prototype.copyWithin }; + +obj.copyWithin(1); +assert(obj[0] === 2); +assert(obj[1] === 2); + +function array_check(result_array, expected_array) { + assert(result_array instanceof Array); + assert(result_array.length === expected_array.length); + for (var idx = 0; idx < expected_array.length; idx++) { + assert(result_array[idx] === expected_array[idx]); + } +} + +// Remove the buffer +var array = [1, 2, 3]; +var value = array.copyWithin(0, { + valueOf: function() { + array.length = 0; + } +}) + +array_check(value, []); + +// Extend the buffer +var array = [1, 2, 3]; +var value = array.copyWithin(1, { + valueOf: function() { + array.length = 6; + } +}) + +array_check(value, [1, 1, 2, undefined, undefined, undefined]); + +// Reduce the buffer +var array = [1, 2, 3, 4, 5, 6, 7]; +var value = array.copyWithin(4, 2, { + valueOf: function() { + array.length = 3; + } +}) + +array_check(value, [1, 2, 3]); diff --git a/tests/jerry/es2015/array-prototype-fill.js b/tests/jerry/es2015/array-prototype-fill.js new file mode 100644 index 00000000..1192cc31 --- /dev/null +++ b/tests/jerry/es2015/array-prototype-fill.js @@ -0,0 +1,218 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function assertArrayEquals (array1, array2) { + if (array1.length !== array2.length) { + return false; + } + + for (var i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; +} + +assert (1 === Array.prototype.fill.length); + +assert (assertArrayEquals ([].fill (8), [])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (), [undefined, undefined, undefined, undefined, undefined])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8), [8, 8, 8, 8, 8])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, 1), [0, 8, 8, 8, 8])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, 10), [0, 0, 0, 0, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, -5), [8, 8, 8, 8, 8])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, 1, 4), [0, 8, 8, 8, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, 1, -1), [0, 8, 8, 8, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, 1, 42), [0, 8, 8, 8, 8])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, -3, 42), [0, 0, 8, 8, 8])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, -3, 4), [0, 0, 8, 8, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, -2, -1), [0, 0, 0, 8, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, -1, -3), [0, 0, 0, 0, 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (8, undefined, 4), [8, 8, 8, 8, 0])); +assert (assertArrayEquals ([ , , , , 0].fill (8, 1, 3), [, 8, 8, , 0])); +assert (assertArrayEquals ([0, 0, 0, 0, 0].fill (7.8), [7.8, 7.8, 7.8, 7.8, 7.8])); +assert (assertArrayEquals (["foo", "bar", "baz"].fill (1), [1, 1, 1])); + + +// If the range is empty, the array is not actually modified and +// should not throw, even when applied to a frozen object. +assert (assertArrayEquals (Object.freeze ([1, 2, 3]).fill (0, 0, 0), [1, 2, 3])); + +// Test exceptions +try { + Object.freeze ([0]).fill (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} +try { + Array.prototype.fill.call (null) + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} +try { + Array.prototype.fill.call (undefined) + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +function TestFillObjectWithAccessors () { + var kLength = 5; + + var log = []; + + var object = { + length: kLength, + get 1 () { + log.push ("get 1"); + return this.foo; + }, + + set 1 (val) { + log.push ("set 1 " + val); + this.foo = val; + } + }; + + Array.prototype.fill.call (object, 42); + + assert (kLength === object.length); + assert (assertArrayEquals (["set 1 42"], log)); + + for (var i = 0; i < kLength; ++i) { + assert (42 === object[i]); + } +} +TestFillObjectWithAccessors (); + +function TestFillObjectWithMaxNumberLength () { + var kMaxSafeInt = Math.pow (2, 32) - 1; + var object = {}; + object.length = kMaxSafeInt; + + Array.prototype.fill.call (object, 42, Math.pow (2, 32) - 4); + + assert (kMaxSafeInt === object.length); + assert (42 === object[kMaxSafeInt - 3]); + assert (42 === object[kMaxSafeInt - 2]); + assert (42 === object[kMaxSafeInt - 1]); +} +TestFillObjectWithMaxNumberLength (); + +function TestFillObjectWithPrototypeAccessors () { + var kLength = 5; + var log = []; + var proto = { + get 1 () { + log.push ("get 0"); + return this.foo; + }, + + set 1 (val) { + log.push ("set 1 " + val); + this.foo = val; + } + }; + + var object = { 0:0, 2:2, length: kLength}; + Object.setPrototypeOf (object, proto); + + Array.prototype.fill.call (object, "42"); + + assert (kLength === object.length); + assert (assertArrayEquals (["set 1 42"], log)); + assert (object.hasOwnProperty (0) == true); + assert (object.hasOwnProperty (1) == false); + assert (object.hasOwnProperty (2) == true); + assert (object.hasOwnProperty (3) == true); + assert (object.hasOwnProperty (4) == true); + + for (var i = 0; i < kLength; ++i) { + assert ("42" === object[i]); + } +} +TestFillObjectWithPrototypeAccessors (); + +function TestFillSealedObject () { + var object = { length: 42 }; + Object.seal (object); + + try { + Array.prototype.fill.call (object); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +} +TestFillSealedObject (); + +function TestFillFrozenObject () { + var object = { length: 42 }; + Object.freeze (object); + + try { + Array.prototype.fill.call (object); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +} +TestFillFrozenObject (); + +function array_check(result_array, expected_array) { + assert(result_array instanceof Array); + assert(result_array.length === expected_array.length); + for (var idx = 0; idx < expected_array.length; idx++) { + assert(result_array[idx] === expected_array[idx]); + } +} + + +// Remove the buffer +var array = [1, 2, 3, 4, 5]; +var value = array.fill(2, 0, { + valueOf: function() { + array.length = 0; + } +}) + +array_check(value, []); + +// Extend the buffer +var array = [1, 2, 3]; +var value = array.fill(1, { + valueOf: function() { + array.length = 6; + } +}) + +array_check(value, [1, 1, 1, undefined, undefined, undefined]); + +// Reduce the buffer +var array = [1, 2, 3, 4, 5, 6, 7]; +var value = array.fill(4, { + valueOf: function() { + array.length = 3; + } +}) + +array_check(value, [4, 4, 4]); diff --git a/tests/jerry/es2015/array-prototype-find-index.js b/tests/jerry/es2015/array-prototype-find-index.js index 8a763144..16227cde 100644 --- a/tests/jerry/es2015/array-prototype-find-index.js +++ b/tests/jerry/es2015/array-prototype-find-index.js @@ -149,7 +149,14 @@ function func (element) { /* ES v6.0 22.1.3.9.8.c Checking behavior when the first element deletes the second */ - function f() { delete arr[1]; }; - var arr = [0, 1, 2, 3]; - Object.defineProperty(arr, '0', { 'get' : f }); - Array.prototype.findIndex.call(arr, func); +function f() { delete arr[1]; }; +var arr = [0, 1, 2, 3]; +Object.defineProperty(arr, '0', { 'get' : f }); +Array.prototype.findIndex.call(arr, func); + +/* ES v6.0 22.1.3.9.8 + Checking whether predicate is called also for empty elements */ +var count = 0; + +[,,,].findIndex(function() { count++; return false; }); +assert (count == 3); diff --git a/tests/jerry/es2015/array-prototype-find.js b/tests/jerry/es2015/array-prototype-find.js index a034c56d..c987301c 100644 --- a/tests/jerry/es2015/array-prototype-find.js +++ b/tests/jerry/es2015/array-prototype-find.js @@ -146,3 +146,10 @@ function f() { delete arr[1]; }; var arr = [0, 1, 2, 3]; Object.defineProperty(arr, '0', { 'get' : f }); Array.prototype.find.call(arr, func); + +/* ES v6.0 22.1.3.8.8 + Checking whether predicate is called also for empty elements */ +var count = 0; + +[,,,].find(function() { count++; return false; }); +assert (count == 3); diff --git a/tests/jerry/es2015/array-prototype-slice.js b/tests/jerry/es2015/array-prototype-slice.js new file mode 100644 index 00000000..46308748 --- /dev/null +++ b/tests/jerry/es2015/array-prototype-slice.js @@ -0,0 +1,55 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Constructor creates longer array than expected. +class LongArray extends Array { + constructor(len) { + super (42); + this.fill ("foo"); + } +} + +var a = new LongArray (5); +a.length = 5; +var sliced = a.slice (); +assert (sliced.length == 5); +assert (JSON.stringify (sliced) == '["foo","foo","foo","foo","foo"]') + +// Constructor creates shorter array than expected. +class ShortArray extends Array { + constructor(len) { + super (2); + this.fill ("bar"); + } +} + +var b = new ShortArray (8); +b.length = 8; +b.fill ("asd", 2); +var sliced2 = b.slice (); +assert (sliced2.length == 8); +assert (JSON.stringify (sliced2) == '["bar","bar","asd","asd","asd","asd","asd","asd"]'); + +// Constructor creates array of the expected size. +class ExactArray extends Array { + constructor(len) { + super (len); + this.fill ("baz"); + } +} + +var c = new ExactArray (5); +var sliced3 = c.slice(); +assert (sliced3.length == 5); +assert (JSON.stringify (sliced3) == '["baz","baz","baz","baz","baz"]'); diff --git a/tests/jerry/es2015/array-species.js b/tests/jerry/es2015/array-species.js new file mode 100644 index 00000000..05b36ece --- /dev/null +++ b/tests/jerry/es2015/array-species.js @@ -0,0 +1,184 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test the ES2015 @@species feature + +'use strict'; + +// Subclasses of Array construct themselves under map, etc + +class MyArray extends Array { } + +function assertEquals(a, b) { + assert(a === b); +} + +assertEquals(MyArray, new MyArray().map(()=>{}).constructor); +assertEquals(MyArray, new MyArray().filter(()=>{}).constructor); +assertEquals(MyArray, new MyArray().slice().constructor); +assertEquals(MyArray, new MyArray().splice().constructor); +assertEquals(MyArray, new MyArray().concat([1]).constructor); +assertEquals(1, new MyArray().concat([1])[0]); + +// Subclasses can override @@species to return the another class + +class MyOtherArray extends Array { + static get [Symbol.species]() { return MyArray; } +} + +assertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor); +assertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor); +assertEquals(MyArray, new MyOtherArray().slice().constructor); +assertEquals(MyArray, new MyOtherArray().splice().constructor); +assertEquals(MyArray, new MyOtherArray().concat().constructor); + +// Array methods on non-arrays return arrays + +class MyNonArray extends Array { + static get [Symbol.species]() { return MyObject; } +} + +class MyObject { } + +assertEquals(MyObject, + Array.prototype.map.call(new MyNonArray(), ()=>{}).constructor); +assertEquals(MyObject, + Array.prototype.filter.call(new MyNonArray(), ()=>{}).constructor); +assertEquals(MyObject, + Array.prototype.slice.call(new MyNonArray()).constructor); +assertEquals(MyObject, + Array.prototype.splice.call(new MyNonArray()).constructor); +assertEquals(MyObject, + Array.prototype.concat.call(new MyNonArray()).constructor); + +assertEquals(undefined, + Array.prototype.map.call(new MyNonArray(), ()=>{}).length); +assertEquals(undefined, + Array.prototype.filter.call(new MyNonArray(), ()=>{}).length); +// slice, splice, and concat actually do explicitly define the length. +assertEquals(0, Array.prototype.slice.call(new MyNonArray()).length); +assertEquals(0, Array.prototype.splice.call(new MyNonArray()).length); +assertEquals(1, Array.prototype.concat.call(new MyNonArray(), ()=>{}).length); + +// Defaults when constructor or @@species is missing or non-constructor + +class MyDefaultArray extends Array { + static get [Symbol.species]() { return undefined; } +} +assertEquals(Array, new MyDefaultArray().map(()=>{}).constructor); + +class MyOtherDefaultArray extends Array { } +assertEquals(MyOtherDefaultArray, + new MyOtherDefaultArray().map(()=>{}).constructor); +MyOtherDefaultArray.prototype.constructor = undefined; +assertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor); +assertEquals(Array, new MyOtherDefaultArray().concat().constructor); + +// Exceptions propagated when getting constructor @@species throws + +class SpeciesError extends Error { } +class ConstructorError extends Error { } +class MyThrowingArray extends Array { + static get [Symbol.species]() { throw new SpeciesError; } +} + +function assertThrows (a, b) { + try { + a(); + } catch (e) { + assert(e instanceof b); + } +} + +assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError); +Object.defineProperty(MyThrowingArray.prototype, 'constructor', { + get() { throw new ConstructorError; } +}); +assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError); + +// Previously unexpected errors from setting properties in arrays throw + +class FrozenArray extends Array { + constructor(...args) { + super(...args); + Object.freeze(this); + } +} +assertThrows(() => new FrozenArray([1]).map(()=>0), TypeError); +assertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError); +assertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError); +assertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError); +assertThrows(() => new FrozenArray([]).concat([1]), TypeError); + +// Verify call counts and constructor parameters + +var count; +var params; +class MyObservedArray extends Array { + constructor(...args) { + super(...args); + params = args; + } + static get [Symbol.species]() { + count++ + return this; + } +} + +function assertArrayEquals(value, expected, type) { + assert(expected.length === value.length); + for (var i=0; i{}).constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().filter(()=>{}).constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().concat().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().slice().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().splice().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); diff --git a/tests/jerry/es2015/array-spread.js b/tests/jerry/es2015/array-spread.js new file mode 100644 index 00000000..975d50a7 --- /dev/null +++ b/tests/jerry/es2015/array-spread.js @@ -0,0 +1,79 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function assertArrayEqual (actual, expected) { + assert (actual.length === expected.length); + + for (var i = 0; i < actual.length; i++) { + assert (actual[i] === expected[i]); + } +} + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +function mustThrow (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +} + +checkSyntax ("{...a}"); +checkSyntax ("...a"); +checkSyntax ("[...]"); +checkSyntax ("[...(...)]"); +checkSyntax ("[......]"); + +mustThrow ("[...5]"); +mustThrow ("[...5, 'foo', 'bar']"); +mustThrow ("[...{}]"); +mustThrow ("[...{ get [Symbol.iterator] () { throw new TypeError } }]"); +mustThrow ("[...{ [Symbol.iterator] () {} }, 'foo']"); +mustThrow ("[...{ [Symbol.iterator] () { return {} } }]"); +mustThrow ("[...{ [Symbol.iterator] () { return { next: 5 } } }]"); +mustThrow ("[...{ [Symbol.iterator] () { return { next: 5 } } }], 'foo'"); +mustThrow ("[...{ [Symbol.iterator] () { return { get next() { throw new TypeError } } } }]"); +mustThrow ("[...{ [Symbol.iterator] () { return { next () { } } } }]"); +mustThrow ("[...{ [Symbol.iterator] () { return { next () { } } } }, 'foo']"); +mustThrow ("[...{ [Symbol.iterator] () { return { next () { return { get value () { throw new TypeError } } } } } } ]"); +mustThrow ("[...{ [Symbol.iterator] () { return { next () { return { get done () { throw new TypeError } } } } } } ]"); + +var arr1 = [0, 1, 2]; +var arr2 = [3, 4, 5]; +var arr3 = [{}, {}, {}]; +var expected = [0, 1, 2, 3 ,4, 5]; + +assertArrayEqual ([...arr1, ...arr2], [0, 1, 2, 3 ,4, 5]); +assertArrayEqual ([...arr2, ...arr1], [3 ,4, 5, 0, 1, 2]); +assertArrayEqual ([...arr1, 9, 9, 9, ...arr2], [0, 1, 2, 9, 9, 9, 3 ,4, 5]); +assertArrayEqual ([...arr1, ...[...arr2]], [0, 1, 2, 3 ,4, 5]); +assertArrayEqual (["0" , "1", ...arr1, ...[...arr2]], ["0", "1", 0, 1, 2, 3 ,4, 5]); +assertArrayEqual ([...arr3], arr3); +assertArrayEqual ([..."foobar"], ["f", "o", "o", "b", "a" ,"r"]); +assertArrayEqual ([...(new Set([1, "foo", arr3]))], [1, "foo", arr3]); + +var holyArray = [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,...arr1]; +assert (holyArray.length === 83); +assert (holyArray[82] === 2); +assert (holyArray[81] === 1); +assert (holyArray[80] === 0); diff --git a/tests/jerry/es2015/arraybuffer-isview.js b/tests/jerry/es2015/arraybuffer-isview.js new file mode 100644 index 00000000..9fb6d2b2 --- /dev/null +++ b/tests/jerry/es2015/arraybuffer-isview.js @@ -0,0 +1,37 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert(ArrayBuffer.isView() === false); +assert(ArrayBuffer.isView([]) === false); +assert(ArrayBuffer.isView({}) === false); +assert(ArrayBuffer.isView(null) === false); +assert(ArrayBuffer.isView(undefined) === false); +assert(ArrayBuffer.isView(new ArrayBuffer(10)) === false); + +assert(ArrayBuffer.isView(new Int8Array()) === true); +assert(ArrayBuffer.isView(new Uint8Array()) === true); +assert(ArrayBuffer.isView(new Uint8ClampedArray()) === true); +assert(ArrayBuffer.isView(new Int16Array()) === true); +assert(ArrayBuffer.isView(new Uint16Array()) === true); +assert(ArrayBuffer.isView(new Int32Array()) === true); +assert(ArrayBuffer.isView(new Uint32Array()) === true); +assert(ArrayBuffer.isView(new Float32Array()) === true); +assert(ArrayBuffer.isView(new Float64Array()) === true); + +assert(ArrayBuffer.isView(new Int8Array(10).subarray(0, 3)) === true); + +var buffer = new ArrayBuffer(2); +var dv = new DataView(buffer); +assert(ArrayBuffer.isView(dv) === true); diff --git a/tests/jerry/es2015/arrow-assignment.js b/tests/jerry/es2015/arrow-assignment.js new file mode 100644 index 00000000..5abadc8b --- /dev/null +++ b/tests/jerry/es2015/arrow-assignment.js @@ -0,0 +1,46 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var y = 0 +var prot = Object.getPrototypeOf(/ /) + +prot.setY = function (v) { y = v } + +assert(y === 0) +// Since arrow function is an assignment expression, this affects certain constructs +var f = x => {} +/ /.setY(5) +assert(y === 5) + +var s +// This is not a function call +assert(eval("s = x => { return 1 }\n(3)") === 3) +assert(typeof s === "function") + +// This is a function call +assert(eval("s = function () { return 1 }\n(3)") === 1) +assert(s === 1) + +var f = 5 ? x => 1 : x => 2 +assert(f() === 1) + +var f = [x => 2][0] +assert(f() === 2) + +var f = 123; f += x => y +assert(typeof f === "string") + +// Comma operator +assert(eval("x => {}, 5") === 5) diff --git a/tests/jerry/es2015/arrow-eval.js b/tests/jerry/es2015/arrow-eval.js new file mode 100644 index 00000000..84b74a85 --- /dev/null +++ b/tests/jerry/es2015/arrow-eval.js @@ -0,0 +1,41 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let a = 4 + +var f = () => { + eval("var a = 5") + assert(a === 5) +} +f() + +assert(a === 4) + +function g() { + eval("var b = 6") + + assert(b === 6) + + var h = () => delete b + h() + + try { + b + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } +} +g() diff --git a/tests/jerry/es2015/arrow-function.js b/tests/jerry/es2015/arrow-function.js index 64d499d0..0b9b8f68 100644 --- a/tests/jerry/es2015/arrow-function.js +++ b/tests/jerry/es2015/arrow-function.js @@ -100,13 +100,13 @@ default: var global_var = 7; - assert ( + assert (( ( static , package ) => { global_var = 5; return static + package } - (4, 5) == 9); + )(4, 5) == 9); assert (global_var == 5); @@ -137,14 +137,50 @@ default: must_throw ("var x => x;"); must_throw ("(()) => 0"); must_throw ("((x)) => 0"); +must_throw ("(((x))) => 0"); must_throw ("(x,) => 0"); +must_throw ("(x==6) => 0"); must_throw ("(x y) => 0"); must_throw ("(x,y,) => 0"); must_throw ("x\n => 0"); must_throw ("this => 0"); must_throw ("(true) => 0"); must_throw ("()\n=>5"); +must_throw ("3 + x => 3"); +must_throw ("3 || x => 3"); +must_throw ("a = 3 || (x,y) => 3"); +must_throw ("x => {} (4)"); +must_throw ("!x => 4"); +must_throw ("x => {} = 1"); +must_throw ("x => {} a = 1"); +must_throw ("x => {} ? 1 : 0"); +must_throw ("(x,x,x) => 0"); +must_throw ("(x,x,x) => { }"); must_throw_strict ("(package) => 0"); must_throw_strict ("(package) => { return 5 }"); must_throw_strict ("(x,x,x) => 0"); must_throw_strict ("(x,x,x) => { }"); + +var f = (a) => 1; +assert(f() === 1); + +var f = (a => 2); +assert(f() === 2); + +var f = ((((a => ((3)))))); +assert(f() === 3); + +var f = (((a) => 4)); +assert(f() === 4); + +var f = (a,b) => 5; +assert(f() === 5); + +var f = (((a,b) => 6)); +assert(f() === 6); + +var f = ((a,b) => x => (a) => 7); +assert(f()()() === 7); + +var f = (((a=1,b=2) => ((x => (((a) => 8)))))); +assert(f()()() === 8); diff --git a/tests/jerry/es2015/binary-literal.js b/tests/jerry/es2015/binary-literal.js new file mode 100644 index 00000000..ac70d014 --- /dev/null +++ b/tests/jerry/es2015/binary-literal.js @@ -0,0 +1,52 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function checkSyntaxError (str) { + try { + eval(str); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +// Test with invalid literals +checkSyntaxError("0c"); +checkSyntaxError("0b"); +checkSyntaxError("0b0123456"); +checkSyntaxError("0b2"); + +checkSyntaxError("0C"); +checkSyntaxError("0B"); +checkSyntaxError("0B2"); + +checkSyntaxError("000b01010101"); +checkSyntaxError("010b01010101"); +checkSyntaxError("11 0b01010101"); + +// Test with valid literals +assert(0b111 === 7); +assert(0b111110111 === 503); +assert(0b111101010101 === 3925); +assert(0b00000000000001 === 1); +assert(0b00000000000000 === 0); +assert(0b1101001 === parseInt ("1101001", 2)); + +assert(0B111 === 7); +assert(0B111110111 === 503); +assert(0B111101010101 === 3925); +assert(0B00000000000001 === 1); +assert(0B00000000000000 === 0); +assert(0B1101001 === parseInt ("1101001", 2)); diff --git a/tests/jerry/es2015/builtin-objects-accessor-property-configurable.js b/tests/jerry/es2015/builtin-objects-accessor-property-configurable.js new file mode 100644 index 00000000..1ac4a85b --- /dev/null +++ b/tests/jerry/es2015/builtin-objects-accessor-property-configurable.js @@ -0,0 +1,48 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var test_failed = false; + +function verifyConfigurableAccessor (obj, name, string) { + let prop = Object.getOwnPropertyDescriptor (obj, name); + if (prop.get && !prop.configurable) { + print (string + " should be configurable, but wasn't"); + test_failed = true; + } +} + +for (let builtin_name of Reflect.ownKeys (this)) { + let builtin_obj = this[builtin_name]; + if (builtin_name[0] === builtin_name[0].toUpperCase () && typeof builtin_obj == "function") { + for (let prop of Reflect.ownKeys (builtin_obj)) { + verifyConfigurableAccessor (builtin_obj, prop, builtin_name + "." + prop.toString ()); + } + + let builtin_proto = builtin_obj.prototype; + if (builtin_proto) { + for (let prop of Reflect.ownKeys (builtin_proto)) { + verifyConfigurableAccessor (builtin_proto, prop, builtin_name + ".prototype." + prop.toString ()); + } + } + + builtin_proto = Reflect.getPrototypeOf (builtin_obj); + if (builtin_proto !== Function.prototype) { + for (let prop of Reflect.ownKeys (builtin_proto.prototype)) { + verifyConfigurableAccessor (builtin_proto.prototype, prop, builtin_name + ".[[Prototype]].prototype." + prop.toString ()); + } + } + } +} + +assert (!test_failed); diff --git a/tests/jerry/es2015/builtin-prototypes.js b/tests/jerry/es2015/builtin-prototypes.js new file mode 100644 index 00000000..0a852d0e --- /dev/null +++ b/tests/jerry/es2015/builtin-prototypes.js @@ -0,0 +1,117 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var prototypes = [ + String.prototype, + Boolean.prototype, + Number.prototype, + Date.prototype, + RegExp.prototype, + Error.prototype, + EvalError.prototype, + RangeError.prototype, + ReferenceError.prototype, + SyntaxError.prototype, + TypeError.prototype, + URIError.prototype +] + +for (proto of prototypes) { + assert (Object.prototype.toString.call (proto) === '[object Object]'); +} + +try { + String.prototype.toString(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Boolean.prototype.valueOf(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Number.prototype.valueOf(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Date.prototype.valueOf(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.exec(""); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.compile("a", "u"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.source; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.global; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.ignoreCase; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.multiline; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.sticky; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + RegExp.prototype.unicode; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/class-inheritance-builtin-array.js b/tests/jerry/es2015/class-inheritance-builtin-array.js index 22aedf2a..2aac4735 100644 --- a/tests/jerry/es2015/class-inheritance-builtin-array.js +++ b/tests/jerry/es2015/class-inheritance-builtin-array.js @@ -47,7 +47,6 @@ assert (c.g () === 5); assert (c.h () === 5); -/* TODO: Enable these tests after Symbol has been implemented // Test built-in Array prototype methods var mapped = c.map ((x) => x * 2); isInstanceofArray (mapped); @@ -115,4 +114,3 @@ } catch (e) { assert (e instanceof TypeError); } -*/ diff --git a/tests/jerry/es2015/class-inheritance-early-semantics.js b/tests/jerry/es2015/class-inheritance-early-semantics.js index 68b8622b..47923817 100644 --- a/tests/jerry/es2015/class-inheritance-early-semantics.js +++ b/tests/jerry/es2015/class-inheritance-early-semantics.js @@ -107,6 +107,14 @@ must_throw ("class A extends A { }"); must_throw ("class A extends { constructor () { super () } }"); +must_throw ("class A extends a * b {}"); + +must_throw ("class A extends a = b {}"); + +must_throw ("class A extends a++ {}"); + +must_throw ("class A extends -a {}"); + class B extends A { constructor (a, b) { super (a); diff --git a/tests/jerry/es2015/class-inheritance-has-instance.js b/tests/jerry/es2015/class-inheritance-has-instance.js index 7152db9a..4d9932de 100644 --- a/tests/jerry/es2015/class-inheritance-has-instance.js +++ b/tests/jerry/es2015/class-inheritance-has-instance.js @@ -35,7 +35,7 @@ assert (secretArray instanceof Array); assert (!([] instanceof mySecretArray)); /* Add a new element to the bound function chain */ -class myEpicSecretArray extends myArray { }; +class myEpicSecretArray extends mySecretArray { }; var epicSecretArray = new myEpicSecretArray (1, 2, 3); epicSecretArray.push (4); diff --git a/tests/jerry/es2015/class-inheritance-inner-class.js b/tests/jerry/es2015/class-inheritance-inner-class.js index f92b047f..3de02982 100644 --- a/tests/jerry/es2015/class-inheritance-inner-class.js +++ b/tests/jerry/es2015/class-inheritance-inner-class.js @@ -13,6 +13,8 @@ * limitations under the License. */ +// TODO: enable this test when super keyword is supported for normal functions +/* var console = { assert : assert }; class C1 { @@ -57,3 +59,4 @@ class C2 extends C1 { } (new C2).f (); +*/ diff --git a/tests/jerry/es2015/class.js b/tests/jerry/es2015/class.js index 42d939ca..916f8ace 100644 --- a/tests/jerry/es2015/class.js +++ b/tests/jerry/es2015/class.js @@ -56,6 +56,7 @@ must_throw("class X {}; var o = {}; Object.defineProperty(o, 'p', { get: X, set: must_throw("var a = new A; class A {};"); must_throw("class A { g\\u0065t e() {} }"); must_throw('class A { "static" e() {} }'); +must_throw('class A { *constructor() {} }'); assert(eval("class A {}") === undefined); assert(eval("var a = class A {}") === undefined); @@ -64,6 +65,22 @@ assert(eval("class A { ; ; ; ;;;;;;;;;;;; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;; }") === assert(eval('class A {"constructor"() {} }') === undefined); assert(isNaN (eval('switch(1) { default: (class A{} % 1) }'))); +class A1 { + ["constructor"]() { + return 5; + } +} + +assert ((new A1).constructor() === 5); + +class A2 { + *["constructor"]() { + yield 5; + } +} + +assert ((new A2).constructor().next().value === 5); + class B { } @@ -90,6 +107,10 @@ class C { return() { return 43; } + + static *constructor() { + return 44; + } } var c = new C; @@ -99,6 +120,7 @@ assert (c["3"]() === 3); assert (c.super() === 42); assert (c.return() === 43); assert (c.constructor === C); +assert (C.constructor().next().value === 44); class D { constructor(d) { @@ -236,3 +258,77 @@ assert (G.get() == 11); assert (G.set() == 12); G.constructor = 30; assert (G.constructor === 30); + +class H { + method() { assert (typeof H === 'function'); return H; } +} + +let H_original = H; +var H_method = H.prototype.method; +C = undefined; +assert(C === undefined); +C = H_method(); +assert(C === H_original); + +var I = class C { + method() { assert(typeof C === 'function'); return C; } +} + +let I_original = I; +var I_method = I.prototype.method; +I = undefined; +assert(I === undefined); +I = I_method(); +assert(I == I_original); + +var J_method; +class J { + static [(J_method = eval('(function() { return J; })'), "X")]() {} +} +var J_original = J; +J = 6; +assert (J_method() == J_original); + +var K_method; +class K { + constructor () { + K_method = function() { return K; } + } +} +var K_original = K; +new K; +K = 6; +assert (K_method() == K_original); + +var L_method; +class L extends (L_method = function() { return L; }) { +} +var L_original = L; +L = 6; +assert (L_method() == L_original); + +/* Test cleanup class environment */ +try { + class A { + [d]() {} + } + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + +try { + class A extends d {} + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} +try { + var a = 1 + 2 * 3 >> class A extends d {}; + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/const1.js b/tests/jerry/es2015/const1.js new file mode 100644 index 00000000..6ba7322b --- /dev/null +++ b/tests/jerry/es2015/const1.js @@ -0,0 +1,74 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const a = 6 +assert(!delete a) +assert(a === 6) + +try { + eval("a = 7") + assert(false) +} catch (e) { + assert(e instanceof TypeError) +} + +function check_type_error(code) { + try { + eval(code) + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } +} + +// Register cases +check_type_error("{ const a = 0; a = 1 }"); +check_type_error("{ const a = 0; a += 1 }"); +check_type_error("{ const a = 0; a -= 1 }"); +check_type_error("{ const a = 0; a *= 1 }"); +check_type_error("{ const a = 0; a %= 1 }"); +check_type_error("{ const a = 0; a /= 1 }"); +check_type_error("{ const a = 0; a <<= 1 }"); +check_type_error("{ const a = 0; a >>= 1 }"); +check_type_error("{ const a = 0; a >>>= 1 }"); +check_type_error("{ const a = 0; a &= 1 }"); +check_type_error("{ const a = 0; a |= 1 }"); +check_type_error("{ const a = 0; a ^= 1 }"); +check_type_error("{ const a = 0; a++ }"); +check_type_error("{ const a = 0; a-- }"); +check_type_error("{ const a = 0; ++a }"); +check_type_error("{ const a = 0; --a }"); +check_type_error("{ const a = 0; [a] = [1] }"); +check_type_error("{ const a = 0; ({a} = { a:1 }) }"); + +// Non-register cases +check_type_error("{ const a = 0; (function (){ a = 1 })() }"); +check_type_error("{ const a = 0; (function (){ a += 1 })() }"); +check_type_error("{ const a = 0; (function (){ a -= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a *= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a %= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a /= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a <<= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a >>= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a >>>= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a &= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a |= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a ^= 1 })() }"); +check_type_error("{ const a = 0; (function (){ a++ })() }"); +check_type_error("{ const a = 0; (function (){ a-- })() }"); +check_type_error("{ const a = 0; (function (){ ++a })() }"); +check_type_error("{ const a = 0; (function (){ --a })() }"); +check_type_error("{ const a = 0; (function (){ [a] = [1] })() }"); +check_type_error("{ const a = 0; (function (){ ({a} = { a:1 }) })() }"); diff --git a/tests/jerry/es2015/continue.js b/tests/jerry/es2015/continue.js new file mode 100644 index 00000000..8a3339d2 --- /dev/null +++ b/tests/jerry/es2015/continue.js @@ -0,0 +1,44 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +for (var i = 0; i < 1000; i++) +{ + switch (1) + { + default: + /* This block must not be enclosed in braces. */ + let j = eval(); + continue; + } +} + +next: +for (var i = 0; i < 1000; i++) +{ + for (let j = eval(); true; ) + { + continue next; + } +} + +next: +for (var i = 0; i < 1000; i++) +{ + for (let j in {a:1}) + { + eval() + continue next; + } +} diff --git a/tests/jerry/es2015/dataview.js b/tests/jerry/es2015/dataview.js index 6faa2bc3..020a1e89 100644 --- a/tests/jerry/es2015/dataview.js +++ b/tests/jerry/es2015/dataview.js @@ -168,11 +168,10 @@ gettersSetters.forEach (function (propName) { var view = new DataView (buffer) /* ES2015 24.2.1.{1, 2}.6 (numberIndex != getIndex) */ - try { - view[propName] (1.5); - assert (false); - } catch (e) { - assert (e instanceof RangeError); + if (propName.indexOf("get") !== -1) { + assert(view[propName] (1.5) === 0); + } else { + assert(view[propName] (1.5) === undefined); } /* ES2015 24.2.1.{1, 2}.6 (getIndex < 0) */ diff --git a/tests/jerry/es2015/date-prototype-toprimitive.js b/tests/jerry/es2015/date-prototype-toprimitive.js new file mode 100644 index 00000000..7ee4509f --- /dev/null +++ b/tests/jerry/es2015/date-prototype-toprimitive.js @@ -0,0 +1,51 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var dateObj = new Date("1997-04-10"); +var dateNaN = new Date(NaN); + +// Test with default hint +var result = dateObj[Symbol.toPrimitive]("default"); +assert(result.toString().substring(0,15) === "Thu Apr 10 1997"); +result = dateNaN[Symbol.toPrimitive]("default"); +assert(dateNaN == "Invalid Date"); + +// Test with number hint +result = dateObj[Symbol.toPrimitive]("number"); +assert(result.toString() === "860630400000"); +result = dateNaN[Symbol.toPrimitive]("number"); +assert(isNaN(result) === true); + +// Test with string hint +result = dateObj[Symbol.toPrimitive]("string"); +assert(result.toString().substring(0,15) === "Thu Apr 10 1997"); +result = dateNaN[Symbol.toPrimitive]("string"); +assert(result == "Invalid Date"); + +// Test with invalid hint +try { + result = dateObj[Symbol.toPrimitive](90); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// Test when unable to call toPrimitive +try { + Date.prototype[Symbol.toPrimitive].call(undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/directive.js b/tests/jerry/es2015/directive.js new file mode 100644 index 00000000..e275e1b4 --- /dev/null +++ b/tests/jerry/es2015/directive.js @@ -0,0 +1,35 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +eval("function f(a, b = 4) { }") +check_syntax_error ("function f(a, b = 4) { 'use strict' }") + +eval('function f(...a) { }') +check_syntax_error ('function f(...a) { "use strict" }') + +eval("({ f([a,b]) { } })") +check_syntax_error ("({ f([a,b]) { 'use strict' } })") + +eval("function f(a, b = 4) { 'directive1'\n'directive2'\n }") +check_syntax_error ("function f(a, b = 4) { 'directive1'\n'directive2'\n'use strict' }") diff --git a/tests/jerry/es2015/error.js b/tests/jerry/es2015/error.js new file mode 100644 index 00000000..4f1daa53 --- /dev/null +++ b/tests/jerry/es2015/error.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Prototype of NativeErrors should be Error */ +assert(Object.getPrototypeOf(EvalError) === Error); +assert(Object.getPrototypeOf(RangeError) === Error); +assert(Object.getPrototypeOf(ReferenceError) === Error); +assert(Object.getPrototypeOf(SyntaxError) === Error); +assert(Object.getPrototypeOf(TypeError) === Error); +assert(Object.getPrototypeOf(URIError) === Error); diff --git a/tests/jerry/es2015/exponentiation.js b/tests/jerry/es2015/exponentiation.js new file mode 100644 index 00000000..e4a296c1 --- /dev/null +++ b/tests/jerry/es2015/exponentiation.js @@ -0,0 +1,73 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var two = 2 +var three = 3 + +// Precedence (right-to-left) tests +assert(2 ** 3 ** 2 === 512) +assert((2 ** 3) ** 2 === 64) +assert(2 ** (3 ** 2) === 512) +assert(two ** three ** two === 512) +assert((two ** three) ** two === 64) +assert(two ** (three ** two) === 512) + +assert(2 ** 2 * 3 ** 3 === 4 * 27) +assert(two ** two * three ** three === 4 * 27) + +var a = 3 +assert((a **= 3) === 27) +assert(a === 27) + +a = 2 +assert((a **= a **= 2) === 16) +assert(a === 16) + +function assertThrows(src) { + try { + eval(src) + assert(false) + } catch (e) { + assert(e instanceof SyntaxError) + } +} + +assertThrows("-2 ** 2") +assertThrows("+a ** 2") +assertThrows("!a ** 2") +assertThrows("~a ** 2") +assertThrows("void a ** 2") +assertThrows("typeof a ** 2") +assertThrows("delete a ** 2") +assertThrows("!(-a) ** 2") + +assert((-2) ** 2 === 4) + +a = 3 +assert((-+-a) ** 3 === 27) + +a = 0 +assert((!a) ** 2 === 1) + +a = 0 +assert(isNaN((void a) ** 3)) + +a = -4 +assert(++a ** 2 === 9) +assert(a === -3) + +a = -2 +assert(a-- ** 2 === 4) +assert(a === -3) diff --git a/tests/jerry/es2015/for-let-reference-error.js b/tests/jerry/es2015/for-let-reference-error.js new file mode 100644 index 00000000..508127ca --- /dev/null +++ b/tests/jerry/es2015/for-let-reference-error.js @@ -0,0 +1,30 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +function check_reference_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof ReferenceError) + } +} + +check_reference_error("for (let x of [x]) {}") +check_reference_error("for (const x of [x]) {}") + +check_reference_error("for (let x in {x}) {}") +check_reference_error("for (const x in {x}) {}") diff --git a/tests/jerry/es2015/for-let.js b/tests/jerry/es2015/for-let.js new file mode 100644 index 00000000..0967d947 --- /dev/null +++ b/tests/jerry/es2015/for-let.js @@ -0,0 +1,105 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var arr = []; +for (let i = 0, j = 0; i < 10; j++) +{ + arr[i] = function() { return i + j; } + i++; +} + +for (let i = 0; i < 10; i++) + assert(arr[i]() === (i * 2 + 1)); + +var j = 0, k = 0; +for (let i = 0; j = i, i < 10; i++) +{ + let i = -3; + assert(i === -3); + assert(j === k); + k++; +} + +var j = 0, k = 0; +for (let i = 0; eval("j = i"), i < 10; i++) +{ + let i = -3; + assert(i === -3); + assert(j === k); + k++; +} + +var arr = []; +for (let i in { x:1, y:1, z:1 }) +{ + let str = "P"; + arr.push(function () { return str + i; }); +} + +assert(arr[0]() === "Px"); +assert(arr[1]() === "Py"); +assert(arr[2]() === "Pz"); + +try { + for (let i in (function() { return i; })()) {} + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + +try { + for (let i = 0, j = 0; i < 5; i++, j++) + { + if (i === 3) + { + eval("throw -42") + } + } + assert(false); +} catch (e) { + assert(e === -42); +} + +exit: { + for (let i = 0, j = 0; i < 5; i++, j++) + { + if (eval("i === 3")) { + assert(i === 3); + break exit; + } + } + assert(false); +} + +var f = null, g = null, h = null; + +for (let i = 0; + f = function() { return i }, i < 1; + i++, g = function() { return i }) +{ + h = function() { return i }; +} +assert(f() === 1); +assert(g() === 1); +assert(h() === 0); + +var arr = []; +for (const i in { aa:4, bb:5, cc:6 }) +{ + arr.push(function () { return i }); +} + +assert(arr[0]() === "aa"); +assert(arr[1]() === "bb"); +assert(arr[2]() === "cc"); diff --git a/tests/jerry/es2015/for-of-iterator-close.js b/tests/jerry/es2015/for-of-iterator-close.js new file mode 100644 index 00000000..54a85932 --- /dev/null +++ b/tests/jerry/es2015/for-of-iterator-close.js @@ -0,0 +1,244 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +function close1() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + for (var it of iter) break; + return closed; +} + +assert(close1()); + +function close2() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + try { + for (var it of iter) throw 0; + assert(false); + } catch(e){ + assert(e === 0); + } + return closed; +} + +assert(close2()); + +function close3() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + for (var it of iter) continue; + return closed; +} + +assert(!close3()); + +function close4() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; throw 6; } + }); + try { + for (var it of iter) throw 5; + assert(false); + } catch(e) { + assert(e === 5); + } + return closed; +} + +assert(close4()); + +function close5() { + var closed_called = 0; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed_called++; throw 6; } + }); + try { + for (var it of iter) { + for (var it of iter) { + throw 5; + } + assert(false); + } + assert(false); + } catch(e) { + assert(e === 5); + } + return closed_called === 2; +} + +assert(close5()); + +function close6() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + for (var it of iter) {}; + + return closed; +} + +assert(!close6()); + +var close7_result = false; +function close7() { + var iter = createIterable([1, 2, 3], { + 'return': function() { close7_result = true; throw "5"; } + }); + + for (var it of iter) { + return "foo"; + } +} + +try { + close7(); + assert(false); +} catch (e) { + assert(close7_result); + assert(e === "5"); +} + +function close8() { + var iter = createIterable([1, 2, 3], { + 'return': function() { close8_result = true; throw "5"; } + }); + + for (var it of iter) { + throw "foo"; + } +} + +var close8_result = false; +try { + close8(); + assert(false); +} catch (e) { + assert(e === "foo"); + assert(close8_result); +} + +function close9() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; throw "5"; } + }); + + try { + for (var it of iter) { + break; + } + } finally { + assert(closed); + throw "foo" + } +} + +try { + close9(); + assert(false); +} catch (e) { + assert(e === "foo"); +} + +function close10() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; return {}; } + }); + + try { + for (var it of iter) { + return "foo"; + } + } finally { + assert(closed); + throw "bar"; + } +} + +try { + close10(); + assert(false); +} catch (e) { + assert(e === "bar"); +} + +function close11() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; throw "5"; } + }); + + try { + for (var it of iter) { + return "foo"; + } + } finally { + assert(closed); + throw "bar"; + } +} + +try { + close11(); + assert(false); +} catch (e) { + assert(e === "bar"); +} + +function close12() { + var closed = false; + var iter = createIterable([1, 2, 3], { + 'return': function() { closed = true; throw "5"; } + }); + + try { + for (var it of iter) { + throw "foo"; + } + } finally { + assert(closed); + throw "bar"; + } +} + +try { + close12(); + assert(false); +} catch (e) { + assert(e === "bar"); +} diff --git a/tests/jerry/es2015/for-pattern.js b/tests/jerry/es2015/for-pattern.js new file mode 100644 index 00000000..bbcb4da7 --- /dev/null +++ b/tests/jerry/es2015/for-pattern.js @@ -0,0 +1,77 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var idx = 0; +for (var [a,b] of [[1,2], [3,4]]) +{ + if (idx == 0) + { + assert(a === 1); + assert(b === 2); + idx = 1; + } + else + { + assert(a === 3); + assert(b === 4); + } +} + +assert(a === 3); +assert(b === 4); + +idx = 0; +for (let [a,b] of [[5,6], [7,8]]) +{ + if (idx == 0) + { + assert(a === 5); + assert(b === 6); + idx = 1; + } + else + { + assert(a === 7); + assert(b === 8); + } +} + +assert(a === 3); +assert(b === 4); + +idx = 0; +for (let [a,b] of [[11,12], [13,14]]) +{ + if (idx == 0) + { + eval("assert(a === 11)"); + eval("assert(b === 12)"); + idx = 1; + } + else + { + eval("assert(a === 13)"); + eval("assert(b === 14)"); + } +} + +assert(a === 3); +assert(b === 4); + +try { + eval("for (let [a,b] = [1,2] of [[3,4]]) {}"); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/forin-header-strict.js b/tests/jerry/es2015/forin-header-strict.js new file mode 100644 index 00000000..d06e6091 --- /dev/null +++ b/tests/jerry/es2015/forin-header-strict.js @@ -0,0 +1,61 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; +try { + eval('for (var i = 0 in {}) {}'); + assert(false); +} catch(e) { + assert(e instanceof SyntaxError); +} + +try { + eval('for (var = i of {}) {}'); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + +var reached = false; + +for (var i in {}) { + reached = true; +} +assert(!reached); + +for (var i of []) { + reached = true; +} +assert(!reached); + +for (let i in {}) { + reached = true; +} +assert(!reached); + +for (let i of []) { + reached = true; +} +assert(!reached); + +for (const i in {}) { + reached = true; +} +assert(!reached); + +for (const i of []) { + reached = true; +} +assert(!reached); diff --git a/tests/jerry/es2015/function-accessor.js b/tests/jerry/es2015/function-accessor.js new file mode 100644 index 00000000..d8c3c7b5 --- /dev/null +++ b/tests/jerry/es2015/function-accessor.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var g = (Object.getOwnPropertyDescriptor({get a(){}}, 'a')).get; + +try { + new g; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var s = (Object.getOwnPropertyDescriptor({set a(value){}}, 'a')).set; + +try { + new s; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/function-arguments-caller.js b/tests/jerry/es2015/function-arguments-caller.js new file mode 100644 index 00000000..3eb2b958 --- /dev/null +++ b/tests/jerry/es2015/function-arguments-caller.js @@ -0,0 +1,47 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var props = ['arguments', 'caller']; + +function f_simple () { +} + +function f_strict () { + "use strict"; +} + +for (let prop of props) { + try { + Function.prototype[prop]; + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } + + assert(f_simple[prop] === null); + + try { + f_strict[prop]; + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } + + let desc = Object.getOwnPropertyDescriptor(f_simple, prop); + assert(desc.value === null); + assert(desc.writable === false); + assert(desc.enumerable === false); + assert(desc.configurable === false); + assert(Object.getOwnPropertyDescriptor(f_strict, prop) === undefined); +} diff --git a/tests/jerry/es2015/function-async1.js b/tests/jerry/es2015/function-async1.js new file mode 100644 index 00000000..17907e58 --- /dev/null +++ b/tests/jerry/es2015/function-async1.js @@ -0,0 +1,146 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* This test checks async modifiers (nothing else). */ + +function check_promise(p, value) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(v === value) + }) +} + +/* Async functions */ + +async function f(a) { + return a +} + +check_promise(f(1), 1) + +f = async function (a) { return a } +check_promise(f(2), 2) + +f = (async function (a) { return a }) +check_promise(f(3), 3) + +f = [async function (a) { return a }] +check_promise(f[0](4), 4) + +/* These four are parser tests. */ +async => {} +async async => {} +(async => {}) +(async async => {}) + +f = async => async; +assert(f(5) === 5) + +f = async async => async; +check_promise(f(6), 6) + +f = (async => async) +assert(f(7) === 7) + +f = (async async => async) +check_promise(f(8), 8) + +f = [async => async] +assert(f[0](9) === 9) + +f = [async async => async] +check_promise(f[0](10), 10) + +f = async (a, b) => a + b; +check_promise(f(10, 1), 11) + +f = (async (a, b) => a + b); +check_promise(f(10, 2), 12) + +f = [async (a, b) => a + b]; +check_promise(f[0](10, 3), 13) + +f = true ? async () => 14 : 0; +check_promise(f(), 14) + +f = (1, async async => async) +check_promise(f(15), 15) + +/* Functions contain async references */ + +function f1() { + var async = 1; + + /* The arrow function after the newline should be ignored. */ + var v1 = async + async => async + + /* The function statement after the newline should not be an async function. */ + var v2 = async + function g() { return 2 } + + async + function h() { return 3 } + + assert(v1 === 1) + assert(v2 === 1) + assert(g() === 2) + assert(h() === 3) +} +f1(); + +function f2() { + var async = 1; + + function g() { async = 2; } + g(); + + assert(async == 2); +} +f2(); + +function f3() { + var v = 3; + var async = () => v = 4; + + function g() { async(); } + g(); + + assert(v === 4); +} +f3(); + +function f4() { + var v = 5; + var async = (a, b) => v = a + b; + + function g() { async(((v)), ((v))); } + g(); + + assert(v === 10); +} +f4(); + +function f5() { + var v = 0; + var async = (a, b) => v = a + b; + + function g() { async((async(1,2)), ((async(3,4)))); } + g(); + + assert(v === 10); +} +f5(); diff --git a/tests/jerry/es2015/function-async2.js b/tests/jerry/es2015/function-async2.js new file mode 100644 index 00000000..3ae9947e --- /dev/null +++ b/tests/jerry/es2015/function-async2.js @@ -0,0 +1,69 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* This test checks async modifiers (nothing else). */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error("function async f() {}") +check_syntax_error("(a,b) async => 1") +/* SyntaxError because arrow declaration is an assignment expression. */ +check_syntax_error("async * (a,b) => 1") +check_syntax_error("({ *async f() {} })") +check_syntax_error("class C { async static f() {} }") +check_syntax_error("class C { * async f() {} }") +check_syntax_error("class C { static * async f() {} }") + + +function check_promise(p, value) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(v === value) + }) +} + +var o = { + async f() { return 1 }, + async() { return 2 }, + async *x() {}, /* Parser test, async iterators are needed to work. */ +} + +check_promise(o.f(), 1) +assert(o.async() === 2) + +class C { + async f() { return 3 } + async *x() {} /* Parser test, async iterators are needed to work. */ + static async f() { return 4 } + static async *y() {} /* Parser test, async iterators are needed to work. */ + async() { return 5 } + static async() { return 6 } +} + +var c = new C + +check_promise(c.f(), 3) +check_promise(C.f(), 4) +assert(c.async() === 5) +assert(C.async() === 6) diff --git a/tests/jerry/es2015/function-await1.js b/tests/jerry/es2015/function-await1.js new file mode 100644 index 00000000..e616b057 --- /dev/null +++ b/tests/jerry/es2015/function-await1.js @@ -0,0 +1,138 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* This test checks await expressions (nothing else). */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error("(async function await() {})") +check_syntax_error("(async function *await() {})") +check_syntax_error("async function f(await) {}") +check_syntax_error("(async function f(await) {})") +check_syntax_error("async function f(a = await new Promise) {}") +check_syntax_error("async function f() { function await() {} }") +check_syntax_error("async await => 0"); +check_syntax_error("async (await) => 0"); +check_syntax_error("async function f() { await () => 0 }"); +check_syntax_error("async (a) => a\\u0077ait a"); +check_syntax_error("async (a) => { () => 0\na\\u0077ait a }"); + +// Valid uses of await + +async a => await a +async a => { await a } +async (a) => await a +async(a) => { await a } + +// Nested async and non-async functions + +async (a) => { + () => await + await a +} + +(a) => { + await + async (a) => await a + await + async (a) => await a + a\u0077ait +} + +async function f1(a) { + await a + (function () { await ? async function(a) { await a } : await }) + await a +} + +async (a) => { + await a; + () => await ? async (a) => await a : await + await a +} + +async (a) => { + (a = () => await, [b] = (c)) + await a + (a, b = () => await) + await a +} + +// Object initializers + +var o = { + async await(a) { + await a; + () => await + await a + }, + + f(a) { + await + async (a) => await a + await + async (a) => await a + a\u0077ait + }, + + async ["g"] () { + await a; + () => await + await a + } +} + +async function f2(a) { + var o = { + [await a]() { await % await } + } + await a; +} + +class C { + async await(a) { + await a; + () => await + await a + } + + f(a) { + await + async (a) => await a + await + async (a) => await a + a\u0077ait + } + + async ["g"] () { + await a; + () => await + await a + } +} + +async function f3(a) { + class C { + [await a]() { await % await } + } + await a; +} diff --git a/tests/jerry/es2015/function-call.js b/tests/jerry/es2015/function-call.js new file mode 100644 index 00000000..74a60681 --- /dev/null +++ b/tests/jerry/es2015/function-call.js @@ -0,0 +1,38 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +function f(...a) +{ + return a.length +} + +check_syntax_error ("f(,)") +check_syntax_error ("f(,1)") +check_syntax_error ("f(1,,)") +check_syntax_error ("f(1,,2)") + +assert(f(10) === 1) +assert(f(10,) === 1) +assert(f(10,11) === 2) +assert(f(10,11,) === 2) diff --git a/tests/jerry/es2015/function-if.js b/tests/jerry/es2015/function-if.js new file mode 100644 index 00000000..3cce20b2 --- /dev/null +++ b/tests/jerry/es2015/function-if.js @@ -0,0 +1,119 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error ("'use strict'; if (true) function f() {}") +check_syntax_error ("'use strict'; if (true) ; else function f() {}") +check_syntax_error ("'use strict'; a: function f() {}") +check_syntax_error ("if (true) async function f() {}") +check_syntax_error ("if (true) ; else async function f() {}") +check_syntax_error ("if (true) a: function f() {}") +check_syntax_error ("if (true) ; else a: function f() {}") + +var g = 1 +var h = 1 + +function f1(p) +{ + assert(g === undefined) + assert(h === undefined) + + if (p) + // Same as: { function g() { return 3 } } + function g() { return 3 } + else + // Same as: { function h() { return 4 } } + function h() { return 4 } + + if (p) { + assert(g() === 3) + assert(h === undefined) + } else { + assert(g === undefined) + assert(h() === 4) + } +} + +f1(true) +f1(false) + +function f2() +{ + assert(g() === 2) + a: b: c: d: function g() { return 2 } + + assert(h === undefined) + + { + assert(h() === 3) + a: b: c: d: function h() { return 3 } + } + + assert(h() === 3) + + try { + assert(h() === 4) + a: b: c: d: function h() { return 4 } + throw 1 + } catch (e) { + assert(h() === 5) + a: b: c: d: function h() { return 5 } + } finally { + assert(h() === 6) + a: b: c: d: function h() { return 6 } + } + + assert(h() === 6) + + switch (1) { + default: + assert(h() === 7) + a: b: c: d: function h() { return 7 } + } + + assert(h() === 7) +} +f2() + +function f3() +{ + assert(h === undefined) + + { + let a = eval("1") + assert(a === 1) + assert(h() === 1) + a: b: c: d: function h() { return 1 } + } + + assert(h() === 1) + + { + eval("a: b: c: d: function h() { return 2 }") + assert(h() === 2) + } + + assert(h() === 2) +} +f3() diff --git a/tests/jerry/es2015/function-name.js b/tests/jerry/es2015/function-name.js new file mode 100644 index 00000000..f2a9e4fe --- /dev/null +++ b/tests/jerry/es2015/function-name.js @@ -0,0 +1,297 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function assertNameExists(func) { + assert(func.hasOwnProperty('name') === true); +} +function assertNameNotExists(func) { + assert(func.hasOwnProperty('name') === false); + assert(Function.prototype.name === ''); + assert(func.name === ''); +} + +function assertConfigurableOnlyMethod(func) { + let desc = Object.getOwnPropertyDescriptor(func, 'name'); + assert(desc.configurable === true); + assert(desc.writable === false); + assert(desc.enumerable === false); + + delete func.name; + assertNameNotExists(func); + + Object.defineProperty(func, 'name', {value: 'newName', configurable: true}); + assert (Object.getOwnPropertyDescriptor(func, 'name').value === 'newName'); + assertNameExists(func); + + delete func.name; + assertNameNotExists(func); + Object.defineProperty(func, 'name', desc); +} + +function assertConfigurableOnlyAccessor(func, name, method) { + let accessor = Object.getOwnPropertyDescriptor(func, name)[method]; + assertConfigurableOnlyMethod(accessor); +} + +function assertMethodName(func, name, functionName = name) { + assertNameExists(func); + assertConfigurableOnlyMethod(func) + assert(Object.getOwnPropertyDescriptor(func, 'name').value === functionName) +} + +function assertGetterName(obj, name, functionName = name) { + assertConfigurableOnlyAccessor(obj, name, 'get'); + assert(Object.getOwnPropertyDescriptor(obj, name).get['name'] === 'get ' + functionName) +} + +function assertSetterName(obj, name, functionName = name) { + assertConfigurableOnlyAccessor(obj, name, 'set'); + assert(Object.getOwnPropertyDescriptor(obj, name).set['name'] === 'set ' + functionName) +} + +var func1 = function () {}; +assertMethodName(func1, 'func1'); + +var func2 = function bar() {}; +assertMethodName(func2, 'bar'); + +var func3 = (function () {}).prototype.constructor; +assert(typeof func3 === 'function'); +assertNameNotExists(func3); + +var func4; +func4 = function () {} +assertMethodName(func4, 'func4'); + +var func5; +func5 = function bar () {} +assertMethodName(func5, 'bar'); + +var func6; +(func6) = function () {} +assertNameNotExists(func6); + +var func7; +(func7) = function bar () {} +assertMethodName(func7, 'bar'); + +let emptySymbolMethod = Symbol(); +let namedSymbolMethod = Symbol('foo'); +let emptySymbolGetter = Symbol(); +let namedSymbolGetter = Symbol('foo'); +let emptySymbolSetter = Symbol(); +let namedSymbolSetter = Symbol('foo'); + +var o = { + func1() {}, + func2: function () {}, + func3: function bar() {}, + func4: () => {}, + func5: class {}, + func6: class A {}, + func7: class name { static name () {} }, + ['func' + '8']() {}, + ['func' + '9']: function () {}, + ['func' + '10']: function bar() {}, + ['func' + '11']: () => {}, + ['func' + '12']: class {}, + ['func' + '13']: class A {}, + ['func' + '14']: class name { static name () {} }, + get func15() {}, + get ['func' + '16']() {}, + set func17(a) {}, + set ['func' + '18'](a) {}, + [emptySymbolMethod]() {}, + [namedSymbolMethod]() {}, + get [emptySymbolGetter]() {}, + get [namedSymbolGetter]() {}, + set [emptySymbolSetter](a) {}, + set [namedSymbolSetter](a) {}, +} + +assertMethodName(o.func1, 'func1'); +assertMethodName(o.func2, 'func2'); +assertMethodName(o.func3, 'bar'); +assertMethodName(o.func4, 'func4'); +assertMethodName(o.func5, 'func5'); +assertMethodName(o.func6, 'A'); +assert(typeof o.func7 === 'function'); + +assertMethodName(o.func8, 'func8'); +assertMethodName(o.func9, 'func9'); +assertMethodName(o.func10, 'bar'); +assertMethodName(o.func11, 'func11'); +assertMethodName(o.func12, 'func12'); +assertMethodName(o.func13, 'A'); +assert(typeof o.func14 === 'function'); + +assertGetterName(o, 'func15'); +assertGetterName(o, 'func16'); +assertSetterName(o, 'func17'); +assertSetterName(o, 'func17'); + +assertMethodName(o[emptySymbolMethod], ''); +assertMethodName(o[namedSymbolMethod], '[foo]'); +assertGetterName(o, emptySymbolGetter, ''); +assertGetterName(o, namedSymbolGetter, '[foo]'); +assertSetterName(o, emptySymbolSetter, ''); +assertSetterName(o, namedSymbolSetter, '[foo]'); + +class A { + constructor () {} + func1() {} + get func2() {} + set func3(a) {} + + static func4() {} + static get func5() {} + static set func6(a) {} + + ['func' + '7']() {} + get ['func' + '8']() {} + set ['func' + '9'](a) {} + + static ['func' + '10']() {} + static get ['func' + '11']() {} + static set ['func' + '12'](a) {} + + [emptySymbolMethod]() {} + [namedSymbolMethod]() {} + get [emptySymbolGetter]() {} + get [namedSymbolGetter]() {} + set [emptySymbolSetter](a) {} + set [namedSymbolSetter](a) {} + + static [emptySymbolMethod]() {} + static [namedSymbolMethod]() {} + static get [emptySymbolGetter]() {} + static get [namedSymbolGetter]() {} + static set [emptySymbolSetter](a) {} + static set [namedSymbolSetter](a) {} +} + +assertMethodName(A.prototype.func1, 'func1'); +assertGetterName(A.prototype, 'func2'); +assertSetterName(A.prototype, 'func3'); + +assertMethodName(A.func4, 'func4'); +assertGetterName(A, 'func5'); +assertSetterName(A, 'func6'); + +assertMethodName(A.prototype.func7, 'func7'); +assertGetterName(A.prototype, 'func8'); +assertSetterName(A.prototype, 'func9'); + +assertMethodName(A.func10, 'func10'); +assertGetterName(A, 'func11'); +assertSetterName(A, 'func12'); + +assertMethodName(A[emptySymbolMethod], ''); +assertMethodName(A[namedSymbolMethod], '[foo]'); +assertGetterName(A, emptySymbolGetter, ''); +assertGetterName(A, namedSymbolGetter, '[foo]'); +assertSetterName(A, emptySymbolSetter, ''); +assertSetterName(A, namedSymbolSetter, '[foo]'); + +assertMethodName(A.prototype[emptySymbolMethod], ''); +assertMethodName(A.prototype[namedSymbolMethod], '[foo]'); +assertGetterName(A.prototype, emptySymbolGetter, ''); +assertGetterName(A.prototype, namedSymbolGetter, '[foo]'); +assertSetterName(A.prototype, emptySymbolSetter, ''); +assertSetterName(A.prototype, namedSymbolSetter, '[foo]'); + +class B { + func1() {} + get func2() {} + set func3(a) {} + + static func4() {} + static get func5() {} + static set func6(a) {} + + ['func' + '7']() {} + get ['func' + '8']() {} + set ['func' + '9'](a) {} + + static ['func' + '10']() {} + static get ['func' + '11']() {} + static set ['func' + '12'](a) {} + + [emptySymbolMethod]() {} + [namedSymbolMethod]() {} + get [emptySymbolGetter]() {} + get [namedSymbolGetter]() {} + set [emptySymbolSetter](a) {} + set [namedSymbolSetter](a) {} + + static [emptySymbolMethod]() {} + static [namedSymbolMethod]() {} + static get [emptySymbolGetter]() {} + static get [namedSymbolGetter]() {} + static set [emptySymbolSetter](a) {} + static set [namedSymbolSetter](a) {} +} + +assertMethodName(B.prototype.func1, 'func1'); +assertGetterName(B.prototype, 'func2'); +assertSetterName(B.prototype, 'func3'); + +assertMethodName(B.func4, 'func4'); +assertGetterName(B, 'func5'); +assertSetterName(B, 'func6'); + +assertMethodName(B.prototype.func7, 'func7'); +assertGetterName(B.prototype, 'func8'); +assertSetterName(B.prototype, 'func9'); + +assertMethodName(B.func10, 'func10'); +assertGetterName(B, 'func11'); +assertSetterName(B, 'func12'); + +assertMethodName(B[emptySymbolMethod], ''); +assertMethodName(B[namedSymbolMethod], '[foo]'); +assertGetterName(B, emptySymbolGetter, ''); +assertGetterName(B, namedSymbolGetter, '[foo]'); +assertSetterName(B, emptySymbolSetter, ''); +assertSetterName(B, namedSymbolSetter, '[foo]'); + +assertMethodName(B.prototype[emptySymbolMethod], ''); +assertMethodName(B.prototype[namedSymbolMethod], '[foo]'); +assertGetterName(B.prototype, emptySymbolGetter, ''); +assertGetterName(B.prototype, namedSymbolGetter, '[foo]'); +assertSetterName(B.prototype, emptySymbolSetter, ''); +assertSetterName(B.prototype, namedSymbolSetter, '[foo]'); + +let names = ['push', 'pop', 'reduce', 'reduceRight']; + +for (let n of names) { + assert(Array.prototype[n].name === n); +} + +assert(Array.prototype[Symbol.iterator].name === 'values'); +assert(Array.prototype.values.name === 'values'); +assert(Object.getOwnPropertyDescriptor(Array, Symbol.species).get.name === 'get [Symbol.species]'); +assert(Object.getOwnPropertyDescriptor(String.prototype, Symbol.iterator).value.name === '[Symbol.iterator]'); +assert(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get.name === 'get __proto__'); +assert(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set.name === 'set __proto__'); + +let arFunc; +let array = []; +array['original'] = array; +array['original'][arFunc = ()=>{ }]=function(){} +assertNameNotExists(array[arFunc]); + +var o = { 0 : class {} }; + +assertMethodName(o['0'], '0'); diff --git a/tests/jerry/es2015/function-new-target.js b/tests/jerry/es2015/function-new-target.js new file mode 100644 index 00000000..ddda1b65 --- /dev/null +++ b/tests/jerry/es2015/function-new-target.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var get = []; +var p = new Proxy(Function, { get: function(o, k) { get.push(k); return o[k]; }}); +new p; + +assert(get + '' === "prototype"); + +var func = function() {} +var reflect = Reflect.construct(Function, ['a','b','return a+b'], func); +assert(Object.getPrototypeOf(reflect) == func.prototype); + +var o = new Proxy (function f () {}, { get(t,p,r) { if (p == "prototype") { throw 42 }}}) + +try { + Reflect.construct(Function, [], o); + assert(false); +} catch (e) { + assert(e === 42); +} diff --git a/tests/jerry/es2015/function-param-init2.js b/tests/jerry/es2015/function-param-init2.js new file mode 100644 index 00000000..a5dea86c --- /dev/null +++ b/tests/jerry/es2015/function-param-init2.js @@ -0,0 +1,100 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f(a, b = a) +{ + function a() { return 2; } + + assert(a() === 2); + assert(b === 1) +} +f(1); + +function g(a, b = a) +{ + function a() { return 2; } + + eval("assert(a() === 2)"); + eval("assert(b === 1)"); +} +g(1); + +var x = 1; +function h(a = x) { + assert(x === undefined); + var x = 2; + assert(a === 1); + assert(x === 2); +} +h(); + +x = function() { return 4; } +let y = 6; + +function i(a = x() / 2, b = (y) + 2, c = typeof z) { + let y = 10; + let z = 11; + + function x() { return 5; } + + assert(a === 2); + assert(x() === 5); + assert(b === 8); + assert(c === "undefined"); + assert(y === 10); + assert(z === 11); +} +i(); + +var arguments = 10; +function j(a = arguments[1]) +{ + assert(a === 2); + a = 3; + assert(arguments[0] === undefined) +} +j(undefined,2); + +function k(a = 2) +{ + let d = 5; + assert(d === 5); + eval("assert(a === 2)"); +} +k(); + +function l(a = 3) +{ + const d = 6; + assert(d === 6); + eval("assert(a === 3)"); +} +l(); + +function m(a, b = 2) +{ + assert(a === 1); + assert(arguments[0] === 1); + assert(b === 2); + assert(arguments[1] === undefined); + + a = 8; + b = 9; + + assert(a === 8); + assert(arguments[0] === 1); + assert(b === 9); + assert(arguments[1] === undefined); +} +m(1); diff --git a/tests/jerry/es2015/function-param-init3.js b/tests/jerry/es2015/function-param-init3.js new file mode 100644 index 00000000..e2e177a4 --- /dev/null +++ b/tests/jerry/es2015/function-param-init3.js @@ -0,0 +1,68 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var d = 1 +function f(a = function () { return d }) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +f() + +var g = (a = () => d) => { + var d = 2 + assert(d === 2) + assert(a() === 1) +} +g() + +var h = ([{a}] = [{a: function () { return d }}]) => { + var d = 2 + assert(d === 2) + assert(a() === 1) +} +h() + +function i(a = ((eval))("(function () { return d })")) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +i() + +function j(a = (([1, ((() => d))])[1])) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +j() + +var m = 0 +function l(a) +{ + m = a + return m +} + +function k(a = l(() => d)) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) + assert(m() === 1) +} +k() diff --git a/tests/jerry/es2015/function-param-init4.js b/tests/jerry/es2015/function-param-init4.js new file mode 100644 index 00000000..040f1550 --- /dev/null +++ b/tests/jerry/es2015/function-param-init4.js @@ -0,0 +1,164 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_reference_error(code) +{ + try { + eval(code); + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } +} + +function f1(a = a) +{ + assert(a === 1) +} +f1(1) +check_reference_error("f1()"); + +function f2([a] = 1 + a) +{ + assert(a === 2) +} +f2([2]) +check_reference_error("f2()"); + +function f3([a = !a]) +{ + assert(a === 2) +} +f3([2]) +check_reference_error("f3([])"); + +function f4([[a]] = a) +{ + assert(a === 3) +} +f4([[3]]) +check_reference_error("f4()"); + +function f5([[a], b = a] = a) +{ + assert(a === 4 && b === 4) +} +f5([[4]]) +check_reference_error("f5()") + +function f6(a = 3 - ((b)), b) +{ + assert(a === 1 && b === 2) +} +f6(1, 2) +check_reference_error("f6(undefined, 2)"); + +function f7(a = b(), [b]) +{ + assert(a === 3 && b === 4) +} +f7(3, [4]) +check_reference_error("f7(undefined, [4])"); + +function f8(a = (function () { return a * 2 })()) +{ + assert(a === 1) +} +f8(1) +check_reference_error("f8()"); + +function f9({a = b, b:{b}}) +{ + assert(a === 2 && b === 3) +} +f9({a:2, b:{b:3}}) +check_reference_error("f9({b:{b:3}})"); + +function f10(a = eval("a")) +{ + assert(a === 1) +} +f10(1) +check_reference_error("f10()"); + +function f11([a] = eval("a")) +{ + assert(a === 2) +} +f11([2]) +check_reference_error("f11()"); + +function f12({a} = eval("a")) +{ + assert(a === 3) +} +f12({a:3}) +check_reference_error("f12()"); + +function f13(a = arguments) +{ + assert(a[0] === undefined) + assert(a[1] === 4) + arguments[0] = 5 + assert(a[0] === 5) +} +f13(undefined, 4) + +function f14(a, b = function() { return a; }(), c = (() => a)()) +{ + assert(a === 6 && b === 6 && c === 6) +} +f14(6) + +function f15(a = (() => b)(), b) +{ + assert(a === 1 && b === 2) +} +f15(1, 2) +check_reference_error("f15(undefined, 2)"); + +var f16 = (a = a) => +{ + assert(a === 1) +} +f16(1) +check_reference_error("f16()"); + +var f17 = ([[a]] = a) => +{ + assert(a === 2) +} +f17([[2]]) +check_reference_error("f17()"); + +var f18 = ({a = b, b:{b}}) => +{ + assert(a === 3 && b === 4) +} +f18({a:3, b:{b:4}}) +check_reference_error("f18({b:{b:4}})"); + +var f19 = (a = eval("a")) => +{ + assert(a === 5) +} +f19(5) +check_reference_error("f19()"); + +var f20 = ([a] = eval("a")) => +{ + assert(a === 6) +} +f20([6]) +check_reference_error("f20()"); diff --git a/tests/jerry/es2015/function-pattern1.js b/tests/jerry/es2015/function-pattern1.js new file mode 100644 index 00000000..e2d70f40 --- /dev/null +++ b/tests/jerry/es2015/function-pattern1.js @@ -0,0 +1,94 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function must_throw (str, type = SyntaxError) +{ + try + { + eval (str); + assert (false); + } + catch (e) + { + assert (e instanceof type) + } +} + +must_throw ("function f(a, [a]) {}"); +must_throw ("function f([a], a) {}"); +must_throw ("function f(a = b, [b]) {}; f()", ReferenceError); +must_throw ("function f([a+b]) {}"); +must_throw ("function f([a().b]) {}"); +must_throw ("function f(...[a] = [1]) {}"); + +function a1([a,b]) { + var a, b; + + assert(a === 1); + assert(b === undefined); + + var a = 3; + assert(a === 3); +} +a1([1]); + +function a2([a,b]) { + eval("var a, b"); + assert(a === 1); + assert(b === undefined); + + eval("var a = 3"); + assert(a === 3); +} +a2([1]); + +function f1(a, [b], c, [d], e) +{ + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +f1(1, [2], 3, [4], 5) + +function f2(a, [b], c, [d], e) +{ + eval(""); + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +f2(1, [2], 3, [4], 5) + +var g1 = (a, [b], c, [d], e) => { + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +g1(1, [2], 3, [4], 5) + +var g2 = (a, [b], c, [d], e) => { + eval(""); + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +g2(1, [2], 3, [4], 5) diff --git a/tests/jerry/es2015/function-pattern2.js b/tests/jerry/es2015/function-pattern2.js new file mode 100644 index 00000000..7a9520df --- /dev/null +++ b/tests/jerry/es2015/function-pattern2.js @@ -0,0 +1,93 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert((function([a], b, {c}) {}).length === 3); + +function f([a = "x", b = "y", c = "z"]) +{ + assert(a === "a"); + assert(b === "b"); + assert(c === "z"); +} +f("ab") + +function g({ ["x" + "y"]: { a = 4, b = 5 }, }) +{ + assert(a === 1); + assert(b === 5); +} +g({ xy: { a:1 } }); + +function h([,,a,,b,,]) +{ + assert(a === 3); + assert(b === 5); +} +h([1,2,3,4,5,6,7,8]) + +function i([a] = [42], b = a) +{ + assert(a === 42); + assert(b === 42); +} +i(); + +function j(a, [[b = a, [c] = [b], { d } = { d:eval("c") }], e = d + 1] = [[]]) +{ + assert(a === 8); + assert(b === 8); + assert(c === 8); + assert(d === 8); + assert(e === 9); +} +j(8); + +function k([a = function() { return a; }]) +{ + assert(typeof a === "function"); + assert(a() === a); +} +k([]); + +function l(a = 0, ...[b, c = 1, d = 4]) +{ + assert(a === 1); + assert(b === 2); + assert(c === 3); + assert(d === 4); +} +l(1,2,3); + +Function("{a, x:b}","[c]", "{ 'dd':d, e = Math.cos(0)}", + "assert(a === 1);" + + "assert(b === undefined);" + + "assert(c === 3);" + + "assert(d === 4);" + + "assert(e === 1);" +)({a:1, b:3}, [3], {a:1, b:2, dd:4}); + +function m() +{ + var prop_name = "x"; + var def_val = 123; + + function g({[prop_name]: a, b = def_val }) + { + assert(a === 12); + assert(b === 123); + } + + g({ x:12 }) +} +m(); diff --git a/tests/jerry/es2015/function-properties.js b/tests/jerry/es2015/function-properties.js index 1ad28ec7..a80b93c7 100644 --- a/tests/jerry/es2015/function-properties.js +++ b/tests/jerry/es2015/function-properties.js @@ -35,7 +35,7 @@ var prototype_obj = { dummy:1, length:1, caller:null, var func = function() {}; Object.setPrototypeOf(func, prototype_obj); -assert(getProperties(func) == "dummy caller arguments"); +assert(getProperties(func) == "dummy"); var bound_func = (function() {}).bind(null); Object.setPrototypeOf(bound_func, prototype_obj); diff --git a/tests/jerry/es2015/function-prototype-bind.js b/tests/jerry/es2015/function-prototype-bind.js new file mode 100644 index 00000000..8d0f1e18 --- /dev/null +++ b/tests/jerry/es2015/function-prototype-bind.js @@ -0,0 +1,69 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* extended class */ +(function() { + class C extends Function {} + var c = new C("x", "y", "return this.foo + x + y;").bind({foo : 1}, 2); + assert(c(3) === 6); + assert(c instanceof C); +})(); + +function boundPrototypeChecker(f, proto) { + Object.setPrototypeOf(f, proto); + + var boundFunc = Function.prototype.bind.call(f, null); + assert(Object.getPrototypeOf(boundFunc) === proto); +} + +/* generator function */ +(function() { + var f = function*(){}; + boundPrototypeChecker(f, Function.prototype) + boundPrototypeChecker(f, {}) + boundPrototypeChecker(f, null); +})(); + +/* arrow function */ +(function() { + var f = () => 5; + boundPrototypeChecker(f, Function.prototype) + boundPrototypeChecker(f, {}) + boundPrototypeChecker(f, null); +})(); + +/* simple class */ +(function() { + class C {}; + boundPrototypeChecker(C, Function.prototype) + boundPrototypeChecker(C, {}) + boundPrototypeChecker(C, null); +})(); + +/* subclasses */ +(function() { + function boundPrototypeChecker(superclass) { + class C extends superclass { + constructor() { + return Object.create(null); + } + } + var boundF = Function.prototype.bind.call(C, null); + assert(Object.getPrototypeOf(boundF) === Object.getPrototypeOf(C)); + } + + boundPrototypeChecker(function(){}); + boundPrototypeChecker(Array); + boundPrototypeChecker(null); +})(); diff --git a/tests/jerry/es2015/function-prototype-hasinstance-class.js b/tests/jerry/es2015/function-prototype-hasinstance-class.js new file mode 100644 index 00000000..d497744f --- /dev/null +++ b/tests/jerry/es2015/function-prototype-hasinstance-class.js @@ -0,0 +1,53 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class base { + constructor (value) { + this.member = value; + } + + method () { + return this.member; + } +} + +class sub { + constructor (value) { + this.member = value; + } +} + +var obj_base = new base (3); +var obj_sub = new sub (4); + +assert (base[Symbol.hasInstance](obj_base) === true); +assert (base[Symbol.hasInstance](obj_sub) === false); + +assert (sub[Symbol.hasInstance](obj_base) === false); +assert (sub[Symbol.hasInstance](obj_sub) === true); + + +class sub_c extends base { + constructor (value) { + super(value); + this.member = value; + } +} + +var obj_sub_c = new sub_c (5); + +assert (base[Symbol.hasInstance](obj_sub_c) === true); + +assert (sub_c[Symbol.hasInstance](obj_base) === false); +assert (sub_c[Symbol.hasInstance](obj_sub_c) === true); diff --git a/tests/jerry/es2015/function-prototype-hasinstance.js b/tests/jerry/es2015/function-prototype-hasinstance.js new file mode 100644 index 00000000..d29d9cf3 --- /dev/null +++ b/tests/jerry/es2015/function-prototype-hasinstance.js @@ -0,0 +1,81 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function base (value) { + this.member = value; +} + +base.prototype.method = function () { return this.member; } + +function sub (value) { + this.member = value; +} + +sub.prototype = base; + + +var obj_base = new base (3); +var obj_sub = new sub (4); + +assert (base[Symbol.hasInstance] (obj_base) === true); +assert (base[Symbol.hasInstance] (obj_sub) === false); +assert (Object[Symbol.hasInstance] (obj_base) === true); +assert (Object[Symbol.hasInstance] (obj_sub) === true); +assert (obj_base.method () === 3); + +assert (sub[Symbol.hasInstance] (obj_base) === false); +assert (sub[Symbol.hasInstance] (obj_sub) === true); +assert (obj_sub.method === undefined); + +function sub_c (value) { + this.member = value; +} + +sub_c.prototype = Object.create (base.prototype) +sub_c.prototype.constructor = sub_c + +var obj_sub_c = new sub_c (5); + +assert (base[Symbol.hasInstance] (obj_sub_c) === true); + +assert (sub_c[Symbol.hasInstance] (obj_base) === false); +assert (sub_c[Symbol.hasInstance] (obj_sub_c) === true); +assert (Object[Symbol.hasInstance] (obj_sub_c) === true); +assert (Function.prototype[Symbol.hasInstance].call (sub_c, obj_sub_c) === true); + +assert (obj_sub_c.method () === 5); + +assert (base[Symbol.hasInstance] (3) === false); +assert (Number[Symbol.hasInstance] (33) === false); +assert (Number[Symbol.hasInstance] (new Number (33)) === true); +assert (Object[Symbol.hasInstance] (44) === false); +assert (Object[Symbol.hasInstance] (new Number (22)) === true); + +assert (base[Symbol.hasInstance] ('demo') === false); +assert (String[Symbol.hasInstance] ('demo') === false); +assert (String[Symbol.hasInstance] (new String ('demo')) === true); +assert (Object[Symbol.hasInstance] ('demo') === false); +assert (Object[Symbol.hasInstance] (new String ('demo')) === true); + +assert (base[Symbol.hasInstance] ([]) === false); +assert (base[Symbol.hasInstance] ([1, 2]) === false); +assert (Array[Symbol.hasInstance] ([1, 2]) === true); +assert (Array[Symbol.hasInstance] (new Array(1, 2)) === true); +assert (Object[Symbol.hasInstance] ([]) === true); +assert (Object[Symbol.hasInstance] (new Array()) === true); + +assert (base[Symbol.hasInstance] (new RegExp('abc')) === false); +assert (RegExp[Symbol.hasInstance] (/abc/) === true); +assert (RegExp[Symbol.hasInstance] (new RegExp('abc')) === true); +assert (Object[Symbol.hasInstance] (/abc/) === true); diff --git a/tests/jerry/es2015/function-rest-parameter.js b/tests/jerry/es2015/function-rest-parameter.js index 35f60c16..0075a4b3 100644 --- a/tests/jerry/es2015/function-rest-parameter.js +++ b/tests/jerry/es2015/function-rest-parameter.js @@ -35,6 +35,7 @@ CheckSyntaxError ('function x (... c = 5) {}'); CheckSyntaxError ('function x (...) {}'); CheckSyntaxError ('function x (a, a, ...a) {}'); CheckSyntaxError ('"use strict" function x (...arguments) {}'); +CheckSyntaxError ('var o = { set e (...args) { } }'); rest_params = ['hello', true, 7, {}, [], function () {}]; @@ -78,3 +79,18 @@ assert (g2 () === 11); assert (g2 (1) === 3); assert (g2 (1, 2) === 3); assert (g2 (1, 2, 3) === 4); + +function args(a, ...b) +{ + assert(a === 1); + assert(arguments[0] === 1); + + a = 5; + + assert(a === 5); + assert(arguments[0] === 1); + + assert(arguments[1] === 2); + assert(b[0] === 2) +} +args(1, 2); diff --git a/tests/jerry/es2015/function-scope.js b/tests/jerry/es2015/function-scope.js new file mode 100644 index 00000000..ad37ebd3 --- /dev/null +++ b/tests/jerry/es2015/function-scope.js @@ -0,0 +1,67 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f1(a) +{ + assert(a === 2) + { + assert(a() === 1) + function a() { return 1 } + } + assert(a === 2) +} +f1(2) + +function f2([a]) +{ + assert(a === 4) + { + assert(a() === 3) + function a() { return 3 } + } + assert(a === 4) +} +f2([4]) + +function f3(a) +{ + assert(a() === 5) + { + assert(a() === 6) + function a() { return 6 } + } + assert(a() === 5) + + function a() { return 5 } +} +f3(7) + +function f4(a) +{ + assert(a === 8) + { + eval("function a() { return 9 }") + assert(a() === 9) + } + assert(a() === 9) +} +f4(8) + +function f5(a, b = function() { return a }) { + function a() { return 9 } + + assert(a() === 9) + assert(b() === 10) +} +f5(10) diff --git a/tests/jerry/es2015/function-scope2.js b/tests/jerry/es2015/function-scope2.js new file mode 100644 index 00000000..6b447686 --- /dev/null +++ b/tests/jerry/es2015/function-scope2.js @@ -0,0 +1,111 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = 1; +var b = 2; + +function f(x = eval("eval('var a = 3; function b() { return 4 } () => a')"), y = b) { + eval("eval('var a = 5; function b() { return 6 }')"); + + assert(a === 5); + assert(b() === 6); + + assert(x() === 3); + assert(y() === 4); + + delete a; + delete b; + + assert(a === 3); + assert(b() === 4); + + assert(x() === 3); + assert(y() === 4); + + delete a; + delete b; + + assert(a === 1); + assert(b === 2); + + assert(x() === 1); + assert(y() === 4); +} +f() + +function g() { + 'use strict' + + function h(x, y = function() { return x }) { + var x = 2; + + /* This should not overwrite y. */ + eval("var y = 3; assert (y === 3)"); + + assert(x === 2); + assert(typeof y === "function"); + assert(y() === 1); + } + h(1); +} +g(); + +function h(a, get = () => a, set = (v) => a = v) { + assert(a === 1); + + var a = 2; + + assert(a === 2); + assert(get() === 1); + + set(3) + a = 4; + + assert(a === 4); + assert(get() === 3); +} +h(1); + +function i([a], get = () => a, set = (v) => a = v) { + assert(a === 1); + + var a; + assert(a === 1); + + a = 2; + + assert(a === 2); + assert(get() === 1); + + set(3) + a = 4; + + assert(a === 4); + assert(get() === 3); +} +i([1]); + +function j(a = eval()) { + var a = 3.14; + + try { + eval("throw 1; function a() { return 8; }") + assert(false) + } catch (e) { + assert(e === 1) + } + + assert(a() === 8) +} +j() diff --git a/tests/jerry/es2015/generator-function.js b/tests/jerry/es2015/generator-function.js new file mode 100644 index 00000000..16cff4ca --- /dev/null +++ b/tests/jerry/es2015/generator-function.js @@ -0,0 +1,97 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Test %GeneratorPrototype% +(function () { + function* generatorFn(){} + var ownProto = Object.getPrototypeOf(generatorFn()); + var sharedProto = Object.getPrototypeOf(ownProto); + + assert(ownProto === generatorFn.prototype); + assert(sharedProto !== Object.prototype); + assert(sharedProto === Object.getPrototypeOf(function*(){}.prototype)); + assert(sharedProto.hasOwnProperty('next')); +})(); + +// Test %GeneratorPrototype% prototype chain +(function () { + function* generatorFn(){} + var g = generatorFn(); + var ownProto = Object.getPrototypeOf(g); + var sharedProto = Object.getPrototypeOf(ownProto); + var iterProto = Object.getPrototypeOf(sharedProto); + + assert(ownProto === generatorFn.prototype); + assert(iterProto.hasOwnProperty(Symbol.iterator)); + assert(!sharedProto.hasOwnProperty(Symbol.iterator)); + assert(!ownProto.hasOwnProperty(Symbol.iterator)); + assert(g[Symbol.iterator]() === g); +})(); + +// Test %GeneratorPrototype% prototype chain +(function () { + function* g(){} + var iterator = new g.constructor("a","b","c","() => yield\n yield a; yield b; yield c;")(1,2,3); + + var item = iterator.next(); + assert(item.value === 1); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === 2); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === 3); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === undefined); + assert(item.done === true); + + assert(g.constructor === (function*(){}).constructor); +})(); + +// Test GeneratorFunction parsing +(function () { + function *f() {}; + + try { + Object.getPrototypeOf(f).constructor("yield", ""); + } catch (e) { + assert(e instanceof SyntaxError); + } +})(); + +// Test correct property membership +(function () { + function *f() {}; + + Object.getPrototypeOf(f).xx = 5; + assert(Object.getPrototypeOf(f).prototype.constructor.xx === 5); +})(); + +// Test GetPrototypeFromConstructor +(function () { + function *f() {}; + + var originalProto = f.prototype; + f.prototype = 5; + assert(Object.getPrototypeOf(f()) === Object.getPrototypeOf(originalProto)); + var fakeProto = { x : 6 }; + f.prototype = fakeProto; + assert(Object.getPrototypeOf(f()) === fakeProto); + assert(f.next === undefined); +})(); diff --git a/tests/jerry/es2015/generator-initializer.js b/tests/jerry/es2015/generator-initializer.js new file mode 100644 index 00000000..4493670d --- /dev/null +++ b/tests/jerry/es2015/generator-initializer.js @@ -0,0 +1,138 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file checks core generator operations. */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error ("({ * })") +check_syntax_error ("({ *, b:4 })") +check_syntax_error ("({ *a:4 })") +check_syntax_error ("({ *['a']:4 })") +check_syntax_error ("({ *a(yield) {} })") +check_syntax_error ("({ get *a() {} })") +check_syntax_error ("({ set *b(v) {} })") + +check_syntax_error ("class C { * }") +check_syntax_error ("class C { static * }") +check_syntax_error ("class C { *() {} }") +check_syntax_error ("class C { static * () {} }") +check_syntax_error ("class C { *['a'] {} }") + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function postfix(a) { return a + "b" } + +var o = { + * a () { + yield 1 + return 2 + }, + *2(x) { + yield x + 1 + return x + 2 + }, + *[postfix("a")]() { + var o = { get yield() { return 3 + 2 } } + + yield o.yield + return 6 + }, + *yield() { + var o = { yield:7 } + + yield o.yield + return 8 + } +} + +var f = o.a() +check_result(f.next(), 1, false) +check_result(f.next(), 2, true) + +var f = o[2](2) +check_result(f.next(), 3, false) +check_result(f.next(), 4, true) + +var f = o.ab() +check_result(f.next(), 5, false) +check_result(f.next(), 6, true) + +var f = o.yield() +check_result(f.next(), 7, false) +check_result(f.next(), 8, true) + +class C { + * a () { + yield 1 + return 2 + } + + *3(x) { + yield x + 1 + return x + 2 + } + + *[postfix("a")]() { + var o = { get yield() { return 3 + 2 } } + + yield o.yield + return 6 + } + + static *yield() { + var o = { yield:7 } + + yield o.yield + return 8 + } + + static * [postfix("b") ] (v = 9) { + return v + } +} + +var c = new C + +var f = c.a() +check_result(f.next(), 1, false) +check_result(f.next(), 2, true) + +var f = c[3](2) +check_result(f.next(), 3, false) +check_result(f.next(), 4, true) + +var f = c.ab() +check_result(f.next(), 5, false) +check_result(f.next(), 6, true) + +var f = C.yield() +check_result(f.next(), 7, false) +check_result(f.next(), 8, true) + +var f = C.bb() +check_result(f.next(), 9, true) diff --git a/tests/jerry/es2015/generator-return.js b/tests/jerry/es2015/generator-return.js new file mode 100644 index 00000000..b14540e9 --- /dev/null +++ b/tests/jerry/es2015/generator-return.js @@ -0,0 +1,74 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function * gen1(a) { + return "a: " + (yield a.p) +} + +var f = gen1({}) +check_result(f.return(4), 4, true) +check_result(f.next(), undefined, true) + +f = gen1({ p:"x" }) +check_result(f.next(), "x", false) +check_result(f.return(10), 10, true) +check_result(f.next(), undefined, true) + +f = gen1({ p:"b" }) +check_result(f.next(), "b", false) +check_result(f.next(), "a: undefined", true) +check_result(f.next(), undefined, true) + +function*gen2() { + try { + for (let i in { x:1, y:2 }) + { + assert((yield i) === "33") + } + assert(false) + } catch (e) { + assert(false) + } finally { + yield "z" + } +} + +f = gen2() +check_result(f.return("ret"), "ret", true) +check_result(f.next(), undefined, true) + +f = gen2() +check_result(f.next(), "x", false) +check_result(f.return("ret"), "z", false) +check_result(f.next(), "ret", true) +check_result(f.next(), undefined, true) + +function* gen3() { + try { + return 8 + } finally { + yield 1 + } +} + +f = gen3() +check_result(f.next(), 1, false) +check_result(f.return(2), 2, true) diff --git a/tests/jerry/es2015/generator-throw.js b/tests/jerry/es2015/generator-throw.js new file mode 100644 index 00000000..da99bdcb --- /dev/null +++ b/tests/jerry/es2015/generator-throw.js @@ -0,0 +1,82 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function check_throw(str, expected) +{ + try { + eval(str) + assert(false); + } catch (e) { + assert(e === expected); + } +} + +function * gen1(a) { + return "a: " + (yield a.p) +} + +var f = gen1({}) +check_throw("f.throw(4)", 4) +check_result(f.next(), undefined, true) + +f = gen1({ p:"x" }) +check_result(f.next(), "x", false) +check_throw("f.throw(10)", 10) +check_result(f.next(), undefined, true) + +f = gen1({ p:"b" }) +check_result(f.next(), "b", false) +check_result(f.next(), "a: undefined", true) +check_result(f.next(), undefined, true) + +function*gen2() { + try { + for (let i in { x:1, y:2 }) + { + assert((yield i) === "33") + } + assert(false) + } finally { + yield "z" + } +} + +f = gen2() +check_throw("f.throw('throw')", "throw") +check_result(f.next(), undefined, true) + +f = gen2() +check_result(f.next(), "x", false) +check_result(f.throw("throw"), "z", false) +check_throw("f.next()", "throw") +check_result(f.next(), undefined, true) + +function* gen3() { + try { + return 8 + } finally { + yield 1 + } +} + +f = gen3() +check_result(f.next(), 1, false) +check_throw("f.throw(2)", 2) diff --git a/tests/jerry/es2015/generator-yield-iterator.js b/tests/jerry/es2015/generator-yield-iterator.js new file mode 100644 index 00000000..3b36d98d --- /dev/null +++ b/tests/jerry/es2015/generator-yield-iterator.js @@ -0,0 +1,121 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function *gen1() { + yield 1 + yield *[2,3,4] + yield 5 +} + +var g = gen1() +check_result(g.next(), 1, false) +check_result(g.next(), 2, false) +check_result(g.next(), 3, false) +check_result(g.next(), 4, false) +check_result(g.next(), 5, false) +check_result(g.next(), undefined, true) + +function *gen2() { + yield * true +} + +try { + g = gen2() + g.next() + assert(false) +} catch (e) { + assert(e instanceof TypeError) +} + +var t0 = 0, t1 = 0 + +function *gen3() { + function *f() { + try { + yield 5 + } finally { + t0 = 1 + } + } + + try { + yield *f() + } finally { + t1 = 1 + } +} + +g = gen3() +check_result(g.next(), 5, false) +check_result(g.return(13), 13, true) +assert(t0 === 1) +assert(t1 === 1) + +t0 = -1 +t1 = 0 + +function *gen4() { + function next(arg) + { + t0++; + + if (t0 === 0) + { + assert(arg === undefined); + return { value:2, done:false } + } + if (t0 === 1) + { + assert(arg === -3); + return { value:3, done:false } + } + assert(arg === -4); + return { value:4, done:true } + } + + var o = { [Symbol.iterator]() { return { next } } } + assert((yield *o) === 4) + return 5; +} + +g = gen4() +check_result(g.next(-2), 2, false) +check_result(g.next(-3), 3, false) +check_result(g.next(-4), 5, true) + +function *gen5() { + function *f() { + try { + yield 1 + assert(false) + } catch (e) { + assert(e === 10) + } + return 2 + } + + assert((yield *f()) === 2) + yield 3 +} + +g = gen5() +check_result(g.next(), 1, false) +check_result(g.throw(10), 3, false) diff --git a/tests/jerry/es2015/generator-yield.js b/tests/jerry/es2015/generator-yield.js new file mode 100644 index 00000000..7fd70c48 --- /dev/null +++ b/tests/jerry/es2015/generator-yield.js @@ -0,0 +1,86 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file checks yield syntax errors. */ + +function check_syntax_error(str) +{ + try { + eval(str); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +function * gen() +{ + yield , yield + + yield + , yield + + (yield + ) + + yield[ + 1] +} + +function*gen2() +{ + 1 ? + yield + : + yield +} + +var gen3 = function*(){ + (yield)/[yield] +} + +check_syntax_error("function *gen(){ yield % yield }"); +check_syntax_error("function *gen(){ (yield) % yield }"); +check_syntax_error("function *gen(){ yield % (yield) }"); +check_syntax_error("function *gen(){ (yield\n1) }"); +check_syntax_error("function *gen(){ function yield() {} }"); +check_syntax_error("function *gen(){ (yield)=>1 }"); +check_syntax_error("function *gen(){ yield => 1 }"); +check_syntax_error("function *gen(){ yi\\u0065ld 1 }"); + +function *gen4() { + var f = function yield(i) { + if (i = 0) + return yield(i + 1) + + return 39 + } + + return f(0) +} + +assert(gen4().next().value === 39); + +(function *() { + () => yield + yield 1; +}) + +function *gen5() { + var o = { + ["f"]() { yield % yield } + } + yield 1; +} diff --git a/tests/jerry/es2015/generator.js b/tests/jerry/es2015/generator.js new file mode 100644 index 00000000..c34fc5a7 --- /dev/null +++ b/tests/jerry/es2015/generator.js @@ -0,0 +1,199 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file checks core generator operations. */ + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function * gen1(a = (t = 8)) { + var o = { p: 2 } + var x = 3.25 + + assert((o.p + (yield 10)) === 23) + assert((o.p + (yield 11)) === 24) + return x +} + +/* Cannot be invoked with new. */ +try { + new gen1 + assert(false) +} catch (e) { + assert(e instanceof TypeError) +} + +/* Fully read values. */ +var t = 0 +var g = gen1() +assert(t === 8) + +check_result(g.next(20), 10, false) +check_result(g.next(21), 11, false) +check_result(g.next(22), 3.25, true) +check_result(g.next(23), undefined, true) + +/* Partly read values (gc needs to free a suspended generator). */ +t = 0 +g = gen1() +assert(t === 8) + +check_result(g.next(20), 10, false) + +function * gen2() { + for (i in { x:0, y:1, z:2 }) + { + let a = eval("'s'") + + var b = yield a + i + assert (b === ++t) + } +} + +/* Fully read values. */ +t = 0 +f = gen2() + +check_result(f.next(0), "sx", false) +check_result(f.next(1), "sy", false) +check_result(f.next(2), "sz", false) +check_result(f.next(3), undefined, true) +check_result(f.next(4), undefined, true) + +/* Partly read values (gc needs to free a suspended generator). */ +f = gen2() + +t = 0 +check_result(f.next(0), "sx", false) + +function *gen3() { + function f(yield) { + return -yield * 2 + } + + var g = (v) => { + assert(v === 6) + } + + g(yield yield f(++t)) + + return 77 +} + +/* Fully read values. */ +t = 0 +f = gen3() + +check_result(f.next(0), -2, false) +check_result(f.next(88), 88, false) +check_result(f.next(6), 77, true) + +/* Partly read values (gc needs to free a suspended generator). */ +t = 0 +f = gen3() + +check_result(f.next(0), -2, false) + +function + /* generator: */ * + /* name: */ gen4() { + + let a = eval("5") + with ({a}) + { + let a = eval("6") + + for (let a = 10; a < 11; a++) + { + let a = eval("7") + yield (a) + } + + yield a, !assert(a === 6) + } + assert((yield a) === undefined) +} + +/* Fully read values. */ +f = gen4() + +check_result(f.next(), 7, false) +check_result(f.next(), 6, false) +check_result(f.next(), 5, false) +check_result(f.next(), undefined, true) + +/* Partly read values (gc needs to free a suspended generator). */ +f = gen4() + +check_result(f.next(), 7, false) + +function*gen5(a,b,c,d) { + yield a + yield b + yield c + yield d +} + +/* Fully read values. */ +t = [] +for(let i of gen5(1,3,5,7)) { + t.push(i) +} + +assert(t.length === 4) +assert(t[0] === 1) +assert(t[1] === 3) +assert(t[2] === 5) +assert(t[3] === 7) + +/* Partly read values (gc needs to free a suspended generator). */ +t = [] +for(let i of gen5(1,3,5,7)) { + t.push(i) + if (i === 3) { + break + } +} + +assert(t.length === 2) +assert(t[0] === 1) +assert(t[1] === 3) + +/* Recursive generator call. */ +function* gen6(a,b,c,d) { + yield f.next() +} + +f = gen6() + +try { + f.next() + assert(false) +} catch (e) { + assert(e instanceof TypeError) +} + +/* Parameterless yield. */ +function* gen7() { + yield +} + +f = gen7() +check_result(f.next(), undefined, false) +check_result(f.next(), undefined, true) + diff --git a/tests/jerry/es2015/identifier-escape.js b/tests/jerry/es2015/identifier-escape.js new file mode 100644 index 00000000..99d63dd4 --- /dev/null +++ b/tests/jerry/es2015/identifier-escape.js @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_syntax_error (code) { + try { + eval(code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +eval("\u{000010C80}: break \ud803\udc80") +eval("\\u{10C80}: break \ud803\udc80") +eval("$\u{000010C80}$: break $\ud803\udc80$") +eval("$\\u{10C82}$: break $\ud803\udc82$") + +assert("\u{000010C80}".length === 2) +assert("x\u{010C80}y".length === 4) +assert("\u{10C80}" === "\ud803\u{dc80}") +assert("\u{0}\x01" === "\u0000\u0001") + +/* Surrogate pairs are not combined if they passed as \u sequences. */ +check_syntax_error("\\u{10C80}: break \\ud803\\udc80"); diff --git a/tests/jerry/es2015/instanceof-symbol-hasinstance-class.js b/tests/jerry/es2015/instanceof-symbol-hasinstance-class.js new file mode 100644 index 00000000..de39b57e --- /dev/null +++ b/tests/jerry/es2015/instanceof-symbol-hasinstance-class.js @@ -0,0 +1,50 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class NoParent { + static [Symbol.hasInstance] (arg) { + return false; + } +} + +var obj = new NoParent (); + +assert ((obj instanceof NoParent) === false); + +class PositiveNumber { + static [Symbol.hasInstance] (arg) { + return (arg instanceof Number) && (arg >= 0); + } +} + +var num_a = new Number (33); +var num_b = new Number (-50); + +assert ((num_a instanceof PositiveNumber) === true); +assert ((num_b instanceof PositiveNumber) === false); + + +class ErrorAlways { + static [Symbol.hasInstance] (arg) { + throw new URIError("ErrorAlways"); + } +} + +try { + (new Object ()) instanceof ErrorAlways; + assert (false); +} catch (ex) { + assert (ex instanceof URIError); +} diff --git a/tests/jerry/es2015/instanceof-symbol-hasinstance.js b/tests/jerry/es2015/instanceof-symbol-hasinstance.js new file mode 100644 index 00000000..aa3aba89 --- /dev/null +++ b/tests/jerry/es2015/instanceof-symbol-hasinstance.js @@ -0,0 +1,86 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function NoParent () { } + +Object.defineProperty (NoParent, Symbol.hasInstance, { + value: function (arg) { return false; } +}); + +var obj = new NoParent (); + +assert ((obj instanceof NoParent) === false); + +try { + Object.defineProperty (NoParent, Symbol.hasInstance, { + value: function (arg) { return true; } + }); + assert (false) +} catch (ex) { + assert (ex instanceof TypeError); +} + + +function PositiveNumber () { } + +Object.defineProperty (PositiveNumber, Symbol.hasInstance, { + value: function (arg) { return (arg instanceof Number) && (arg >= 0); } +}) + +var num_a = new Number (33); +var num_b = new Number (-50); + +assert ((num_a instanceof PositiveNumber) === true); +assert ((num_b instanceof PositiveNumber) === false); + + +function ErrorAlways () { } + +Object.defineProperty (ErrorAlways, Symbol.hasInstance, { + value: function (arg) { throw new URIError ("ErrorAlways"); } +}) + +try { + (new Object ()) instanceof ErrorAlways; + assert (false); +} catch (ex) { + assert (ex instanceof URIError); +} + + +function NonCallable () { } + +Object.defineProperty (NonCallable, Symbol.hasInstance, { value: 11 }); + +try { + (new Object ()) instanceof NonCallable; + assert (false); +} catch (ex) { + assert (ex instanceof TypeError); +} + + +function ErrorGenerator () { } + +Object.defineProperty (ErrorGenerator, Symbol.hasInstance, { + get: function () { throw new URIError ("ErrorGenerator"); } +}); + +try { + (new Object ()) instanceof ErrorGenerator; + assert (false); +} catch (ex) { + assert (ex instanceof URIError); +} diff --git a/tests/jerry/es2015/json-stringify.js b/tests/jerry/es2015/json-stringify.js new file mode 100644 index 00000000..afb49090 --- /dev/null +++ b/tests/jerry/es2015/json-stringify.js @@ -0,0 +1,48 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test with proxy +assert(JSON.stringify(new Proxy(['foo'], {})) === '["foo"]'); +assert(JSON.stringify(new Proxy({0:"foo"}, {})) === '{"0":"foo"}'); + +var target = [1,2,3]; +var handler = { + get(target, prop) { + if (prop == "length") + { + throw 42; + } + } +} + +try { + JSON.stringify(new Proxy(target,handler)); + assert(false); +} catch (e) { + assert(e === 42); +} + +var revocable = Proxy.revocable (target, { get (t, p , r) { + if (p == "toJSON") { + revocable.revoke(); + } +}}); +var proxy = revocable.proxy; + +try { + JSON.stringify(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/length-property.js b/tests/jerry/es2015/length-property.js new file mode 100644 index 00000000..5a9230a1 --- /dev/null +++ b/tests/jerry/es2015/length-property.js @@ -0,0 +1,146 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var builtin_objects = [ + Array, + ArrayBuffer, + Boolean, + DataView, + Date, + Error, + EvalError, + Function, + Map, + Number, + Object, + Promise, + RangeError, + ReferenceError, + RegExp, + Set, + String, + Symbol, + SyntaxError, + TypeError, + URIError, + WeakMap, + WeakSet, +]; + +var builtin_typedArrays = [ + Float32Array, + Float64Array, + Int16Array, + Int32Array, + Int8Array, + Uint16Array, + Uint32Array, + Uint8Array, + Uint8ClampedArray, +]; + + +(function () { + /* each length property is configurable */ + var desc; + + for (obj of builtin_objects) { + desc = Object.getOwnPropertyDescriptor(obj, 'length'); + assert(desc.writable === false); + assert(desc.enumerable === false); + assert(desc.configurable === true); + } + + for (ta of builtin_typedArrays) { + desc = Object.getOwnPropertyDescriptor(ta, 'length'); + assert(desc.writable === false); + assert(desc.enumerable === false); + assert(desc.configurable === true); + } +})(); + +(function () { + /* each length property can be deleted */ + for (obj of builtin_objects) { + assert(obj.hasOwnProperty('length') === true); + assert(delete obj.length); + assert(obj.hasOwnProperty('length') === false); + } + + for (ta of builtin_typedArrays) { + assert(ta.hasOwnProperty('length') === true); + assert(delete ta.length); + assert(ta.hasOwnProperty('length') === false); + } +})(); + +(function () { + /* test length property of builtin function */ + for (obj of builtin_objects) { + var property_names = Object.getOwnPropertyNames(obj); + for (var name of property_names) { + if (typeof obj[name] == 'function') { + var func = obj[name]; + var desc = Object.getOwnPropertyDescriptor(func, 'length'); + assert(desc.writable === false); + assert(desc.enumerable === false); + assert(desc.configurable === true); + + assert(func.hasOwnProperty('length') === true); + assert(delete func.length); + assert(func.hasOwnProperty('length') === false); + } + } + } +})(); + +(function () { + /* test length property of function objects */ + var normal_func = function () {}; + var arrow_func = () => {}; + var bound_func = normal_func.bind({}); + var nested_bound_func = arrow_func.bind().bind(1); + + var functions = [normal_func, arrow_func, bound_func, nested_bound_func]; + + for (func of functions) { + var desc = Object.getOwnPropertyDescriptor(func, 'length'); + assert(desc.writable === false); + assert(desc.enumerable === false); + assert(desc.configurable === true); + } + + for (func of functions) { + assert(func.hasOwnProperty('length') === true); + assert(delete func.length); + assert(func.hasOwnProperty('length') === false); + } +})(); + +(function() { + /* changing the length of f affects the bound function */ + function f(a,b,c) {} + Object.defineProperty(f, "length", { value: 30 }); + var g = f.bind(1,2) + assert(g.length === 29); +})(); + +(function() { + /* changing the length of f does not affect the bound function */ + function f(a,b,c) {} + var g = f.bind(1,2) + Object.defineProperty(f, "length", { value: 30 }); + assert(g.length === 2); +})(); diff --git a/tests/jerry/es2015/let1.js b/tests/jerry/es2015/let1.js new file mode 100644 index 00000000..809fc3ce --- /dev/null +++ b/tests/jerry/es2015/let1.js @@ -0,0 +1,42 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = 5; +var a = 6; +let b = 7; + +assert (a === 6); +assert (this.a === 6); +assert (b === 7); +assert (this.b === undefined); + +{ + let c; + c = 8; + + { + let c = 9; + assert (c === 9); + } + + { + function c() { return 10 } + assert (c() === 10); + } + + assert (c === 8); +} +assert (typeof c === "undefined"); + diff --git a/tests/jerry/es2015/let10.js b/tests/jerry/es2015/let10.js new file mode 100644 index 00000000..63cb5086 --- /dev/null +++ b/tests/jerry/es2015/let10.js @@ -0,0 +1,45 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_reference_error (code) +{ + try { + eval (code); + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } +} + +check_reference_error ("let b = a, a;"); +check_reference_error ("const b = b;"); +check_reference_error ("a; let b, a;"); +check_reference_error ("a = 1; let b, a;"); + +function f() { + return x + y.a; +} + +check_reference_error ("x"); +check_reference_error ("y"); +check_reference_error ("x = 1"); +check_reference_error ("y = 1"); + +let x = 6; +assert (x === 6); +let y = { a: 7 }; +assert (y.a === 7); + +assert (f() === 13); diff --git a/tests/jerry/es2015/let11.js b/tests/jerry/es2015/let11.js new file mode 100644 index 00000000..163d185f --- /dev/null +++ b/tests/jerry/es2015/let11.js @@ -0,0 +1,18 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let b = 5; +eval('function b() { return 8; }; assert(b() === 8);'); +assert(b === 5); diff --git a/tests/jerry/es2015/let12.js b/tests/jerry/es2015/let12.js new file mode 100644 index 00000000..2ef22d85 --- /dev/null +++ b/tests/jerry/es2015/let12.js @@ -0,0 +1,41 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +checkSyntax ("if (5) let a;"); +checkSyntax ("if (5) const a;"); +checkSyntax ("if (0) {} else let a;"); +checkSyntax ("if (0) {} else const a;"); +checkSyntax ("while (5) let a;"); +checkSyntax ("while (5) const a;"); +checkSyntax ("do let a; while (5)"); +checkSyntax ("do const a; while (5)"); +checkSyntax ("for (a in b) let c;"); +checkSyntax ("for (a in b) const c;"); +checkSyntax ("for (a of b) let c;"); +checkSyntax ("for (a of b) const c;"); +checkSyntax ("for (;;) let c;"); +checkSyntax ("for (;;) const c;"); +checkSyntax ("with ({}) let c;"); +checkSyntax ("with ({}) const c;"); +checkSyntax ("a: let c;"); +checkSyntax ("a: const c;"); diff --git a/tests/jerry/es2015/let13.js b/tests/jerry/es2015/let13.js new file mode 100644 index 00000000..862296d0 --- /dev/null +++ b/tests/jerry/es2015/let13.js @@ -0,0 +1,110 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Declaring let */ + +/* Note: l\u0065t is let */ + +function check_syntax_error (code) { + try { + eval(code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +function check_strict_syntax_error (code) { + "use strict" + + try { + eval(code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error("let let = 5") +check_syntax_error("const [let] = [1]") +check_syntax_error("const l\u0065t = 6") +check_syntax_error("let [l\u0065t] = [2]") +check_syntax_error("l\\u0065t a") +check_strict_syntax_error("var let = 5") +check_strict_syntax_error("function let() {}") +check_strict_syntax_error("for (let in []) ;") +check_strict_syntax_error("l\\u0065t;") + +var let = 1 +assert(let === 1) + +var [let] = [2] +assert(let === 2) + +var x = 0; +let = [ () => x = 1 ] + +l\u0065t[0]() +assert(x === 1) + +function f1() +{ + var a = 0 + + function let(l\u0065t) { + a = let + } + + let(3) + + assert(a === 3) +} +f1() + +function f2() +{ + var let = [1] + + /* First: destructuring pattern definition */ + let + [a] = [2] + + assert(a === 2) + + a = 0 + + /* Second: property access */ + l\u0065t + [a] = [3] + + assert(let[0][0] === 3) +} +f2() + +var arr = [] + +for (let in ["x","y"]) + arr.push(let) + +assert(arr[0] === "0") +assert(arr[1] === "1") + +/* Let and arrow */ + +for (let => 4; false ; ) ; + +let => 5 + +/* Let label */ +let: break let diff --git a/tests/jerry/es2015/let14.js b/tests/jerry/es2015/let14.js new file mode 100644 index 00000000..5020c085 --- /dev/null +++ b/tests/jerry/es2015/let14.js @@ -0,0 +1,54 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f() { return 4 } + +exit: { + assert(f() === 6); + break exit; + function f() { return 6; } +} +assert(f() === 4); + +{ + assert(f() === 6); + f = 1; + assert(f === 1); + function f() { return 6; } + f = 2; + assert(f === 2); +} +assert(f === 1); + +function g() { return 3 } +exit: { + assert(g() === 5); + function g() { return 4; } + break exit; + function g() { return 5; } +} +assert(g() === 5); + +function h() { + try { + x; + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } + + eval("exit: { assert(x() === 8); x = 4; break exit; function x() { return 8; } }"); + assert(x === undefined); +} +h(); diff --git a/tests/jerry/es2015/let15.js b/tests/jerry/es2015/let15.js new file mode 100644 index 00000000..5b4cdebc --- /dev/null +++ b/tests/jerry/es2015/let15.js @@ -0,0 +1,65 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +{ + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + let a = 1; + + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + let [b] = [2]; + + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + const {c} = { c:3 }; + + f(); + function f() { assert(a + b + c === 6) } +} + +{ + let a = 3; + let [b] = [4]; + const {c} = { c:5 }; + + let f = (function () { assert(a + b + c === 12) }) + f(); + + { + function g() { assert(a + b + c === 12) } + g(); + } +} + +{ + class C {} + + assert(function () { return C } () === C); +} diff --git a/tests/jerry/es2015/let2.js b/tests/jerry/es2015/let2.js new file mode 100644 index 00000000..9636e226 --- /dev/null +++ b/tests/jerry/es2015/let2.js @@ -0,0 +1,47 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_syntax_error (code) +{ + try { + eval (code); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +check_syntax_error ("let a; let b; let a"); +check_syntax_error ("let a, b, a"); +check_syntax_error ("var a; let a;"); +check_syntax_error ("var a; const a = 3;"); +check_syntax_error ("let a; var a;"); +check_syntax_error ("const a = 3; var x, y, a;"); +check_syntax_error ("const a"); +check_syntax_error ("{ const a }"); +check_syntax_error ("const a, b"); +check_syntax_error ("let a; { let b; { var a; } }"); +check_syntax_error ("{ { var a = 4; } }; let a = 3"); +check_syntax_error ("function a() {}; let a;"); +check_syntax_error ("let a; function a() {};"); +check_syntax_error ("{ { function a() {}; let a; } }"); +check_syntax_error ("{ { let a; function a() {}; } }"); +check_syntax_error ("let a = 1; const b = 5; const a = 2;"); +check_syntax_error ("try {} catch (e) { let e; }"); +check_syntax_error ("try {} catch (e) { const e = 1; }"); +check_syntax_error ("let A; class A {}"); +check_syntax_error ("const A; class A {}"); +check_syntax_error ("class A {}; let A"); +check_syntax_error ("class A {}; const A = 1"); diff --git a/tests/jerry/es2015/let3.js b/tests/jerry/es2015/let3.js new file mode 100644 index 00000000..0e74c619 --- /dev/null +++ b/tests/jerry/es2015/let3.js @@ -0,0 +1,87 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var g = -1; + +function f1() { + /* Function copied to var. */ + assert (g === undefined); + + { + assert (g() === 1); + function g() { return 1 }; + + { + assert (g() === 2); + function g() { return 2 }; + } + + assert (g() === 1); + } + + assert (g() === 2); +} +f1(); + +function f2() { + /* Function is not copied to var. */ + 'use strict' + assert (g === -1); + + { + assert (g() === 1); + function g() { return 1 }; + + { + assert (g() === 2); + function g() { return 2 }; + } + + assert (g() === 1); + } + + assert (g === -1); +} +f2(); + +function f3() { + /* Function hoisted as let. */ + assert (g === -1); + + { + let g = 1; + + { + if (true) + { + assert (g() === 2); + + if (true) + { + assert (g() === 2); + } + + function g() { return 2 }; + } + + assert (g === 1); + } + + assert (g === 1); + } + + assert (g === -1); +} +f3(); diff --git a/tests/jerry/es2015/let4.js b/tests/jerry/es2015/let4.js new file mode 100644 index 00000000..ffeb3979 --- /dev/null +++ b/tests/jerry/es2015/let4.js @@ -0,0 +1,87 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var g = -1; + +function f1() { + /* Function copied to var. */ + assert (g === undefined); + + { + assert (g() === 1); + function g() { return 1 }; + + { + eval("assert (g() === 2)"); + function g() { return 2 }; + } + + assert (g() === 1); + } + + assert (g() === 2); +} +f1(); + +function f2() { + /* Function is not copied to var. */ + 'use strict' + assert (g === -1); + + { + assert (g() === 1); + function g() { return 1 }; + + { + eval("assert (g() === 2)"); + function g() { return 2 }; + } + + assert (g() === 1); + } + + assert (g === -1); +} +f2(); + +function f3() { + /* Function hoisted as let. */ + assert (g === -1); + + { + let g = 1; + + { + if (true) + { + assert (g() === 2); + + if (true) + { + eval("assert (g() === 2)"); + } + + function g() { return 2 }; + } + + assert (g === 1); + } + + assert (g === 1); + } + + assert (g === -1); +} +f3(); diff --git a/tests/jerry/es2015/let5.js b/tests/jerry/es2015/let5.js new file mode 100644 index 00000000..05ec3e0a --- /dev/null +++ b/tests/jerry/es2015/let5.js @@ -0,0 +1,35 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let arr = []; + +for (var a = 0; a < 10; a++) +{ + let j = a; + var f; + + { + f = function () { return j; } + + let j = (a & 0x1) ? a + 10 : a + 100; + } + + arr[j] = f; +} + +for (var a = 0; a < 10; a++) +{ + assert (arr[a]() == ((a & 0x1) ? a + 10 : a + 100)) +} diff --git a/tests/jerry/es2015/let6.js b/tests/jerry/es2015/let6.js new file mode 100644 index 00000000..f1f270b6 --- /dev/null +++ b/tests/jerry/es2015/let6.js @@ -0,0 +1,79 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +try { + let a = 1; + eval ("assert(a === 1)"); +} catch (e) { + assert (false); +} + +assert (typeof a === "undefined"); + +try { + let a = 2; + eval ("assert(a === 2)"); + + assert (typeof b === "undefined"); + throw 3; +} catch (e) { + let b = e; + eval ("assert(b === 3)"); + + assert (typeof a === "undefined"); +} + +assert (typeof a === "undefined"); +assert (typeof b === "undefined"); + +try { + let a = 4; + eval ("assert(a === 4)"); + + assert (typeof b === "undefined"); +} finally { + let b = 5; + eval ("assert(b === 5)"); + + assert (typeof a === "undefined"); +} + +assert (typeof a === "undefined"); +assert (typeof b === "undefined"); + +try { + let a = 6; + eval ("assert(a === 6)"); + + assert (typeof b === "undefined"); + assert (typeof c === "undefined"); + throw 7; +} catch (e) { + let b = e; + eval ("assert(b === 7)"); + + assert (typeof a === "undefined"); + assert (typeof c === "undefined"); +} finally { + let c = 8; + eval ("assert(c === 8)"); + + assert (typeof a === "undefined"); + assert (typeof b === "undefined"); +} + +assert (typeof a === "undefined"); +assert (typeof b === "undefined"); +assert (typeof c === "undefined"); diff --git a/tests/jerry/es2015/let7.js b/tests/jerry/es2015/let7.js new file mode 100644 index 00000000..461905b4 --- /dev/null +++ b/tests/jerry/es2015/let7.js @@ -0,0 +1,84 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +assert (typeof f === "undefined"); + +function g() { return 6; } + +switch (g()) { +case f(): + + let g = 9; + + assert (g === 9); + + function f() { return 6; } + break; + +default: + assert (false); +} + +assert (f() === 6); + +switch (g()) { +case f() - 2: + + let g = 9; + + assert ((function() { return g + f(); })() === 17); + + function f() { return 8; } + break; + +default: + assert (false); +} + +assert (f() === 8); + +switch (g()) { +case g() + 5: + { + let g = 4; + assert (g == 4); + } + break; + +default: + /* If the declaration is not "executed", it has no effect */ + function g() { return 1; } + assert (false); +} + +assert (g() === 6); + +switch (g()) { +case g() * 2: + { + let g = 4; + assert (g == 4); + eval(); + } + + function g() { return 3; } + break; + +default: + assert (false); +} + +assert (g() === 3); diff --git a/tests/jerry/es2015/let8.js b/tests/jerry/es2015/let8.js new file mode 100644 index 00000000..86b3b68c --- /dev/null +++ b/tests/jerry/es2015/let8.js @@ -0,0 +1,58 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert (typeof A === "undefined"); + +{ + class A {}; + + { + let A = 6; + + assert (A === 6); + } + + assert (typeof A === "function"); +} + +assert (typeof A === "undefined"); + +{ + let A = 5; + { + { + class A {}; + + assert (typeof A === "function"); + } + + assert (A === 5); + } +} + +assert (typeof A === "undefined"); + +{ + let A = 5; + { + { + class A {}; + + eval ('assert (typeof A === "function")'); + } + + eval ('assert (A === 5)'); + } +} diff --git a/tests/jerry/es2015/let9.js b/tests/jerry/es2015/let9.js new file mode 100644 index 00000000..29797ed2 --- /dev/null +++ b/tests/jerry/es2015/let9.js @@ -0,0 +1,48 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function f() { + try { + a; + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } + + eval ("assert (a === undefined); { function a() { return 5; } }"); + assert (a() === 5); + + /* Variables created by eval can be deleted. */ + delete a; + + try { + a; + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } +} +f(); + +function g() { + let a = 1; + + eval ("assert (a === 1);" + + "{ function a() { return 2; } assert (a() === 2) }" + + "assert (a === 1);"); + + assert (a === 1); +} +g(); diff --git a/tests/jerry/es2015/map-iterators.js b/tests/jerry/es2015/map-iterators.js index 64122e3b..d65e34e9 100644 --- a/tests/jerry/es2015/map-iterators.js +++ b/tests/jerry/es2015/map-iterators.js @@ -32,13 +32,15 @@ methods.forEach(function (method) { } }); -var m = new Map([{0: '0', 1: 0}, +var testArray = [{0: '0', 1: 0}, {0: '1', 1: 1}, {0: '2', 1: 2}, {0: '3', 1: 3}, {0: '4', 1: 4}, {0: '5', 1: 5}, - {0: '6', 1: 6}]); + {0: '6', 1: 6}]; + +var m = new Map(testArray); methods.forEach(function(method) { assert(m[method]().toString() === '[object Map Iterator]'); @@ -62,63 +64,121 @@ methods.forEach(function (method) { } }); -var valueIterators = [m.values(), m[Symbol.iterator]()]; +var entryIterators = [m.entries(), m[Symbol.iterator]()]; var keyIterator = m.keys(); -var entryIterator = m.entries(); +var valueIterator = m.values(); var elementCount = m.size; for (var i = 0; i < elementCount; i++) { - valueIterators.forEach(function(element) { + entryIterators.forEach(function(element) { var next = element.next(); assert(next.done === false); - assert(next.value === i); + assert(next.value[0] === '' + i); + assert(next.value[1] === i); }); var next = keyIterator.next(); assert(next.done === false); assert(next.value === '' + i); - var next = entryIterator.next(); + var next = valueIterator.next(); assert(next.done === false); - assert(next.value[0] === '' + i); - assert(next.value[1] === i); + assert(next.value === i); } -valueIterators.forEach(function(element) { - var next = element.next(); - assert(next.done === true); - assert(next.value === undefined); - }); +entryIterators.forEach(function(element) { + var next = element.next(); + assert(next.done === true); + assert(next.value === undefined); +}); var next = keyIterator.next(); assert(next.done === true); assert(next.value === undefined); -next = entryIterator.next(); +next = valueIterator.next(); assert(next.done === true); assert(next.value === undefined); -var valueIterators = [m.values(), m[Symbol.iterator]()]; +var entryIterators = [m.entries(), m[Symbol.iterator]()]; var keyIterator = m.keys(); -var entryIterator = m.entries(); +var valueIterator = m.values(); var elementCount = m.size; for (var i = 0; i < elementCount; i++) { - valueIterators.forEach(function(element) { + entryIterators.forEach(function(element) { var next = element.next(); assert(next.done === false); - assert(next.value === i); + assert(next.value[0] === '' + i); + assert(next.value[1] === i); }); var next = keyIterator.next(); assert(next.done === false); assert(next.value === '' + i); - var next = entryIterator.next(); + var next = valueIterator.next(); assert(next.done === false); - assert(next.value[0] === '' + i); - assert(next.value[1] === i); + assert(next.value === i); m.delete('' + i); } assert(m.size === 0); + +m = new Map(testArray); +var loopCount = 0; +var expected = [{0: '0', 1: 0}, + {0: '2', 1: 2}, + {0: '4', 1: 4}, + {0: '6', 1: 6}, + {0: '1', 1: 1}, + {0: '3', 1: 3}, + {0: '5', 1: 5}] + +m.forEach(function(value, key) { + if (loopCount === 0) { + for (i = 0; i < testArray.length; i++) { + if (i % 2) { + m.delete(testArray[i][0]); + m.set(testArray[i][0], testArray[i][1]); + } + } + } + + assert (key === expected[loopCount][0]); + assert (value === expected[loopCount][1]); + + loopCount++; +}); + +assert(loopCount === expected.length); + +loopCount = 0; +expected = [{0: '0', 1: 0}, + {0: '1', 1: 1}]; + +for (var [key, value] of m) { + if (loopCount === 0) { + m.clear(); + m.set('1', 1); + } + + assert(key === expected[loopCount][0]); + assert(value === expected[loopCount][1]); + + loopCount++; +} + +m = new Map(testArray); +loopCount = 0; + +for (var [key, value] of m) { + if (loopCount === 0) { + m.delete('' + testArray.length - 1); + } + + assert(key === '' + loopCount); + assert(value === loopCount); + + loopCount++; +} diff --git a/tests/jerry/es2015/map-prototype-foreach.js b/tests/jerry/es2015/map-prototype-foreach.js index 300f20c8..218b064c 100644 --- a/tests/jerry/es2015/map-prototype-foreach.js +++ b/tests/jerry/es2015/map-prototype-foreach.js @@ -106,3 +106,13 @@ var object = { map.forEach (function (value, key) { assert (this._secret === 42); }, object); + +/* Test third argument of callback */ +map = new Map(); +map.set('foo', 42); +map.set('bar', 84); + +map.forEach(function(value, key, thisArg) { + assert (typeof thisArg === "object"); + assert (thisArg === map); +}); diff --git a/tests/jerry/es2015/map.js b/tests/jerry/es2015/map.js index 55b711e4..07876004 100644 --- a/tests/jerry/es2015/map.js +++ b/tests/jerry/es2015/map.js @@ -123,3 +123,37 @@ m = new Map([{0: "foo", 1: 3}, {0 : "bar", 1 : 2}]); assert (m.size === 2); assert (m.get("foo") === 3); assert (m.get("bar") === 2); + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +var closed = false; +var iter = createIterable([1, 2, 3], { + 'return': function(){ closed = true; return {}; } +}); +try { + new Map(iter); +} catch(e){} + +assert(closed === true); + +var map = new Map(); +map.set(-0, "foo"); +var k; +map.forEach(function (value, key) { + k = 1 / key; +}); + +assert(k === Infinity); +assert(map.get(+0) === "foo"); diff --git a/tests/jerry/es2015/math-acosh.js b/tests/jerry/es2015/math-acosh.js new file mode 100644 index 00000000..bdda500c --- /dev/null +++ b/tests/jerry/es2015/math-acosh.js @@ -0,0 +1,29 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var nan = NaN; +var p_zero = 0.0; +var m_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.acosh(NaN))); +assert(isNaN(Math.acosh(0))); +assert(isNaN(Math.acosh(Number.NEGATIVE_INFINITY))); +assert(isSameZero(Math.acosh(1), p_zero)); +assert(Math.acosh(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); + diff --git a/tests/jerry/es2015/math-asinh.js b/tests/jerry/es2015/math-asinh.js new file mode 100644 index 00000000..af4d2dd6 --- /dev/null +++ b/tests/jerry/es2015/math-asinh.js @@ -0,0 +1,29 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var nan = NaN; +var p_zero = 0.0; +var m_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.asinh(NaN))); +assert(isSameZero(Math.asinh(p_zero), p_zero)); +assert(isSameZero(Math.asinh(m_zero), m_zero)); +assert(Math.asinh(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.asinh(Number.NEGATIVE_INFINITY) === Number.NEGATIVE_INFINITY); + diff --git a/tests/jerry/es2015/math-atanh.js b/tests/jerry/es2015/math-atanh.js new file mode 100644 index 00000000..7d37f70a --- /dev/null +++ b/tests/jerry/es2015/math-atanh.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var nan = NaN; +var p_zero = 0.0; +var m_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.atanh(NaN))); +assert(isNaN(Math.atanh(2))); +assert(isNaN(Math.atanh(44))); +assert(isNaN(Math.atanh(-2))); +assert(isNaN(Math.atanh(-13))); +assert(isSameZero(Math.atanh(p_zero), p_zero)); +assert(isSameZero(Math.atanh(m_zero), m_zero)); +assert(Math.atanh(-1) === Number.NEGATIVE_INFINITY); +assert(Math.atanh(1) === Number.POSITIVE_INFINITY); diff --git a/tests/jerry/es2015/math-cbrt.js b/tests/jerry/es2015/math-cbrt.js new file mode 100644 index 00000000..700408a2 --- /dev/null +++ b/tests/jerry/es2015/math-cbrt.js @@ -0,0 +1,33 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.cbrt(NaN))); +assert(isSameZero(Math.cbrt(p_zero), p_zero)); +assert(isSameZero(Math.cbrt(n_zero), n_zero)); +assert(Math.cbrt(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.cbrt(Number.NEGATIVE_INFINITY) === Number.NEGATIVE_INFINITY); + +assert(Math.cbrt(1.0) === 1.0); +assert(Math.cbrt(-1.0) === -1.0); + +assert(Math.cbrt(27.0) === 3.0); +assert(Math.cbrt(0.001) === 0.1); diff --git a/tests/jerry/es2015/math-cosh.js b/tests/jerry/es2015/math-cosh.js new file mode 100644 index 00000000..f68e4cb4 --- /dev/null +++ b/tests/jerry/es2015/math-cosh.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +assert(isNaN(Math.cosh(NaN))); +assert(Math.cosh(p_zero) === 1); +assert(Math.cosh(n_zero) === 1); +assert(Math.cosh(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.cosh(Number.NEGATIVE_INFINITY) === Number.POSITIVE_INFINITY); diff --git a/tests/jerry/es2015/math-expm1.js b/tests/jerry/es2015/math-expm1.js new file mode 100644 index 00000000..2eb4f080 --- /dev/null +++ b/tests/jerry/es2015/math-expm1.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.expm1(NaN))); +assert(isSameZero(Math.expm1(p_zero), p_zero)); +assert(isSameZero(Math.expm1(n_zero), n_zero)); +assert(Math.expm1(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.expm1(Number.NEGATIVE_INFINITY) === -1); +assert(1/Math.expm1(-0) === Number.NEGATIVE_INFINITY) +assert(1/Math.expm1(0) === Number.POSITIVE_INFINITY) +assert(Math.expm1(1) <= 1.00000001 * (Math.E - 1)); +assert(Math.expm1(1) >= 0.99999999 * (Math.E - 1)); diff --git a/tests/jerry/es2015/math-functions-tonumber-rule2.js b/tests/jerry/es2015/math-functions-tonumber-rule2.js new file mode 100644 index 00000000..f1b39fa1 --- /dev/null +++ b/tests/jerry/es2015/math-functions-tonumber-rule2.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = ""; +var a = {valueOf: function() { str += "a"; return 1;}}; +var b = {valueOf: function() { str += "b"; return NaN;}}; +var c = {valueOf: function() { str += "c"; return 2;}}; +var d = {valueOf: function() { str += "d"; return Infinity;}}; +var e = {valueOf: function() { str += "e"; return 3;}}; + +Math.hypot (a, b, c, d, e); +assert (str === "abcde"); diff --git a/tests/jerry/es2015/math-log10.js b/tests/jerry/es2015/math-log10.js new file mode 100644 index 00000000..f936d898 --- /dev/null +++ b/tests/jerry/es2015/math-log10.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +assert(isNaN(Math.log10(NaN))); +assert(isNaN(Math.log10(-42))); +assert(isNaN(Math.log10(-3.0))); +assert(Math.log10(n_zero) === Number.NEGATIVE_INFINITY); +assert(Math.log10(p_zero) === Number.NEGATIVE_INFINITY); +assert(Math.log10(1) === p_zero); +assert(Math.log10(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.log10(10.0) === 1); +assert(Math.log10(100.0) === 2) diff --git a/tests/jerry/es2015/math-log1p.js b/tests/jerry/es2015/math-log1p.js new file mode 100644 index 00000000..42918db9 --- /dev/null +++ b/tests/jerry/es2015/math-log1p.js @@ -0,0 +1,30 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.log1p(NaN))); +assert(isNaN(Math.log1p(-42))); +assert(isNaN(Math.log1p(-3.0))); +assert(isSameZero(Math.log1p(n_zero), n_zero)); +assert(isSameZero(Math.log1p(p_zero), p_zero)); +assert(Math.log1p(-1) === Number.NEGATIVE_INFINITY); +assert(Math.log1p(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.log1p(Math.E - 1) === 1); diff --git a/tests/jerry/es2015/math-log2.js b/tests/jerry/es2015/math-log2.js new file mode 100644 index 00000000..7533be46 --- /dev/null +++ b/tests/jerry/es2015/math-log2.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +assert(isNaN(Math.log2(NaN))); +assert(isNaN(Math.log2(-42))); +assert(isNaN(Math.log2(-3.0))); +assert(Math.log2(n_zero) === Number.NEGATIVE_INFINITY); +assert(Math.log2(p_zero) === Number.NEGATIVE_INFINITY); +assert(Math.log2(1) === p_zero); +assert(Math.log2(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.log2(2.0) === 1); +assert(Math.log2(4.0) === 2) +assert(Math.log2(1024.0) === 10) diff --git a/tests/jerry/es2015/math-sinh.js b/tests/jerry/es2015/math-sinh.js new file mode 100644 index 00000000..e6a4137e --- /dev/null +++ b/tests/jerry/es2015/math-sinh.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.sinh(NaN))); +assert(isSameZero(Math.sinh(p_zero), p_zero)); +assert(isSameZero(Math.sinh(n_zero), n_zero)); +assert(Math.sinh(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.sinh(Number.NEGATIVE_INFINITY) === Number.NEGATIVE_INFINITY); diff --git a/tests/jerry/es2015/math-tanh.js b/tests/jerry/es2015/math-tanh.js new file mode 100644 index 00000000..26872cc1 --- /dev/null +++ b/tests/jerry/es2015/math-tanh.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.tanh(NaN))); +assert(isSameZero(Math.tanh(p_zero), p_zero)); +assert(isSameZero(Math.tanh(n_zero), n_zero)); +assert(Math.tanh(Number.POSITIVE_INFINITY) === 1); +assert(Math.tanh(Number.NEGATIVE_INFINITY) === -1); diff --git a/tests/jerry/es2015/math-trunc.js b/tests/jerry/es2015/math-trunc.js index 958e83dc..7a3796f7 100644 --- a/tests/jerry/es2015/math-trunc.js +++ b/tests/jerry/es2015/math-trunc.js @@ -18,13 +18,18 @@ var m_zero = -p_zero; var p_inf = Infinity; var m_inf = -p_inf; +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + assert (isNaN(Math['trunc'](NaN))); -assert (Math['trunc'](p_zero) === p_zero); -assert (Math['trunc'](m_zero) === m_zero); +assert (isSameZero (Math['trunc'](p_zero), p_zero)); +assert (isSameZero (Math['trunc'](m_zero), m_zero)); assert (Math['trunc'](p_inf) === p_inf); assert (Math['trunc'](m_inf) === m_inf); -assert (Math['trunc'](0.5) === p_zero); -assert (Math['trunc'](-0.5) === m_zero); +assert (isSameZero (Math['trunc'](0.5), p_zero)); +assert (isSameZero (Math['trunc'](-0.5), m_zero)); assert (Math['trunc'](1.2) === 1); assert (Math['trunc'](-1.5) === -1); assert (Math['trunc'](65.7) === 65); diff --git a/tests/jerry/es2015/module-export-fail-test.js b/tests/jerry/es2015/module-export-fail-test.js new file mode 100644 index 00000000..86052829 --- /dev/null +++ b/tests/jerry/es2015/module-export-fail-test.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This module is imported by failing tests. */ +export let a; diff --git a/tests/jerry/es2015/new-target-async.js b/tests/jerry/es2015/new-target-async.js new file mode 100644 index 00000000..1742ef96 --- /dev/null +++ b/tests/jerry/es2015/new-target-async.js @@ -0,0 +1,20 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +async function async_method () { + assert (new.target === undefined); +} + +async_method (); diff --git a/tests/jerry/es2015/new-target-class.js b/tests/jerry/es2015/new-target-class.js new file mode 100644 index 00000000..3fd69aa4 --- /dev/null +++ b/tests/jerry/es2015/new-target-class.js @@ -0,0 +1,63 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class Simple { + constructor () { + assert (new.target === Simple); + this.called = 0; + } + + get getter () { + this.called++; + return new.target; + } + + set setter (val) { + assert (new.target === undefined); + this.called++; + } +} + +var smp = new Simple (); +assert (smp.getter === undefined); +assert (smp.called === 1); +smp.setter = -1; +assert (smp.called === 2); + +class BaseA { + constructor () { + assert (new.target === SubA); + } +} + +class SubA extends BaseA { + constructor () { + super (); + assert (new.target === SubA); + } +} + +new SubA (); + +/* TODO: enable if there is class name support. */ +/* +class Named { + constructor () { + assert(new.target.name == "Named"); + } +} + +new Named (); +*/ diff --git a/tests/jerry/es2015/new-target-for-containers.js b/tests/jerry/es2015/new-target-for-containers.js new file mode 100644 index 00000000..e78af219 --- /dev/null +++ b/tests/jerry/es2015/new-target-for-containers.js @@ -0,0 +1,86 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var o = new Proxy (function f () {}, { get(t,p,r) { if (p == "prototype") { throw 42.1 } Reflect.get(...arguments) }}) + +try { + Reflect.construct (Map, [], o); + assert (false); +} catch (e) { + assert(e == 42.1) +} + +try { + Reflect.construct (Set, [], o); + assert (false); +} catch (e) { + assert(e == 42.1) +} + +try { + Reflect.construct (WeakMap, [], o); + assert (false); +} catch (e) { + assert(e == 42.1) +} + +try { + Reflect.construct (WeakSet, [], o); + assert (false); +} catch (e) { + assert(e == 42.1) +} + +try { + Reflect.construct (Map); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Set); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (WeakMap); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (WeakSet); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyMap extends Map {}; +class MySet extends Set {}; +class MyWeakMap extends WeakMap {}; +class MyWeakSet extends WeakSet {}; +var m1= new MyMap(); +var s1= new MySet(); +var wm1= new MyWeakMap(); +var ws1= new MyWeakSet(); + +assert(Object.getPrototypeOf(m1) == MyMap.prototype) +assert(Object.getPrototypeOf(s1) == MySet.prototype) +assert(Object.getPrototypeOf(wm1) == MyWeakMap.prototype) +assert(Object.getPrototypeOf(ws1) == MyWeakSet.prototype) diff --git a/tests/jerry/es2015/new-target-for-date-object.js b/tests/jerry/es2015/new-target-for-date-object.js new file mode 100644 index 00000000..07f64056 --- /dev/null +++ b/tests/jerry/es2015/new-target-for-date-object.js @@ -0,0 +1,40 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +try { + Reflect.construct (Date,); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Date, "2015-01-01"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Date, 1420070400000); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyDate extends Date {}; +var d1= new MyDate(); + +assert(Object.getPrototypeOf(d1) == MyDate.prototype) diff --git a/tests/jerry/es2015/new-target-generator.js b/tests/jerry/es2015/new-target-generator.js new file mode 100644 index 00000000..6839c9b7 --- /dev/null +++ b/tests/jerry/es2015/new-target-generator.js @@ -0,0 +1,33 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function *demo_gen () { + for (var idx = 0; idx < 3; idx++) + { + assert (new.target === undefined); + yield idx; + assert (new.target === undefined); + } +} + +var gen = demo_gen (); + +var value = 0; +for (var item of gen) +{ + value = item; +} + +assert (value === 2); diff --git a/tests/jerry/es2015/new-target.js b/tests/jerry/es2015/new-target.js new file mode 100644 index 00000000..cc6e8767 --- /dev/null +++ b/tests/jerry/es2015/new-target.js @@ -0,0 +1,161 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function null_target () { + assert (new.target === undefined); +} + +function demo () { + null_target (); + return new.target; +} + +assert (demo () === undefined); +assert ((new demo ()) === demo); + +/* new.target is only valid inside functions */ +try { + eval ("new.target"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + var eval_other = eval; + eval_other ("new.target"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +/* test with arrow function */ +var arrow_called = false; +function arrow () { + assert (new.target === arrow); + var mth = () => { return new.target; } + assert (mth () === arrow); + arrow_called = true; +} + +new arrow (); +assert (arrow_called === true); + +/* test unary operation */ +var f_called = false; +function f () { + assert (isNaN (-new.target)); + f_called = true; +} + +new f (); +assert (f_called === true); + +/* test property access */ +function fg (callback_object) { + callback_object.value = new.target.value; +} + +fg.value = 22; + +var test_obj = {}; +new fg (test_obj); + +assert (test_obj.value === 22); + + +/* test new.target with eval */ +function eval_test () { + var target = eval ("new.target"); + assert (target === eval_test); +} + +new eval_test (); + +function eval_eval_test () { + var target = eval ('eval("new.target")'); + assert (target === eval_eval_test); +} + +new eval_eval_test (); + +/* new.target is only valid in direct eval */ +function eval_test_2 () { + var ev = eval; + try { + ev ("new.target"); + assert (false); + } catch (ex) { + assert (ex instanceof SyntaxError); + } +} + +new eval_test_2 (); + +function eval_test_3 () { + var ev = eval; + try { + eval ("ev ('new.target')"); + assert (false); + } catch (ex) { + assert (ex instanceof SyntaxError); + } +} + +new eval_test_3 (); + +/* test assignment of the "new.target" */ +function expect_syntax_error (src) +{ + try { + eval (src); + assert (false); + } catch (ex) { + assert (ex instanceof SyntaxError); + } +} + +expect_syntax_error ("function assign () { new.target = 3; }"); +expect_syntax_error ("function assign () { new.target += 3; }"); +expect_syntax_error ("function assign () { new.target *= 3; }"); +expect_syntax_error ("function assign () { new.target -= 3; }"); +expect_syntax_error ("function assign () { new.target |= 3; }"); +expect_syntax_error ("function assign () { new.target &= 3; }"); + +expect_syntax_error ("function assign () { new.target++; }"); +expect_syntax_error ("function assign () { ++new.target; }"); +expect_syntax_error ("function assign () { new.target--; }"); +expect_syntax_error ("function assign () { --new.target; }"); + +expect_syntax_error ("function synt () { new....target; }"); + +function delete_test () { + assert ((delete new.target) === true); +} + +new delete_test (); + +function binary_test_1 () { + /*/ new.target is converted to string */ + assert ((new.target + 1) === "function(){/* ecmascript */}1"); +} +function binary_test_2 () { assert (isNaN (new.target - 3)); } +function binary_test_3 () { assert (isNaN (new.target * 2)); } +function binary_test_4 () { assert (isNaN (new.target / 4)); } + +new binary_test_1 (); +new binary_test_2 (); +new binary_test_3 (); +new binary_test_4 (); diff --git a/tests/jerry/es2015/number-constants.js b/tests/jerry/es2015/number-constants.js new file mode 100644 index 00000000..9042d611 --- /dev/null +++ b/tests/jerry/es2015/number-constants.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//This test will not pass on FLOAT32 due to precision issues + +assert(Number.MAX_SAFE_INTEGER === 9007199254740991); +assert(Number.MIN_SAFE_INTEGER === -9007199254740991); +assert(Number.EPSILON === 2.2204460492503130808472633361816e-16); diff --git a/tests/jerry/es2015/number-methods.js b/tests/jerry/es2015/number-methods.js new file mode 100644 index 00000000..5dfdd45c --- /dev/null +++ b/tests/jerry/es2015/number-methods.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (Number.parseInt ('18528769') === 18528769); +assert (Number.parseFloat ('1.2e3') === 1.2e3); +assert (parseInt ('18528769') === 18528769); +assert (parseFloat ('1.2e3') === 1.2e3); + +assert(Number.parseInt === parseInt); + +assert(Number.parseFloat === parseFloat); diff --git a/tests/jerry/es2015/object-assign.js b/tests/jerry/es2015/object-assign.js index f4fc0055..93ed999d 100644 --- a/tests/jerry/es2015/object-assign.js +++ b/tests/jerry/es2015/object-assign.js @@ -156,3 +156,12 @@ try { } catch (e) { assert (e instanceof TypeError) } + +var asd = Symbol ("asd"); +var foo = Symbol ("foo"); +var bar = Symbol ("bar"); +var obj = {1: 5, "a": 6, [foo]: 7, [asd]: 8, [bar]: 9}; +var result = Object.assign ({}, obj); +assert (result[foo] == 7); +assert (result[asd] == 8); +assert (result[bar] == 9); diff --git a/tests/jerry/es2015/object-freeze-with-symbol.js b/tests/jerry/es2015/object-freeze-with-symbol.js new file mode 100644 index 00000000..15de72de --- /dev/null +++ b/tests/jerry/es2015/object-freeze-with-symbol.js @@ -0,0 +1,28 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var s1 = Symbol(); +var s2 = Symbol(); +var obj = {}; + +obj[s1] = 1; +Object.freeze(obj); + +obj[s1] = 2; +obj[s2] = 3 + +assert(obj[s1] === 1); +assert(obj[s2] === undefined); +assert(delete obj[s1] === false); diff --git a/tests/jerry/es2015/object-get-own-property-names.js b/tests/jerry/es2015/object-get-own-property-names.js new file mode 100644 index 00000000..6bc79505 --- /dev/null +++ b/tests/jerry/es2015/object-get-own-property-names.js @@ -0,0 +1,23 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Check that Object.getOwnPropertyNames does NOT include Symbols by default. +var asd = Symbol ("asd"); +var foo = Symbol ("foo"); +var bar = Symbol ("bar"); +var result = Object.getOwnPropertyNames ({1: 5, "a": 6, [foo]: 7, [asd]: 8, [bar]: 9}); +assert (!Object.hasOwnProperty (result, foo)); +assert (!Object.hasOwnProperty (result, asd)); +assert (!Object.hasOwnProperty (result, bar)); diff --git a/tests/jerry/es2015/object-get-own-property-symbols.js b/tests/jerry/es2015/object-get-own-property-symbols.js index 83848f93..540c2271 100644 --- a/tests/jerry/es2015/object-get-own-property-symbols.js +++ b/tests/jerry/es2015/object-get-own-property-symbols.js @@ -109,11 +109,3 @@ assert (props.indexOf(foo2) !== -1); assert (props.length === 2); assert (Object.getOwnPropertyDescriptor (object, foo).enumerable === true); assert (Object.getOwnPropertyDescriptor (object, foo2).enumerable === false); - -// Test non-object argument -try { - Object.getOwnPropertySymbols ('hello'); - assert (false); -} catch (e) { - assert (e instanceof TypeError); -} diff --git a/tests/jerry/es2015/object-initializer.js b/tests/jerry/es2015/object-initializer.js index 19767828..c411fb19 100644 --- a/tests/jerry/es2015/object-initializer.js +++ b/tests/jerry/es2015/object-initializer.js @@ -70,3 +70,8 @@ default: assert(o.get == 8); assert(o.set == 12); } + +var obj = { get() { return 5; }, set() { return 6; } }; + +assert (obj.get() === 5); +assert (obj.set() === 6); diff --git a/tests/jerry/es2015/object-is.js b/tests/jerry/es2015/object-is.js new file mode 100644 index 00000000..02017517 --- /dev/null +++ b/tests/jerry/es2015/object-is.js @@ -0,0 +1,59 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(Object.is(2, "foo") === false); +assert(Object.is(null, 2) === false); + +var x; +assert(Object.is(x, 2) === false); + +assert(Object.is(null, null) === true); + +assert(Object.is(2, 8) === false); +assert(Object.is(8, 8) === true); + +assert(Object.is(3.14, 6.28) === false); +assert(Object.is(3.14, 3.14) === true); + +assert(Object.is('foo', 'foo') === true); +assert(Object.is('foo', 'bar') === false); +assert(Object.is(new String('foo'), 'foo') === false); + +assert(Object.is([], []) === false); + +assert(Object.is(true, true) === true); +assert(Object.is(false, false) === true); +assert(Object.is(true, false) === false); +assert(Object.is(false, true) === false); +assert(Object.is("", false) === false); +assert(Object.is(0, false) === false); + +sym1 = Symbol.for('foo'); +sym2 = Symbol.for('foo'); +assert(Object.is(sym1, sym2) === true); +assert(Object.is(Symbol('foo'), Symbol('foo')) === false); + +var foo = { a: 1 }; +var bar = { a: 1 }; +var zoo = foo; +assert(Object.is(foo, foo) === true); +assert(Object.is(foo, bar) === false); +assert(Object.is(foo, zoo) === true); + +// Special Cases +assert(Object.is(+0, -0) === false); +assert(Object.is(+0, 0) === true); +assert(Object.is(-0, -0) === true); +assert(Object.is(-0, 0) === false); +assert(Object.is(NaN, 0/0) === true); diff --git a/tests/jerry/es2015/object-methods.js b/tests/jerry/es2015/object-methods.js new file mode 100644 index 00000000..dca58a67 --- /dev/null +++ b/tests/jerry/es2015/object-methods.js @@ -0,0 +1,60 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (JSON.stringify (Object.getOwnPropertyNames("hello")) === '["0","1","2","3","4","length"]'); + +var n = Object.assign(42, {a: "str"}); +assert (n instanceof Number); +assert (n.valueOf() === 42); +assert (n.a === "str"); + +assert (JSON.stringify (Object.getOwnPropertySymbols("hello")) === '[]'); + +assert (JSON.stringify (Object.keys("str")) === '["0","1","2"]'); + +var d = Object.getOwnPropertyDescriptor("hello", '1'); +assert (d.value === "e"); +assert (d.writable === false); +assert (d.enumerable === true); +assert (d.configurable === false); + +assert (Object.seal(42) === 42); +assert (Object.seal("a") === "a"); +assert (Object.seal(undefined) === undefined); +assert (Object.seal() === undefined); + +assert (Object.isSealed(42) === true); +assert (Object.isSealed("a") === true); +assert (Object.isSealed(undefined) === true); +assert (Object.isSealed() === true); + +assert (Object.freeze(42) === 42); +assert (Object.freeze("a") === "a"); +assert (Object.freeze(undefined) === undefined); +assert (Object.freeze() === undefined); + +assert (Object.isFrozen(42) === true); +assert (Object.isFrozen("a") === true); +assert (Object.isFrozen(undefined) === true); +assert (Object.isFrozen() === true); + +assert (Object.preventExtensions(42) === 42); +assert (Object.preventExtensions("a") === "a"); +assert (Object.preventExtensions(undefined) === undefined); +assert (Object.preventExtensions() === undefined); + +assert (Object.isExtensible(42) === false); +assert (Object.isExtensible("a") === false); +assert (Object.isExtensible(undefined) === false); +assert (Object.isExtensible() === false); diff --git a/tests/jerry/es2015/object-pattern.js b/tests/jerry/es2015/object-pattern.js new file mode 100644 index 00000000..3db8a1c7 --- /dev/null +++ b/tests/jerry/es2015/object-pattern.js @@ -0,0 +1,234 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +function mustThrow (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +} + +checkSyntax ("var {a}"); +checkSyntax ("var {a, o.a}"); +checkSyntax ("var {a, ...b}"); +checkSyntax ("var {a, ...b} = 4"); +checkSyntax ("var {a, ...[b] = 4}"); +checkSyntax ("var {a,,} = 4"); +checkSyntax ("var {a :} = 4"); +checkSyntax ("var {a : ,} = 4"); +checkSyntax ("var {a : ['foobar']} = 4"); +checkSyntax ("var {let}"); +checkSyntax ("var {get = []"); +checkSyntax ("var {get : 5}"); +checkSyntax ("var {[a = {},}"); +checkSyntax ("let {a,a} = []"); +checkSyntax ("let {a : b, b} = []"); +checkSyntax ("const {a,a} = []"); +checkSyntax ("const {a : b, b} = []"); +checkSyntax ("try { let {$} = $;"); +checkSyntax ("let a, { 'x': a } = {x : 4};"); +checkSyntax ("let a, { x: b.c } = {x : 6};"); +checkSyntax ("let {a:(a)} = {a:1}"); + +mustThrow ("var {a} = null"); +mustThrow ("var {a} = undefined"); +mustThrow ("function f ({a : {}}) {}; f({});"); +mustThrow ("function f ({}) {}; f();"); + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment + +// Basic assignment +(function () { + var o = {p: 42, q: true}; + var {p, q} = o; + + assert (p === 42); + assert (q === true); +}) (); + +// Assignment without declaration +(function () { + var a, b; + ({a, b} = {a: 1, b: 2}); + + assert (a === 1); + assert (b === 2); +}) (); + +// Assigning to new variable names +(function () { + var o = {p: 42, q: true}; + var {p: foo, q: bar} = o; + + assert (foo === 42); + assert (bar === true); +}) (); + +// Default values +(function () { + var {a = 10, b = 5} = {a: 3}; + + assert (a === 3); + assert (b === 5); +}) (); + + +// Assigning to new variables names and providing default values +(function () { + var {a: aa = 10, b: bb = 5} = {a: 3}; + + assert (aa === 3); + assert (bb === 5); +}) (); + +// Nested object and array destructuring +(function () { + const metadata = { + title: 'Scratchpad', + translations: [ + { + locale: 'de', + localization_tags: [], + last_edit: '2014-04-14T08:43:37', + url: '/de/docs/Tools/Scratchpad', + title: 'JavaScript-Umgebung' + } + ], + url: '/en-US/docs/Tools/Scratchpad' + }; + + let { + title: englishTitle, // rename + translations: [ + { + title: localeTitle, // rename + }, + ], + } = metadata; + + assert (englishTitle === "Scratchpad"); + assert (localeTitle === "JavaScript-Umgebung"); +}) (); + +// Computed object property names and destructuring +(function () { + let key = 'z'; + let {[key]: foo} = {z: 'bar'}; + + assert (foo === "bar"); +}) (); + +// Invalid JavaScript identifier as a property name +(function () { + const foo = { 'fizz-buzz': true }; + const { 'fizz-buzz': fizzBuzz } = foo; + + assert (fizzBuzz === true); +}) (); + +// Combined Array and Object Destructuring +(function () { + const props = [ + { id: 1, name: 'Fizz'}, + { id: 2, name: 'Buzz'}, + { id: 3, name: 'FizzBuzz'} + ]; + + const [,, { name }] = props; + + assert (name === "FizzBuzz"); +}) (); + +// The prototype chain is looked up when the object is deconstructed +(function () { + var obj = {self: '123'}; + Object.getPrototypeOf(obj).prot = '456'; + const {self, prot} = obj; + assert (self === '123'); + assert (prot === '456'); +}) (); + +// Test inner patterns I. +(function () { + var a,b,c,d,e; + var o = { a : { b: 2 }, c: 1, d: { e: undefined } }; + var { e: { b : a } = { b : 2, a : 1}, d: { e: { b : e = 2} = { b } } } = o; + assert (a === 2); + assert (b === undefined); + assert (c === undefined); + assert (d === undefined); + assert (e === 2); +}) (); + +// Test inner patterns II. +(function () { + var a,b,c,d,e; + var o = { a : [{ b : 2 ,}, d], e : 5 }; + + var { a: [{b, c = 3}, d = 4], e } = o; + assert (a === undefined); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +}) (); + +// Multiple declaration +(function () { + var {a} = {a : 1}, {b} = {b : 2}; + + assert (a === 1); + assert (b === 2); +}) (); + +// Force the creation of lexical environment I. +(function () { + const {a} = {a : 1}; + eval(); + + assert (a === 1); +}) (); + +// Force the creation of lexical environment II. +(function () { + let {a} = {a : 1}; + eval(); + + assert (a === 1); +}) (); + +// Check the parsing of AssignmentElement +(function () { + var a = 6; + ({"a": ((a)) } = {a : 7}); + assert (a === 7); +}) (); + +try { + eval ("var a = 0; -{a} = {a:1}"); + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/object-prototype-proto.js b/tests/jerry/es2015/object-prototype-proto.js new file mode 100644 index 00000000..6e6bde60 --- /dev/null +++ b/tests/jerry/es2015/object-prototype-proto.js @@ -0,0 +1,89 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval('var o = { __proto__ : 5, __proto__ : 5 }'); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + +var f = function(){}; +assert((new f()).__proto__ === f.prototype); + +var o = {}; +o.__proto__ = Array.prototype; +assert(o instanceof Array); + +var obj = Object.create(null) +p = {}; +obj.__proto__ = p; +assert(Object.getPrototypeOf(obj) !== p); + +var Circle = function () {}; +var shape = {}; +var circle = new Circle(); + +shape.__proto__ = circle; + +assert(Object.getPrototypeOf(shape) === circle); +assert(shape.__proto__ === circle); + +assert(Object.prototype.hasOwnProperty('__proto__') === true); + +var desc = Object.getOwnPropertyDescriptor(Object.prototype,"__proto__"); +assert((desc && "get" in desc && "set" in desc && desc.configurable && !desc.enumerable) === true); + +assert((Object.getOwnPropertyNames(Object.prototype).indexOf('__proto__') > -1) === true); + +try { + shape.__proto__ = shape; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var o2 = { ["__proto__"] : null }; +assert(o2.__proto__ === null); +assert(Object.getPrototypeOf(o2) === Object.prototype); + +var o3 = { __proto__ : null }; +assert(o3.__proto__ === undefined); +assert(Object.getPrototypeOf(o3) === null); + +var o4 = { "__proto__" : null }; +assert(o4.__proto__ === undefined); +assert(Object.getPrototypeOf(o4) === null); + +var __proto__ = []; +var o5 = { __proto__ }; +assert(o5.__proto__ === __proto__); +assert(Object.getPrototypeOf(o5) === Object.prototype); + +var o6 = { __proto__() { return "42" } }; +assert(o6.__proto__() === "42"); +assert(Object.getPrototypeOf(o6) === Object.prototype); + +var o7 = { __\u0070r\u006ft\u006f__: null }; +assert(o7.__proto__ === undefined); +assert(Object.getPrototypeOf(o7) === null); + +var o8 = { }; +o8.__proto__ = Array.prototype; +assert(Object.getPrototypeOf(o8) === Array.prototype); + +var str1 = '{"__proto__": [] }'; +var obj1 = JSON.parse(str1); +assert(Object.getPrototypeOf(obj1) === Object.prototype); +assert(Array.isArray(obj1.__proto__)); diff --git a/tests/jerry/es2015/object-seal-with-symbol.js b/tests/jerry/es2015/object-seal-with-symbol.js new file mode 100644 index 00000000..8da1f7c4 --- /dev/null +++ b/tests/jerry/es2015/object-seal-with-symbol.js @@ -0,0 +1,28 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var s1 = Symbol(); +var s2 = Symbol(); +var obj = {}; + +obj[s1] = 1; +Object.seal(obj); + +obj[s1] = 2; +obj[s2] = 3 + +assert(obj[s1] === 2); +assert(obj[s2] === undefined); +assert(delete obj[s1] === false); diff --git a/tests/jerry/es2015/octal-literal.js b/tests/jerry/es2015/octal-literal.js new file mode 100644 index 00000000..da9e0bed --- /dev/null +++ b/tests/jerry/es2015/octal-literal.js @@ -0,0 +1,46 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function checkSyntaxError (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +checkSyntaxError ("0p"); +checkSyntaxError ("0o"); +checkSyntaxError ("0o0123456789"); +checkSyntaxError ("0o9"); + +checkSyntaxError ("0p"); +checkSyntaxError ("0O"); +checkSyntaxError ("0O9"); + +// Check strict mode +checkSyntaxError ("'use strict'; 0777"); +assert (eval ("'use strict'; 0o777") === 511); + +assert (0o123 === 83); +assert (0o77777777 === 16777215); +assert (0o767 === parseInt ("767", 8)); +assert (0767 === 0o767); + +assert (0O123 === 83); +assert (0O77777777 === 16777215); +assert (0O767 === parseInt ("767", 8)); +assert (0767 === 0O767); diff --git a/tests/jerry/es2015/promise-all-iterator.js b/tests/jerry/es2015/promise-all-iterator.js new file mode 100644 index 00000000..4c53cf3c --- /dev/null +++ b/tests/jerry/es2015/promise-all-iterator.js @@ -0,0 +1,81 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +// iterator next +Promise.all({[Symbol.iterator]() { return {get next() { throw 5; }}} +}).then(onfullfilled => { + // If this is not called, the promise has failed, and catch must be called. + assert(false); +}).catch(err => { + assert(err === 5); +}); + +// iterator value +Promise.all({ [Symbol.iterator] () { return { next () { return { get value () { throw 5 }}}}} +}).then(onfullfilled => { + // If this is not called, the promise has failed, and catch must be called. + assert(false); +}).catch(err => { + assert(err === 5); +}); + +// iterator done +Promise.all({ [Symbol.iterator] () { return { next () { return { get done () { throw 5 }}}}} +}).then(onfullfilled => { + // If this is not called, the promise has failed, and catch must be called. + assert(false); +}).catch(err => { + assert(err === 5); +}); + +// iterator get +Promise.all({ get [Symbol.iterator] () { throw 5 } +}).then(onfullfilled => { + // If this is not called, the promise has failed, and catch must be called. + assert(false); +}).catch(err => { + assert(err === 5); +}); + +var fulfills = Promise.all(createIterable([ + new Promise(resolve => { resolve("foo"); }), + new Promise(resolve => { resolve("bar"); }), +])); +var rejects = Promise.all(createIterable([ + new Promise((_, reject) => { reject("baz"); }), + new Promise((_, reject) => { reject("qux"); }), +])); + +fulfills.then(result => { assert (result + "" === "foo,bar"); }); +rejects.catch(result => { assert (result === "baz"); }); + +var closed = false; +delete Promise.resolve; +Promise.all(createIterable([1,2,3], {'return': function () { closed = true; }})); +assert (closed); diff --git a/tests/jerry/es2015/promise-new-target.js b/tests/jerry/es2015/promise-new-target.js new file mode 100644 index 00000000..18d730ea --- /dev/null +++ b/tests/jerry/es2015/promise-new-target.js @@ -0,0 +1,26 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +try { + Reflect.construct (Promise); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyPromise extends Promise {}; + +var p1= new MyPromise(function(){}); +assert(Object.getPrototypeOf(p1) == MyPromise.prototype) diff --git a/tests/jerry/es2015/promise-race-iterator.js b/tests/jerry/es2015/promise-race-iterator.js new file mode 100644 index 00000000..e225d548 --- /dev/null +++ b/tests/jerry/es2015/promise-race-iterator.js @@ -0,0 +1,69 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +// iterator next +Promise.race({[Symbol.iterator]() { return {get next() { throw 5; }}} +}).catch(err => { + assert(err === 5); +}); + +// iterator value +Promise.race({ [Symbol.iterator] () { return { next () { return { get value () { throw 5 }}}}} +}).catch(err => { + assert(err === 5); +}); + +// iterator done +Promise.race({ [Symbol.iterator] () { return { next () { return { get done () { throw 5 }}}}} +}).catch(err => { + assert(err === 5); +}); + +// iterator get +Promise.race({ get [Symbol.iterator] () { throw 5 } +}).catch(err => { + assert(err === 5); +}); + +var fulfills = Promise.race(createIterable([ + new Promise(resolve => { resolve("foo"); }), + new Promise(resolve => { resolve("bar"); }), +])); +var rejects = Promise.race(createIterable([ + new Promise((_, reject) => { reject("baz"); }), + new Promise((_, reject) => { reject("qux"); }), +])); + +fulfills.then(result => { assert (result + "" === "foo"); }); +rejects.catch(result => { assert (result === "baz"); }); + +var closed = false; +delete Promise.resolve; +Promise.race(createIterable([1,2,3], {'return': function () { closed = true; }})); +assert (closed); diff --git a/tests/jerry/es2015/promise-species.js b/tests/jerry/es2015/promise-species.js new file mode 100644 index 00000000..6773bfcc --- /dev/null +++ b/tests/jerry/es2015/promise-species.js @@ -0,0 +1,53 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that Promises use @@species appropriately + +// Another constructor with no species will not be instantiated + +var test = new Promise(function(){}); +var bogoCount = 0; +function bogusConstructor() { bogoCount++; } +test.constructor = bogusConstructor; +assert(Promise.resolve(test) instanceof Promise); +assert(!(Promise.resolve(test) instanceof bogusConstructor)); + +// If there is a species, it will be instantiated +// @@species will be read exactly once, and the constructor is called with a +// function +var count = 0; +var params; + +class MyPromise extends Promise { + constructor(...args) { + super(...args); + params = args; + } + static get [Symbol.species]() { + count++ + return this; + } +} + +var myPromise = MyPromise.resolve().then(); +assert(1 === count); +assert(1 === params.length); +assert('function' === typeof(params[0])); +assert(myPromise instanceof MyPromise); +assert(myPromise instanceof Promise); diff --git a/tests/jerry/es2015/promise-thenable.js b/tests/jerry/es2015/promise-thenable.js new file mode 100644 index 00000000..4a47e57f --- /dev/null +++ b/tests/jerry/es2015/promise-thenable.js @@ -0,0 +1,32 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var counter = 0; + +function f() { } + +f.then = function(resolve) { + if (++counter < 10) { + resolve(f) + } +} + +new Promise(function(resolve) { + resolve(f) +}) + +function __checkAsync() { + assert(counter == 10) +} diff --git a/tests/jerry/es2015/proxy_call.js b/tests/jerry/es2015/proxy_call.js new file mode 100644 index 00000000..d5750571 --- /dev/null +++ b/tests/jerry/es2015/proxy_call.js @@ -0,0 +1,355 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = function () {}; +var handler = { apply (target) { + throw 42; +}}; + +var proxy = new Proxy (target, handler); + +try { + // opfunc_call + proxy (5) + assert (false); +} catch (e) { + assert (e == 42); +} + +try { + var revocable = Proxy.revokable (function () {}, {}); + proxy = new Proxy(revocable.proxy, {}) + revocable.revoke(); + proxy (5) + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +function sum (a, b) { + return a + b; +} + +var handler = { + apply: function (target, thisArg, argumentsList) { + return target (argumentsList[0], argumentsList[1]) * 10; + } +}; + +var proxy1 = new Proxy(sum, handler); + +assert (sum (1, 2) === 3); +assert (proxy1 (1, 2) === 30); + +// Non Callable tests +var proxy = new Proxy ({},{}); +try { + proxy() + assert (false) +} catch (e) { + assert (e instanceof TypeError) +} + +var proxy2 = new Proxy(proxy, {}); +try { + proxy2() + assert (false) +} catch (e) { + assert (e instanceof TypeError) +} + +// No arguments +var called = false; +var target = function () { + called = true; +} +var proxy = new Proxy (target, {}); +assert (!called); +proxy(); +assert (called); + +called = false; +var proxy2 = new Proxy (proxy, {}); +assert (!called); +proxy2(); +assert (called); + +//1 Argument +var called = false; +var target = function (a) { + called = true; + assert ('1' === a); +} +var proxy = new Proxy (target, {}); +assert (!called); +proxy ('1'); +assert (called); + +// 2 Arguments +var called = false; +var target = function (a, b) { + called = true; + assert ('1' === a); + assert ('2' === b); +} +var proxy = new Proxy (target, {}); +assert (!called); +proxy ('1', '2'); +assert (called); + +// Changed receiver +var apply_receiver = {receiver:true}; +var seen_receiver = undefined; +var target = function () { + seen_receiver = this; +} +var proxy = new Proxy (target, {}); +assert (undefined === seen_receiver); +Reflect.apply (proxy, apply_receiver, [1,2,3,4]); +assert (apply_receiver === seen_receiver); + +// Trap +var called_target = false; +var called_handler = false; +var target = function (a, b) { + called_target = true; + assert (1 === a); + assert (2 === b); +} +var handler = { + apply: function (target, this_arg, args) { + target.apply (this_arg, args); + called_handler = true; + } +} +var proxy = new Proxy (target, handler); +assert (!called_target); +assert (!called_handler); +Reflect.apply (proxy, {rec:1}, [1,2]); +assert (called_target); +assert (called_handler); + +// Trap array arg +var called_target = false; +var called_handler = false; +var target = function (a, b) { + called_target = true; + var arg = [1, 2]; + assert (arg[0] === a[0]); + assert (arg[1] === a[1]); + assert (3 === b); +} +var handler = { + apply: function (target, this_arg, args) { + target.apply (this_arg, args); + called_handler = true; + } +} +var proxy = new Proxy (target, handler); +assert (!called_target); +assert (!called_handler); +proxy ([1,2], 3); +assert (called_target); +assert (called_handler); + +// Trap object arg +var called_target = false; +var called_handler = false; +var target = function (o) { + called_target = true; + var obj = {a: 1, b: 2} + assert (obj.a === o.a); + assert (obj.b === o.b) +} +var handler = { + apply: function (target, this_arg, args) { + target.apply (this_arg, args); + called_handler = true; + } +} +var proxy = new Proxy (target, handler); +assert (!called_target); +assert (!called_handler); +proxy ({a: 1, b: 2}); +assert (called_target); +assert (called_handler); + +// Trap generator arg +function* gen () { + yield 1; + yield 2; + yield 3; +} +var called_target = false; +var called_handler = false; +var target = function (g) { + called_target = true; + var arr = [1, 2, 3]; + var arr2 = [...g]; + assert (arr[0] === arr2[0]); + assert (arr[1] === arr2[1]); + assert (arr[2] === arr2[2]); +} +var handler = { + apply: function (target, this_arg, args) { + target.apply (this_arg, args); + called_handler = true; + } +} +var proxy = new Proxy (target, handler); +assert (!called_target); +assert (!called_handler); +proxy (gen()); +assert (called_target); +assert (called_handler); + +// Noncallable Trap +var called_target = false; +var target = function () { + called_target = true; +}; +var handler = { + apply: 'non callable trap' +}; + +var proxy = new Proxy(target, handler); +try { + proxy (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (!called_target); + +// Null trap +var _args; +var target = function (a, b) { + _args = [a, b]; + return a + b; +}; +var handler = { + apply: null +}; + +var proxy = new Proxy (target, handler); +var result = proxy (1, 2); + +assert (result === 3); +assert (_args.length === 2); +assert (_args[0] === 1); +assert (_args[1] === 2); + +var values = [NaN, 1.5, 100, /RegExp/, "string", {}, [], Symbol(), + new Map(), new Set(), new WeakMap(), new WeakSet()]; +values.forEach(target => { + target = Object (target); + var proxy = new Proxy(target, { apply() { assert (false) } }); + try { + proxy(); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + ({ proxy }).proxy(); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Reflect.apply(proxy, null, []); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Reflect.apply(proxy, { proxy }, []); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Reflect.apply(proxy, { proxy }, []); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Function.prototype.call.apply (proxy, [null]); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Function.prototype.apply.apply (proxy, [null, []]); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + var proxy_to_proxy = new Proxy (proxy, { apply() { assert (false); } }); + + try { + proxy_to_proxy (); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + ({ proxy_to_proxy }).proxy_to_proxy(); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Reflect.apply (proxy_to_proxy, null, []); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Reflect.apply (proxy_to_proxy, { proxy }, []); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Function.prototype.call.apply (proxy_to_proxy, [null]); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + Function.prototype.apply.apply (proxy_to_proxy, [null, []]); + assert (false); + } catch (e) { + assert (e instanceof TypeError); + } +}); diff --git a/tests/jerry/es2015/proxy_construct.js b/tests/jerry/es2015/proxy_construct.js new file mode 100644 index 00000000..46ff8e0b --- /dev/null +++ b/tests/jerry/es2015/proxy_construct.js @@ -0,0 +1,165 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = function () {}; +var handler = { construct (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // opfunc_call + new proxy(5) + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 22.1.2.3.4.a + Array.of.call(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic functionality +var proxy = new Proxy({},{}); + +try { + new proxy(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var proxy2 = new Proxy(proxy, {}); + +try { + new proxy2(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var called = false; + +function Target() { + called = true; + this.property1 = 'value1'; +}; + +Target.prototype = {}; +var proxy = new Proxy(Target, {}); + +assert(called === false); + +var instance = new proxy(); + +assert(called === true); +assert('value1' === instance.property1); +assert(Target.prototype === Object.getPrototypeOf(instance)); + +var proxy2 = new Proxy(proxy, {}); +called = false; +var instance2 = new proxy2(); + +assert(called === true); +assert('value1' === instance2.property1); +assert(Target.prototype === Object.getPrototypeOf(instance)); + +function Target2(a, b) { + this.sum = a + b; +}; +var handler = { + construct(t, c, args) { + return { sum: 42 }; + } +}; +var proxy = new Proxy(Target2, handler); +assert((new proxy(1, 2)).sum === 42); + +function Target3(arg1, arg2) { + this.arg1 = arg1; + this.arg2 = arg2; +} +var seen_target, seen_arguments, seen_new_target; +var handler = { + construct(target, args, new_target) { + seen_target = target; + seen_arguments = args; + seen_new_target = new_target; + return Reflect.construct(target, args, new_target); + } +} +var proxy = new Proxy(Target3, handler); +var instance = new proxy('a', 'b'); + +assert(Target3 === seen_target); +assert(JSON.stringify(seen_arguments) === '["a","b"]'); +assert(proxy === seen_new_target); +assert('a' === instance.arg1); +assert('b' === instance.arg2); + +var instance2 = Reflect.construct(proxy, ['a1', 'b1'], Array); +assert(Target3 === seen_target); +assert(JSON.stringify(seen_arguments) === '["a1","b1"]'); +assert(Array === seen_new_target); +assert('a1'=== instance2.arg1); +assert('b1' === instance2.arg2); + +var p = new Proxy(function() {}, { + construct: function(target, argumentsList, newTarget) { + throw 42; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test when invariants gets violated +var p = new Proxy(function() {}, { + construct: function(target, argumentsList, newTarget) { + return 1; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var p = new Proxy({}, { + construct: function(target, argumentsList, newTarget) { + return {}; + } +}); + +try { + new p(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_create.js b/tests/jerry/es2015/proxy_create.js new file mode 100644 index 00000000..e0e19ee5 --- /dev/null +++ b/tests/jerry/es2015/proxy_create.js @@ -0,0 +1,58 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {} +var handler = {}; +var proxy = new Proxy(target, handler); + +var revocable = Proxy.revocable(target, handler); +revocable.revoke(); +var rev_proxy = revocable.proxy; + +try { + Proxy(target, handler); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(undefined, undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(rev_proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy({}, rev_proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(rev_proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_define_own_property.js b/tests/jerry/es2015/proxy_define_own_property.js new file mode 100644 index 00000000..5f05b995 --- /dev/null +++ b/tests/jerry/es2015/proxy_define_own_property.js @@ -0,0 +1,176 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = function () {}; +var handler = { defineProperty (target) { + throw 42; +}, construct () { + return {}; +}}; + +var proxy = new Proxy(target, handler); + +// 22.1.2.3.8.c +Array.of.call(proxy, 5) + +// test basic functionality +var g_target, g_name; + +var handler = { + defineProperty: function(target, name, desc) { + g_target = target; + g_name = name; + return true; + } +} + +var target = {}; +var proxy = new Proxy(target, handler); +var desc = { value: 1, writable: true, configurable: true }; + +Object.defineProperty(proxy, "foo", desc); + +assert(target === g_target); +assert("foo" === g_name); + +var handler = { + defineProperty: function(target, name, desc) { + Object.defineProperty(target, name, desc); + } +} + +var proxy = new Proxy(target, handler); + +Object.defineProperty(proxy, "bar", desc); + +assert(proxy.bar === 1); + +/* TODO - remove this comment when [[GetOwnProperty]] is implemented +proxy.bar = 2; +assert(proxy.bar === 2); +*/ + +delete proxy.bar; +assert(proxy.bar === undefined); + +/* TODO - remove this comment when [[GetOwnProperty]] is implemented +Object.defineProperty(proxy, "name", { + get() { + return this._name; + }, + set(value) { + this._name = value; + } +}); + +proxy.name = "foo"; + +assert(proxy.name === "foo"); +assert(target.name === "foo"); +*/ + +// test when trap is not callable +var target = {}; +var handler = { + defineProperty: 1 +} + +var proxy = new Proxy(target, handler); + +try { + Object.defineProperty(proxy, "foo", {value: "foo"}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when trap is undefined +var target = {}; +var handler = { + defineProperty: undefined +} + +var proxy = new Proxy(target, handler); +var desc = { value: 1 }; + +Object.defineProperty(proxy, "prop1", desc); +assert(proxy.prop1 === 1); + +var target2 = {}; +var proxy2 = new Proxy(target2, {}); + +Object.defineProperty(proxy2, "prop2", desc); +assert(proxy2.prop2 === 1); + +// test when invariants gets violated +var target = {}; +var handler = { + defineProperty: function(target, name, desc) { + return true; + } +} + +var proxy = new Proxy(target, handler); + +Object.preventExtensions(target); + +try { + Object.defineProperty(proxy, "foo", {value: 1}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var target = {}; +var desc = {value: 1, writable: true, configurable: false, enumerable: true}; + +var proxy = new Proxy(target, handler); + +try { + Object.defineProperty(proxy, "foo", desc); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var target = {}; +var handler = { + defineProperty: function(target, name, desc) { + return true; + } +} + +var proxy = new Proxy(target, handler); + +Object.defineProperty(target, "foo", {value: 1, writable: false, configurable: false}); + +try { + Object.defineProperty(proxy, 'foo', {value: 2}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +target.bar = "baz"; + +try { + Object.defineProperty(proxy, 'bar', {value: 2, configurable: false}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_delete.js b/tests/jerry/es2015/proxy_delete.js new file mode 100644 index 00000000..1cd21ce7 --- /dev/null +++ b/tests/jerry/es2015/proxy_delete.js @@ -0,0 +1,164 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { deleteProperty (target) { + throw 42; +}, get (object, propName) { + if (propName == "length") { + return 5; + } +}}; + +var proxy = new Proxy(target, handler); + +var a = 5; + +// ecma_op_delete_binding +with (proxy) { + delete a +} + +try { + // 22.1.3.16.6.e + Array.prototype.pop.call(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic functionality +var target = {foo: "bar"}; +var handler = { + deleteProperty(obj, prop) { + delete obj[prop]; + } +} + +var proxy = new Proxy(target, handler); + +assert(target.foo === "bar") +assert(proxy.foo === "bar"); + +assert(delete proxy.foo === false); + +assert(target.foo === undefined); +assert(proxy.foo === undefined); + +assert(target.bar === undefined); +assert(delete proxy.bar == false); +assert(target.bar === undefined); + +var handler2 = { + deleteProperty(obj, prop) { + delete obj[prop]; + return true; + } +} + +var proxy = new Proxy(target, handler2); + +assert(target.bar === undefined); +assert(delete proxy.bar == true); +assert(target.bar === undefined); + +// test with no trap +var target = {1: 42}; +var handler = {}; +var proxy = new Proxy(target, handler); + +assert(target[1] === 42) +assert(delete proxy[1] === true) +assert(target[1] === undefined); + +// test with undefined trap +var target = {2: 52}; +var handler = { deleteProperty: null}; +var proxy = new Proxy(target, handler); + +assert(target[2] === 52) +assert(delete proxy[2] === true) +assert(target[2] === undefined); + +// test when trap is invalid +var target = {}; +var handler = { deleteProperty: true }; +var proxy = new Proxy(target, handler); + +try { + delete proxy[0]; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when handler is null +var revocable = Proxy.revocable ({}, {}); +var proxy = revocable.proxy; +revocable.revoke(); + +try { + delete proxy.foo; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when target is proxy +var target = {prop: "foo"}; +var handler = { + deleteProperty(obj, prop) { + delete obj[prop]; + } +}; + +var proxy1 = new Proxy(target, handler); +var proxy2 = new Proxy(proxy1, handler); + +assert(target.prop === "foo"); +assert(proxy1.prop === "foo"); +assert(proxy2.prop === "foo"); + +delete proxy2.prop; + +assert(target.prop === undefined); +assert(proxy1.prop === undefined); +assert(proxy2.prop === undefined); + +// tests when invariants gets violated +var target = {}; +var handler = { + deleteProperty(obj, prop) { + delete obj[prop]; + return true; + } +}; + +Object.defineProperty(target, "foo", { + configurable: false, + value: "foo" +}); + +var proxy = new Proxy (target, handler); + +try { + delete proxy.foo; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_get.js b/tests/jerry/es2015/proxy_get.js new file mode 100644 index 00000000..821bb99a --- /dev/null +++ b/tests/jerry/es2015/proxy_get.js @@ -0,0 +1,140 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { get (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // vm_op_get_value + proxy.a + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // ecma_op_get_value_object_base + proxy[2]; + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // @@toPrimitive symbol + proxy + "foo"; + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic funcionality +var target = { + target_one: 1, + prop: "value" +}; + +var handler = {handler: 1}; +var proxy = new Proxy(target, handler); + +assert(proxy.prop === "value"); +assert(proxy.nothing === undefined); +assert(proxy.handler === undefined); + +handler.get = function () {return "value 2"}; + +assert(proxy.prop === "value 2"); +assert(proxy.nothing === "value 2"); +assert(proxy.handler === "value 2"); + +var handler2 = new Proxy({get: function() {return "value 3"}}, {}); +var proxy2 = new Proxy(target, handler2); + +assert(proxy2.prop === "value 3"); +assert(proxy2.nothing === "value 3"); +assert(proxy2.handler === "value 3"); + +var get = []; +var p = new Proxy([0,,2,,4,,], { get: function(o, k) { get.push(k); return o[k]; }}); +Array.prototype.reverse.call(p); + +assert(get + '' === "length,0,4,2"); + +// test when get throws an error +var handler = new Proxy({}, {get: function() {throw 42;}}); +var proxy = new Proxy ({}, handler); + +try { + proxy.prop; + assert(false); +} catch (e) { + assert(e === 42); +} + +// test when trap is undefined +var handler = new Proxy({}, {get: function() {return undefined}}); +var target = {prop: "value"}; +var proxy = new Proxy(target, handler); +assert(proxy.prop === "value"); +assert(proxy.prop2 === undefined); + +// test when invariants gets violated +var target = {}; +var handler = {get: function(r, p){if (p != "key4") return "value"}} +var proxy = new Proxy(target, handler); + +assert(proxy.key === "value"); +assert(proxy.key2 === "value"); +assert(proxy.key3 === "value"); +assert(proxy.key4 === undefined); + +Object.defineProperty(target, "key", { + configurable: false, + writable: false, + value: "different value" +}); + +try { + proxy.key; + assert(false); +} catch (e) { + assert(e instanceof TypeError) +} + +Object.defineProperty(target, "key2", { + configurable: false, + get: function() {return "different value"} +}); + +assert(proxy.key2 === "value"); + +Object.defineProperty(target, "key3", { + configurable: false, + set: function() {} +}); + +try { + proxy.key3; + assert(false); +} catch (e) { + assert(e instanceof TypeError) +} diff --git a/tests/jerry/es2015/proxy_get_own_property_descriptor.js b/tests/jerry/es2015/proxy_get_own_property_descriptor.js new file mode 100644 index 00000000..43218728 --- /dev/null +++ b/tests/jerry/es2015/proxy_get_own_property_descriptor.js @@ -0,0 +1,270 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { getOwnPropertyDescriptor (target) { + throw "cat"; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.3.2.5 + Object.prototype.hasOwnProperty.call(proxy); + assert(false); +} catch(e) { + assert(e == "cat"); +} + +try { + // 19.1.3.4 + Object.prototype.propertyIsEnumerable.call(proxy) + assert(false); +} catch(e) { + assert(e == "cat"); +} + +try { + // 19.1.2.6.5 + Object.getOwnPropertyDescriptor(proxy) + assert(false); +} catch(e) { + assert(e == "cat"); +} + +var target = {}; +var configurable_desc = { + value: 123, + configurable: true, + writable: true, + enumerable: false, +}; +Object.defineProperty(target, "configurable", configurable_desc); + +var nonconfigurable_desc = { + value: 234, + configurable: false, + writable: false, + enumerable: true +} +Object.defineProperty(target, "nonconfigurable", nonconfigurable_desc); + +var proxied_desc = { + value: 345, + configurable: true +}; + +var proxied_desc = { + value: 345, + configurable: true +}; + +var handler = { + "getOwnPropertyDescriptor": function(target, name) { + if (name === "proxied") { + return proxied_desc; + } + if (name === "return_null") { + return null; + } + return Object.getOwnPropertyDescriptor(target, name); + } +}; + +var proxy = new Proxy(target, handler); +var proxy_without_handler = new Proxy(target, {}); + +// Checking basic functionality: + +var configurable_obj = Object.getOwnPropertyDescriptor(proxy, "configurable"); + +assert(configurable_desc.value == configurable_obj.value); +assert(configurable_desc.configurable == configurable_obj.configurable); +assert(configurable_desc.writable == configurable_obj.writable); +assert(configurable_desc.enumerable == configurable_obj.enumerable); + +var nonconfigurable_obj = Object.getOwnPropertyDescriptor(proxy, "nonconfigurable"); +assert(nonconfigurable_obj.value == nonconfigurable_desc.value); +assert(nonconfigurable_obj.configurable == nonconfigurable_desc.configurable); +assert(nonconfigurable_obj.writable == nonconfigurable_desc.writable); +assert(nonconfigurable_obj.enumerable == nonconfigurable_desc.enumerable); + +var other_obj = { value: proxied_desc.value, + configurable: proxied_desc.configurable, + enumerable: false, + writable: false } +var proxied_obj = Object.getOwnPropertyDescriptor(proxy, "proxied"); + +assert(other_obj.value == proxied_obj.value); +assert(other_obj.configurable == proxied_obj.configurable); +assert(other_obj.writable == proxied_obj.writable); +assert(other_obj.enumerable == proxied_obj.enumerable); + +var other_obj2 = Object.getOwnPropertyDescriptor(proxy_without_handler, "configurable"); + +assert(other_obj2.value == configurable_desc.value); +assert(other_obj2.configurable == configurable_desc.configurable); +assert(other_obj2.writable == configurable_desc.writable); +assert(other_obj2.enumerable == configurable_desc.enumerable); + +var other_obj3 = Object.getOwnPropertyDescriptor(proxy_without_handler, "nonconfigurable"); + +assert(other_obj3.value == nonconfigurable_desc.value); +assert(other_obj3.configurable == nonconfigurable_desc.configurable); +assert(other_obj3.writable == nonconfigurable_desc.writable); +assert(other_obj3.enumerable == nonconfigurable_desc.enumerable); + +try { + Object.getOwnPropertyDescriptor(proxy, "return_null"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +// Checking invariants mentioned explicitly by the ES spec: + +// (Inv-1) "A property cannot be reported as non-existent, if it exists as a +// non-configurable own property of the target object." +handler.getOwnPropertyDescriptor = function(target, name) { return undefined; }; + +try { + Object.getOwnPropertyDescriptor(proxy, "nonconfigurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +assert(Object.getOwnPropertyDescriptor(proxy, "configurable") == undefined) + +// (Inv-2) "A property cannot be reported as non-configurable, if it does not +// exist as an own property of the target object or if it exists as a +// configurable own property of the target object." +handler.getOwnPropertyDescriptor = function(target, name) { + return {value: 234, configurable: false, enumerable: true}; +}; + +try { + Object.getOwnPropertyDescriptor(proxy, "nonexistent"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +try { + Object.getOwnPropertyDescriptor(proxy, "configurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +assert(!Object.getOwnPropertyDescriptor(proxy, "nonconfigurable").configurable); + +// (Inv-3) "A property cannot be reported as non-existent, if it exists as an +// own property of the target object and the target object is not extensible." +Object.seal(target); +handler.getOwnPropertyDescriptor = function(target, name) { return undefined; }; + +try { + Object.getOwnPropertyDescriptor(proxy, "configurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +try { + Object.getOwnPropertyDescriptor(proxy, "nonconfigurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +assert(undefined == Object.getOwnPropertyDescriptor(proxy, "nonexistent")); + +// (Inv-4) "A property cannot be reported as existent, if it does not exist as +// an own property of the target object and the target object is not +// extensible." +var existent_desc = {value: "yes"}; +handler.getOwnPropertyDescriptor = function() { return existent_desc; }; + +try { + Object.getOwnPropertyDescriptor(proxy, "nonexistent"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +var new_obj = { value: "yes", + writable: false, + enumerable: false, + configurable: false }; +var conf_proxied = Object.getOwnPropertyDescriptor(proxy, "configurable"); + +assert(new_obj.value == conf_proxied.value); +assert(new_obj.configurable == conf_proxied.configurable); +assert(new_obj.writable == conf_proxied.writable); +assert(new_obj.enumerable == conf_proxied.enumerable); + +// Checking individual bailout points in the implementation: + +// Step 6: Trap is not callable. +handler.getOwnPropertyDescriptor = {}; + +try { + Object.getOwnPropertyDescriptor(proxy, "configurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +// Step 8: Trap throws. +handler.getOwnPropertyDescriptor = function() { throw "unicorn"; }; + +try { + Object.getOwnPropertyDescriptor(proxy, "configurable"); + assert(false); +} catch(e) { + assert(e == "unicorn"); +} + +// Step 9: Trap result is neither undefined nor an object. +handler.getOwnPropertyDescriptor = function() { return 1; } + +try { + Object.getOwnPropertyDescriptor(proxy, "configurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +// Step 11b: See (Inv-1) above. +// Step 11e: See (Inv-3) above. + +// Step 16: Incompatible PropertyDescriptor; a non-configurable property +// cannot be reported as configurable. (Inv-4) above checks more cases. +handler.getOwnPropertyDescriptor = function(target, name) { + return {value: 456, configurable: true, writable: true} +}; + +try { + Object.getOwnPropertyDescriptor(proxy, "nonconfigurable"); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} + +// Step 17: See (Inv-2) above. diff --git a/tests/jerry/es2015/proxy_get_prototoype_of.js b/tests/jerry/es2015/proxy_get_prototoype_of.js new file mode 100644 index 00000000..e86f3014 --- /dev/null +++ b/tests/jerry/es2015/proxy_get_prototoype_of.js @@ -0,0 +1,168 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { getPrototypeOf (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.2.9.2 + Object.getPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 19.1.3.3 + Object.prototype.isPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +(function () { + class e extends Array {}; + function f () {}; + function g () {}; + + Object.setPrototypeOf(g, proxy); + + // 7.3.19.7.b + try { + g instanceof f; + assert(false); + } catch (e) { + assert(e === 42); + } + + // ecma_op_implicit_class_constructor_has_instance [[GetPrototypeOf]] + try { + g instanceof e; + assert(false); + } catch (e) { + assert(e === 42); + } +})(); + +try { + // 9.4.1.3.3 + Function.prototype.bind.call(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test basic functionality +var target = {}; +var handler = { + getPrototypeOf(target) { + return Array.prototype; + } +} +var proxy = new Proxy(target, handler); + +assert(Object.getPrototypeOf(proxy) === Array.prototype); +assert(Reflect.getPrototypeOf(proxy) === Array.prototype); +assert(Array.prototype.isPrototypeOf(proxy)); +assert(proxy instanceof Array); + +var obj = Object.preventExtensions({}); +assert(Object.getPrototypeOf(obj) === Object.prototype); + +var handler = { + getPrototypeOf(target) { + return Object.prototype; + } +} +var proxy = new Proxy(target, handler); +assert(Object.getPrototypeOf(proxy) === Object.prototype); + +// test with no trap +var target = {}; +var handler = {}; +var proxy = new Proxy(target, handler); + +assert(Object.getPrototypeOf(proxy) === Object.prototype); + +// test with "undefined" trap +var target = {}; +var handler = { getPrototypeOf: null }; +var proxy = new Proxy(target, handler); + +assert(Object.getPrototypeOf(proxy) === Object.prototype); + +// test with invalid trap +var target = {}; +var handler = { getPrototypeOf: 42 }; +var proxy = new Proxy(target, handler); + +try { + Object.getPrototypeOf(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when target is proxy +var target = {}; +var handler = {}; +var proxy = new Proxy(target, handler); + +var target_prototype = {}; +handler.getPrototypeOf = function() { + return target_prototype ; +} + +var proxy2 = new Proxy(proxy, handler); +assert(Object.getPrototypeOf(proxy2) === target_prototype); + +// test when invariants gets violated +var target = {}; +var handler = { + getPrototypeOf(target) { + return 'foo'; + } +} +var proxy = new Proxy(target, handler); + +try { + Object.getPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var target = Object.preventExtensions({}); +var handler = { + getPrototypeOf(target) { + return {}; + } +} + +var proxy = new Proxy(target, handler); + +try { + Object.getPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_has.js b/tests/jerry/es2015/proxy_has.js new file mode 100644 index 00000000..fd765755 --- /dev/null +++ b/tests/jerry/es2015/proxy_has.js @@ -0,0 +1,172 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { has (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 12.9.3 + "foo" in proxy; + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 8.1.1.2.1 + with (proxy) { + p; + assert(false); + } + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // ecma_op_put_value_lex_env_base/[[HasProperty]] + with (proxy) { + function a (){} + assert(false); + } + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic functionality +var target = { + "target_one": 1 +}; + +var handler = { + has: function(target, prop) { + return prop == "present"; + } +} + +var proxy = new Proxy(target, handler); + +assert("present" in proxy === true); +assert("non_present" in proxy === false); + +var target = { + foo: 5, + bar: 10 +}; + +var handler = { + has: function(target, prop) { + if (prop[0] === 'f') { + return false; + } + return prop in target; + } +}; + +var proxy = new Proxy(target, handler); + +assert("foo" in proxy === false); +assert("bar" in proxy === true); + +// test with no trap +var target = { + foo: "foo" +}; +var handler = {}; +var proxy = new Proxy(target, handler); + +assert("foo" in proxy === true); + +// test with "undefined" trap +var target = { + foo: "foo" +}; +var handler = {has: null}; +var proxy = new Proxy(target, handler); + +assert("foo" in proxy === true); + +// test with invalid trap +var target = { + foo: "foo" +}; +var handler = {has: 42}; +var proxy = new Proxy(target, handler); + +try { + "foo" in proxy; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when target is proxy +var target = { + foo: "foo" +}; + +var handler = { + has: function(target, prop) { + return prop in target; + } +} + +var proxy1 = new Proxy(target, handler); +var proxy2 = new Proxy(proxy1, handler); + +assert("foo" in proxy2 === true); + +// test when invariants gets violated +var target = {}; + +Object.defineProperty(target, "prop", { + configurable: false, + value: 10 +}) + +var handler = { + has: function(target, prop) { + return false; + } +} + +var proxy = new Proxy(target, handler); + +try { + 'prop' in proxy; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var target = { a: 10 }; +Object.preventExtensions(target); + +var proxy = new Proxy(target, handler); + +try { + 'a' in proxy; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_is_extensible.js b/tests/jerry/es2015/proxy_is_extensible.js new file mode 100644 index 00000000..0f01c90f --- /dev/null +++ b/tests/jerry/es2015/proxy_is_extensible.js @@ -0,0 +1,164 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// error checks +var target = {}; +var handler = { isExtensible (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 7.3.15 + Object.isFrozen(proxy) + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 7.3.15 + Object.isSealed(proxy) + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 7.2.5 + Object.isExtensible(proxy) + assert(false); +} catch (e) { + assert(e === 42); +} + +// no trap +var target = {}; +var handler = {}; +var proxy = new Proxy(target, handler); +assert(Object.isExtensible(target) === true) +assert(Object.isExtensible(proxy) === true); +Object.preventExtensions(target); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); + +// undefined trap +var target = {}; +var handler = { isExtensible: null }; +var proxy = new Proxy(target, handler); +assert(Object.isExtensible(target) === true) +assert(Object.isExtensible(proxy) === true); +Object.preventExtensions(target); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); + +// invalid trap +var target = {}; +var handler = { isExtensible: true }; +var proxy = new Proxy(target, handler); + +try { + Object.isExtensible(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// valid trap +var target = { prop1: true }; +var handler = { + isExtensible(target) { + target.prop1 = false; + return Object.isExtensible(target); + } +}; + +var proxy = new Proxy(target, handler); +assert(Object.isExtensible(proxy) === true); +assert(target.prop1 === false); +Object.preventExtensions(target); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); + +// trap result is invalid +var target = {}; +var handler = { + isExtensible(target) { + return false; + } +}; + +var proxy = new Proxy(target, handler); + +try { + Object.isExtensible(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// handler is null +var target = {}; +var handler = { + isExtensible (target) { + return Object.isExtensible(target); + } +}; + +var revocable = Proxy.revocable (target, {}); +var proxy = revocable.proxy; +revocable.revoke(); + +try { + Object.isExtensible(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// proxy within proxy +var target = {}; +var handler1 = { + isExtensible(target) { + return Object.isExtensible(target); + } +}; + +var handler2 = { + isExtensible(target) { + return false; + } +}; + +var proxy = new Proxy(target, handler1); +var proxy2 = new Proxy(proxy, handler1); +assert(Object.isExtensible(proxy2) === true); + +var proxy3 = new Proxy(proxy, handler2); + +try { + Object.isExtensible(proxy3); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var proxy4 = new Proxy(proxy2, handler1); +Object.preventExtensions(target); +assert(Object.isExtensible(proxy4) === false); diff --git a/tests/jerry/es2015/proxy_own_keys.js b/tests/jerry/es2015/proxy_own_keys.js new file mode 100644 index 00000000..9c2f0380 --- /dev/null +++ b/tests/jerry/es2015/proxy_own_keys.js @@ -0,0 +1,225 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function array_check(result_array, expected_array) { + assert(result_array instanceof Array); + assert(result_array.length === expected_array.length); + for (var idx = 0; idx < expected_array.length; idx++) { + assert(result_array[idx] === expected_array[idx]); + } +} + +var target = {}; +var handler = { ownKeys (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // Array.prototype.sort + Array.prototype.sort.call(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 19.1.2.14.4 + Object.keys(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 19.1.2.7.1 + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 19.1.2.8.1 + Object.getOwnPropertySymbols(proxy); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic functionality +var symA = Symbol("smA"); +var symB = Symbol("smB"); +var target = { prop1: "prop1", prop2: "prop2"}; +target[symB] = "s3"; +var handler = { + ownKeys: function(target) { + return ["foo", "bar", symA]; + } +} + +var proxy = new Proxy(target, handler); + +array_check(Reflect.ownKeys(proxy), ["foo", "bar", symA]); +array_check(Object.getOwnPropertyNames(proxy), ["foo", "bar"]); +array_check(Object.keys(proxy), ["foo", "bar"]); +array_check(Object.getOwnPropertySymbols(proxy), [symA]); + +handler.ownKeys = function(target) {return Object.getOwnPropertyNames(target);}; + +array_check(Reflect.ownKeys(proxy), ["prop1", "prop2"]); +array_check(Object.getOwnPropertyNames(proxy), ["prop1", "prop2"]); +array_check(Object.keys(proxy), ["prop1", "prop2"]); +array_check(Object.getOwnPropertySymbols(proxy), []); + +// test with no trap +var target = { prop1: "prop1", prop2: "prop2"}; +var handler = {}; +var proxy = new Proxy(target, handler); + +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["prop1","prop2"]'); + +// test wtih "undefined" trap +var target = { prop1: "prop1", prop2: "prop2"}; +var handler = {ownKeys: null}; +var proxy = new Proxy(target, handler); + +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["prop1","prop2"]'); + +// test with invalid trap +var target = { prop1: "prop1", prop2: "prop2"}; +var handler = {ownKeys: 42}; +var proxy = new Proxy(target, handler); + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when CreateListFromArrayLike called on non-object +var target = { prop1: "prop1", prop2: "prop2"}; +var handler = { + ownKeys: function(target) { + return "foo"; + } +}; + +var proxy = new Proxy(target, handler); + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test with invalid property key +var target = {}; +var handler = { + ownKeys: function(target) { + return [5]; + } +}; + +var proxy = new Proxy(target, handler); + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test with duplicated keys +var target = { prop1: "prop1", prop2: "prop2"}; +var handler = { + ownKeys: function(target) { + return ["a", "a", "a"]; + } +}; + +var proxy = new Proxy(target, handler); + +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["a","a","a"]'); + +// test with lots of keys +var keyslist = []; + +var handler = { + ownKeys: function(target) { + for (var idx = 0; idx < 30; idx++) { + keyslist.push("K" + idx); + } + return keyslist; + } +}; + +var proxy = new Proxy(target, handler); +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === JSON.stringify(keyslist)); + +// test when invariants gets violated +var target = { + "target_one": 1 +}; +Object.defineProperty(target, "nonconf", {value: 1, configurable: false}); + +var keys = ["foo"]; + +var handler = { + ownKeys: function(target) { + return keys; + } +}; + +var proxy = new Proxy(target, handler); + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +keys = ["nonconf"]; +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["nonconf"]'); + +Object.preventExtensions(target); +keys = ["foo", "nonconf"]; + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +keys = ["target_one", "nonconf"]; + +assert(JSON.stringify(Object.getOwnPropertyNames(proxy)) === '["target_one","nonconf"]'); + +keys = ["target_one", "nonconf", "foo"]; + +try { + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_prevent_extensions.js b/tests/jerry/es2015/proxy_prevent_extensions.js new file mode 100644 index 00000000..6868125d --- /dev/null +++ b/tests/jerry/es2015/proxy_prevent_extensions.js @@ -0,0 +1,147 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { preventExtensions (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 7.3.14 + Object.freeze(proxy) + assert(false); +} catch (e) { + assert(e === 42); +} + +try { + // 7.3.14 + Object.seal(proxy) + assert(false); +} catch (e) { + assert(e === 42); +} + +// test with no trap +var target = {}; +var handler = {}; +var proxy = new Proxy(target, handler); + +assert(Object.isExtensible(target) === true); +assert(Object.isExtensible(proxy) === true); +Object.preventExtensions(proxy); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); + +// test with "undefined" trap +var target = {}; +var handler = { preventExtensions: null }; +var proxy = new Proxy(target, handler); + +assert(Object.isExtensible(target) === true); +assert(Object.isExtensible(proxy) === true); +Object.preventExtensions(proxy); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); + +// test with invalid trap +var target = {}; +var handler = { preventExtensions: 42 }; +var proxy = new Proxy(target, handler); + +try { + Object.preventExtensions(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test with valid trap +var target = { foo: "bar" }; +var handler = { + preventExtensions(target) { + target.foo = "foo" + Object.preventExtensions(target); + return true; + } +} + +var proxy = new Proxy(target, handler); +assert(Object.isExtensible(target) === true); +assert(Object.isExtensible(proxy) === true); +assert(target.foo === "bar"); +Object.preventExtensions(proxy); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy) === false); +assert(target.foo === "foo"); + +// test when invariants gets violated +var target = {}; +var handler = { + preventExtensions(target) { + return true; + } +} + +var proxy = new Proxy(target, handler); + +try { + Object.preventExtensions(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when target is proxy +var target = {}; +var handler = { + preventExtensions(target) { + Object.preventExtensions(target); + return true; + } +} + +var proxy1 = new Proxy(target, handler); +var proxy2 = new Proxy(proxy1, handler); + +assert(Object.isExtensible(target) === true); +assert(Object.isExtensible(proxy1) === true); +assert(Object.isExtensible(proxy2) === true); +Object.preventExtensions(proxy2); +assert(Object.isExtensible(target) === false); +assert(Object.isExtensible(proxy1) === false); +assert(Object.isExtensible(proxy2) === false); + +var target = {}; +var handler = { + preventExtensions(target) { + return true; + } +} + +var proxy1 = new Proxy(target, handler); +var proxy2 = new Proxy(proxy1, handler); + +try { + Object.preventExtensions(proxy2); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_revocable.js b/tests/jerry/es2015/proxy_revocable.js new file mode 100644 index 00000000..9106be80 --- /dev/null +++ b/tests/jerry/es2015/proxy_revocable.js @@ -0,0 +1,64 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = function () {}; +var handler = { get (name) { + return 5; +}}; + +var revocable = Proxy.revocable(target, handler); + +var proxy = revocable.proxy; + +assert(proxy.a === 5); + +revocable.revoke(); + +try { + proxy.a; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable({}, proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + diff --git a/tests/jerry/es2015/proxy_set.js b/tests/jerry/es2015/proxy_set.js new file mode 100644 index 00000000..96183344 --- /dev/null +++ b/tests/jerry/es2015/proxy_set.js @@ -0,0 +1,140 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// test basic funcionality +function Monster() { + this.eyeCount = 4; +} + +var handler = { + set(obj, prop, value) { + if (prop == 'eyeCount') { + obj[prop] = value; + } else { + obj[prop] = "foo"; + } + } +}; + +var monster = new Monster(); +var proxy = new Proxy(monster, handler); + +proxy.eyeCount = 1; +proxy.foo = "bar"; + +assert(monster.eyeCount === 1); +assert(monster.foo === "foo"); + +var target = { foo: "foo"}; +var handler = { + set: function(obj, prop, value) { + obj[prop] = ""; + } +}; +var proxy = new Proxy(target, handler); + +proxy.foo = 12; +assert(target.foo === ""); + +var properties = ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}]; + +var target = {}; +var handler = {}; +var proxy = new Proxy(target, handler); + +// test when property does not exist on target +/* TODO: Enable these tests when Proxy.[[GetOwnProperty]] has been implemented +for (var p of properties) { + proxy.p = 42; + assert(target.p === 42); +} + +// test when property exists as writable data on target +for (var p of properties) { + Object.defineProperty(target, p, { + writable: true, + value: 24 + }); + + proxy.p = 42; + assert(target.p === 42); +} +*/ +// test when target is a proxy +var target = {}; +var handler = { + set(obj, prop, value) { + obj[prop] = value; + } +}; + +var proxy = new Proxy(target, handler); +var proxy2 = new Proxy(proxy, handler); + +proxy2.prop = "foo"; + +assert(target.prop === "foo"); + +// test when handler is null +var target = {}; +var handler = { + set(obj, prop, value) { + obj[prop] = value; + } +}; + +var revocable = Proxy.revocable (target, {}); +var proxy = revocable.proxy; +revocable.revoke(); + +try { + proxy.prop = 42; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// test when invariants gets violated +var target = {}; +var handler = { set() {return 42} }; +var proxy = new Proxy(target, handler); + +Object.defineProperty(target, "key", { + configurable: false, + writable: false, + value: 0 +}); + +try { + proxy.key = 600; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +Object.defineProperty(target, "key2", { + configurable: false, + set: undefined +}); + +try { + proxy.key2 = 500; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_set_apply_receiver.js b/tests/jerry/es2015/proxy_set_apply_receiver.js new file mode 100644 index 00000000..25d7da13 --- /dev/null +++ b/tests/jerry/es2015/proxy_set_apply_receiver.js @@ -0,0 +1,30 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var get = []; +var p = new Proxy({ + exec: function() { + return null; + } +}, { + get: function(o, k) { + get.push(k); + return o[k]; + } +}); +RegExp.prototype[Symbol.match].call(p); +p.global = true; +RegExp.prototype[Symbol.match].call(p); + +assert(get + '' === "global,exec,global,unicode,exec"); diff --git a/tests/jerry/es2015/proxy_set_prototoype_of.js b/tests/jerry/es2015/proxy_set_prototoype_of.js new file mode 100644 index 00000000..f215bc49 --- /dev/null +++ b/tests/jerry/es2015/proxy_set_prototoype_of.js @@ -0,0 +1,158 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var target = {}; +var handler = { setPrototypeOf (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.2.18 + Object.setPrototypeOf(proxy, {}); + assert(false); +} catch (e) { + assert(e === 42); +} + +// test basic funcionality +var targetProto = {}; +var target = { + foo: false +}; + +var handler = { + setPrototypeOf(target, targetrProto) { + target.foo = true; + return false; + } +}; + +var proxy = new Proxy(target, handler); + +assert(Reflect.setPrototypeOf(proxy, targetProto) === false); +assert(target.foo === true); + +try { + Object.setPrototypeOf(proxy, targetProto); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Object.setPrototypeOf(proxy, undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Object.setPrototypeOf(proxy, 1); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var target = {}; +var handler = {}; +var prototype = []; + +var proxy = new Proxy(target, handler); + +Object.setPrototypeOf(proxy, prototype); +assert(Object.getPrototypeOf(target) === prototype); + +handler.setPrototypeOf = function(target, proto) { + return false; +}; + +try { + Object.setPrototypeOf(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +handler.setPrototypeOf = function(target, proto) { + return undefined; +}; + +try { + Object.setPrototypeOf(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +handler.setPrototypeOf = function(proto) {}; + +try { + Object.setPrototypeOf(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var proto = {}; +Object.setPrototypeOf(proto, Function.prototype); + +var seen_prototype; +var seen_target; + +handler.setPrototypeOf = function(target, proto) { + seen_target = target; + seen_prototype = proto; + return true; +} + +Object.setPrototypeOf(proxy, proto); +assert(target === seen_target); +assert(proto === seen_prototype); + +// test when target is proxy +var target = {}; +var handler = {}; +var handler2 = {}; +var target2 = new Proxy(target, handler2); +var proxy2 = new Proxy(target2, handler); +var prototype = [2,3]; + +Object.setPrototypeOf(proxy2, prototype); + +assert(prototype === Object.getPrototypeOf(target)); + +// test when invariants gets violated +var target = {}; +var handler = { + setPrototypeOf(target, proto) { + Object.setPrototypeOf(target, Function.prototype); + Object.preventExtensions(target); + return true; + } +} + +var proxy = new Proxy(target, handler); + +try { + Object.setPrototypeOf(proxy, Array.prototype); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/reflect-apply.js b/tests/jerry/es2015/reflect-apply.js new file mode 100644 index 00000000..531d997b --- /dev/null +++ b/tests/jerry/es2015/reflect-apply.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (Reflect['apply'](Math.floor, undefined, [1.75]) === 1); +assert (Reflect['apply'](String.fromCharCode, undefined, [104, 101, 108, 108, 111]) === "hello"); +assert (Reflect['apply'](RegExp.prototype.exec, /ab/, ['confabulation']).index === 4); +assert (Reflect['apply'](''.charAt, 'ponies', [3]) === "i"); diff --git a/tests/jerry/es2015/reflect-construct.js b/tests/jerry/es2015/reflect-construct.js new file mode 100644 index 00000000..d37ee2ba --- /dev/null +++ b/tests/jerry/es2015/reflect-construct.js @@ -0,0 +1,80 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Reflect.construct (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Date); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var d = Reflect.construct (Date, [1776, 6, 4]); +assert (d instanceof Date); +assert (d.getFullYear () === 1776); + +function func1 (a, b, c) { + this.sum = a + b + c; +} + +var args = [1, 2, 3]; +var object1 = new func1 (...args); +var object2 = Reflect.construct (func1, args); + +assert (object2.sum === 6); +assert (object1.sum === 6); + +function CatClass () { + this.name = 'Cat'; +} + +function DogClass () { + this.name = 'Dog'; +} + +var obj1 = Reflect.construct (CatClass, args, DogClass); +assert (obj1.name === 'Cat'); +assert (!(obj1 instanceof CatClass)); +assert (obj1 instanceof DogClass); + +try { + Reflect.construct (func1, 5, 5); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (5, 5); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +function func2 () { + throw 5; +} + +try { + Reflect.construct (func2, {}); + assert (false); +} catch (e) { + assert (e === 5); +} diff --git a/tests/jerry/es2015/reflect-define-Property.js b/tests/jerry/es2015/reflect-define-Property.js new file mode 100644 index 00000000..7bca0996 --- /dev/null +++ b/tests/jerry/es2015/reflect-define-Property.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = {}; +assert(Reflect['defineProperty'](obj, 'x', {value: 7}) === true); +assert(Reflect['defineProperty'](obj, 'y', {value: function() {throw 5}}) === true); +try { + Reflect['defineProperty'](obj, {toString: function() {throw new TypeError(5)}}, {value: 8}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/reflect-deleteproperty.js b/tests/jerry/es2015/reflect-deleteproperty.js new file mode 100644 index 00000000..f8fdd49e --- /dev/null +++ b/tests/jerry/es2015/reflect-deleteproperty.js @@ -0,0 +1,61 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var object = { + property: 'Batcat' +}; + +Reflect.deleteProperty (object, 'property'); + +assert (object.property === undefined); + +assert (2 === Reflect.deleteProperty.length); + +try { + Reflect.deleteProperty (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.deleteProperty (42, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.deleteProperty (null, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var target = {bat: 42}; +var a = { [Symbol.toPrimitive]: function() { return 'bat' } }; +var b = { [Symbol.toPrimitive]: function() { throw 'cat' } }; + +assert (Reflect.deleteProperty (target, a)); + +try { + Reflect.deleteProperty (target, b); + assert (false); +} catch (e) { + assert (e === 'cat'); +} diff --git a/tests/jerry/es2015/reflect-get-own-property-description.js b/tests/jerry/es2015/reflect-get-own-property-description.js new file mode 100644 index 00000000..caca9b1c --- /dev/null +++ b/tests/jerry/es2015/reflect-get-own-property-description.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var object1 = { + property1: 42 +}; + +assert(Reflect.getOwnPropertyDescriptor(object1, 'property1').value === 42); +assert(Reflect.getOwnPropertyDescriptor(object1, 'property2') === undefined); +assert(Reflect.getOwnPropertyDescriptor(object1, 'property1').writable === true); diff --git a/tests/jerry/es2015/reflect-get.js b/tests/jerry/es2015/reflect-get.js new file mode 100644 index 00000000..f89700dc --- /dev/null +++ b/tests/jerry/es2015/reflect-get.js @@ -0,0 +1,55 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var object1 = { + x: "Bat", + y: "Cat" +}; + +assert (Reflect.get (object1, 'y') === "Cat"); + +try { + Reflect.get (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (Reflect.get ({}) === undefined); + +var o = {x: 10}; +function foo () { + try { + return Reflect.get (o, "x"); + } catch (e) { + return 1; + } +} + +assert (10 === foo()); + +var c = {}; +function foo2 (a) { + try { + return Reflect.get (c, a); + } catch (e) { + return 1; + } +} + +assert (1 === foo2 ({[Symbol.toPrimitive]() { throw new Error(); }})); diff --git a/tests/jerry/es2015/reflect-getPrototypeOf.js b/tests/jerry/es2015/reflect-getPrototypeOf.js new file mode 100644 index 00000000..140bfce9 --- /dev/null +++ b/tests/jerry/es2015/reflect-getPrototypeOf.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (Reflect['getPrototypeOf']({}) === Object.prototype); +assert (Reflect['getPrototypeOf'](Object.create(null)) === null); +assert (Reflect['getPrototypeOf'](Object.prototype) === null); + +try { + Reflect.getPrototypeOf(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.getPrototypeOf("str"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/reflect-has.js b/tests/jerry/es2015/reflect-has.js new file mode 100644 index 00000000..75a00405 --- /dev/null +++ b/tests/jerry/es2015/reflect-has.js @@ -0,0 +1,64 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +assert (Reflect.has ({x: 0}, 'x') === true); +assert (Reflect.has ({x: 0}, 'y') === false); + +assert (Reflect.has ({x: 0}, 'toString') === true); + +var object = { + prop: 'Apple' +}; + +assert (Reflect.has (object, 'prop') === true); + +assert (2 === Reflect.has.length); + +try { + Reflect.has (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.has (42, 'batcat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.has (null, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var target = {bat: 42}; +var a = { [Symbol.toPrimitive]: function () { return 'bat' } }; +var b = { [Symbol.toPrimitive]: function () { throw 'cat' } }; + +assert (Reflect.has (target, a) === true); + +try { + Reflect.has (target, b); + assert (false); +} catch (e) { + assert (e === 'cat'); +} diff --git a/tests/jerry/es2015/reflect-isextensible.js b/tests/jerry/es2015/reflect-isextensible.js new file mode 100644 index 00000000..a954b663 --- /dev/null +++ b/tests/jerry/es2015/reflect-isextensible.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var empty = {}; +assert (Reflect['isExtensible'](empty) === true); + +Reflect.preventExtensions(empty); +assert (Reflect['isExtensible'](empty) === false); + +var sealed = Object.seal({}); +assert (Reflect['isExtensible'](sealed) === false); diff --git a/tests/jerry/es2015/reflect-own-keys.js b/tests/jerry/es2015/reflect-own-keys.js new file mode 100644 index 00000000..6c89b8fc --- /dev/null +++ b/tests/jerry/es2015/reflect-own-keys.js @@ -0,0 +1,144 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var object1 = { + property1: 42, + property2: 13 +}; + +var array1 = []; + +assert (Reflect.ownKeys (object1)[0] === "property1"); +assert (Reflect.ownKeys (object1)[1] === "property2"); +assert (Reflect.ownKeys (object1).length === 2); + +var obj = { a: 1, b: 2}; +var keys = Reflect.ownKeys (obj); +assert (2 === keys.length); +assert ("a" === keys[0]); +assert ("b" === keys[1]); + +var obj = { a: function(){}, b: function(){} }; +var keys = Reflect.ownKeys (obj); +assert (2 === keys.length); +assert ("a" === keys[0]); +assert ("b" === keys[1]); + +// Check slow case +var obj = { a: 1, b: 2, c: 3 }; +delete obj.b; +var keys = Reflect.ownKeys (obj) +assert (2 === keys.length); +assert ("a" === keys[0]); +assert ("c" === keys[1]); + +// Check that non-enumerable properties are being returned. +var keys = Reflect.ownKeys ([1, 2]); +assert (3 === keys.length); +assert ("0" === keys[0]); +assert ("1" === keys[1]); +assert ("string" === typeof keys[0]); +assert ("string" === typeof keys[1]); +assert ("length" === keys[2]); + +// Check that no proto properties are returned. +var obj = { foo: "foo" }; +var obj2 = { bar: "bar" }; +Object.setPrototypeOf (obj, obj2) +keys = Reflect.ownKeys (obj); +assert (1 === keys.length); +assert ("foo" === keys[0]); + +// Check that getter properties are returned. +var obj = {}; +Object.defineProperty (obj, "getter", function() {}) +//obj.__defineGetter__("getter", function() {}); +keys = Reflect.ownKeys (obj); +assert (1 === keys.length); +assert ("getter" === keys[0]); + +// Check that implementation does not access Array.prototype. +var savedConcat = Array.prototype.concat; +Array.prototype.concat = function() { return []; } +keys = Reflect.ownKeys ({0: 'foo', bar: 'baz'}); +assert (2 === keys.length); +assert ('0' === keys[0]); +assert ('bar'=== keys[1]); +assert (Array.prototype === Object.getPrototypeOf (keys)) +Array.prototype.concat = savedConcat; + +try { + Reflect.ownKeys (4); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.ownKeys("cica"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.ownKeys(true); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (Reflect.ownKeys (Object (4)) !== []) +assert (Reflect.ownKeys (Object ("foo")) !== ["0", "1", "2", "length"]) +assert (Reflect.ownKeys (Object (4)) !== []); +assert (Reflect.ownKeys (Object ("foo")) !== [0, 1, 2, "length"]); +assert (Reflect.ownKeys (Object (true)) !== []); + +var id = Symbol("my kitten"); +var user = { + name: "Bob", + age: 30, + [id]: "is batcat" +} + +assert (Reflect.ownKeys (user)[0] === "name"); +assert (Reflect.ownKeys (user)[1] === "age"); +assert (Reflect.ownKeys (user)[2] === id); diff --git a/tests/jerry/es2015/reflect-preventextensions.js b/tests/jerry/es2015/reflect-preventextensions.js new file mode 100644 index 00000000..5af6589e --- /dev/null +++ b/tests/jerry/es2015/reflect-preventextensions.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var object1 = {}; + +assert (Reflect['isExtensible'](object1) === true); + +Reflect.preventExtensions(object1); +assert (Reflect['isExtensible'](object1) === false); diff --git a/tests/jerry/es2015/reflect-set.js b/tests/jerry/es2015/reflect-set.js new file mode 100644 index 00000000..e3d80537 --- /dev/null +++ b/tests/jerry/es2015/reflect-set.js @@ -0,0 +1,68 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var object = {}; +Reflect.set (object, 'property', 'batcat'); + +assert (object.property === 'batcat'); + +var array = ['cat', 'cat', 'cat']; +Reflect.set (array, 2, 'bat'); + +assert (array[2] === 'bat'); + +assert (3 === Reflect.set.length); + +try { + Reflect.set (); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.set (42, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.set (null, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var target = {}; +var a = { [Symbol.toPrimitive]: function () { return 'bat' } }; +var b = { [Symbol.toPrimitive]: function () { throw 'cat' } }; +assert (Reflect.set (target, a, 42) === true); +assert (42 === target.bat); + +try { + Reflect.set (null, 'bat'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var y = []; +Object.defineProperty (y, 0, {value: 42, configurable: false}); +assert (Reflect.set (y, 'length', 0) === false); +assert (Reflect.set (y, 'length', 2) === true); diff --git a/tests/jerry/es2015/reflect-setPrototypeOf.js b/tests/jerry/es2015/reflect-setPrototypeOf.js new file mode 100644 index 00000000..c3e07a88 --- /dev/null +++ b/tests/jerry/es2015/reflect-setPrototypeOf.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var object1 = {}; + +assert(Reflect.setPrototypeOf(object1, Object.prototype) === true); +assert(Reflect.setPrototypeOf(object1, null) === true); + +var object2 = {}; +assert(Reflect.setPrototypeOf(Object.freeze(object2), null) === false); diff --git a/tests/jerry/es2015/regexp-accessors-descriptors.js b/tests/jerry/es2015/regexp-accessors-descriptors.js new file mode 100644 index 00000000..46ee2968 --- /dev/null +++ b/tests/jerry/es2015/regexp-accessors-descriptors.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var accessors = [ 'flags', 'global', 'ignoreCase', 'multiline', 'source', 'sticky', 'unicode' ] + +accessors.forEach(function(attr) { + var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, attr); + assert(typeof desc.get === 'function') + assert(desc.set === undefined) + assert(desc.enumerable === false) + assert(desc.configurable === true) +}); diff --git a/tests/jerry/es2015/regexp-construct.js b/tests/jerry/es2015/regexp-construct.js new file mode 100644 index 00000000..0c0d8634 --- /dev/null +++ b/tests/jerry/es2015/regexp-construct.js @@ -0,0 +1,57 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var r = RegExp ("a","gim"); +var r2 = RegExp (r,"gim"); +var r3 = RegExp (r); + +assert(r2.source === 'a'); +assert(r2.global === true); +assert(r2.ignoreCase === true); +assert(r2.multiline === true); + +assert(r3.source === 'a'); +assert(r3.global === true); +assert(r3.ignoreCase === true); +assert(r3.multiline === true); + +var obj = { get source() { throw 5 }, [Symbol.match] : true } + +try { + new RegExp (obj); + assert(false) +} catch (e) { + assert(e === 5); +} + +r = new RegExp ("a","gimuy"); +assert (r.global === true); +assert (r.ignoreCase === true); +assert (r.multiline === true); +assert (r.unicode === true); +assert (r.sticky === true); + +try { + new RegExp ("a", "uu"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp ("a", "yy"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regexp-flags.js b/tests/jerry/es2015/regexp-flags.js new file mode 100644 index 00000000..df66a2d6 --- /dev/null +++ b/tests/jerry/es2015/regexp-flags.js @@ -0,0 +1,72 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var r = /[𐲡-𐲱𐲟]/u; + +var m = r.exec("𐲬"); +assert(m !== null); +assert(m[0] === "𐲬"); + +r = /[𐲡E]/ug; +assert (r.exec("E𐲡E")[0] === 'E'); +assert (r.exec("E𐲡E")[0] === '𐲡'); +assert (r.exec("E𐲡E")[0] === 'E'); + +try { + eval("/[𐲡-𐲱𐲟]/"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/\udc96/.exec("\ud803\udc96")[0] === '\udc96'); +assert (/\udc96/u.exec("\ud803\udc96") === null); +assert (/\udc96/u.exec("\udc96")[0] === '\udc96'); + +assert (/\ud803/.exec("\ud803\udc96")[0] === '\ud803'); +assert (/\ud803/u.exec("\ud803\udc96") === null); +assert (/\ud803/u.exec("\ud803")[0] === '\ud803'); + +assert (/./u.exec("\ud803\udc96")[0] === '𐲖'); +assert (/./.exec("\ud803\udc96")[0] === '\ud803'); +assert (/./u.exec("\ud803\ud803")[0] === '\ud803'); +assert (/./u.exec("\udc96\udc96")[0] === '\udc96'); +assert (/./u.exec("\ud803")[0] === '\ud803'); + +var r = /abc/y; +m = r.exec ("strabcstr"); +assert (m === null); + +r.lastIndex = 3; +m = r.exec ("strabcstr"); +assert (m[0] === "abc"); +assert (r.lastIndex === 6); + +m = r.exec ("strabcstr"); +assert (m === null); +assert (r.lastIndex === 0); + +var r = /abc/yg; +m = r.exec ("strabcstr"); +assert (m === null); + +try { + RegExp.prototype.flags; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var flagsProp = Object.getOwnPropertyDescriptor (RegExp.prototype, "flags"); +assert(flagsProp.get.call({}) === ''); diff --git a/tests/jerry/es2015/regexp-lastindex.js b/tests/jerry/es2015/regexp-lastindex.js index 94af81d0..0e7521f8 100644 --- a/tests/jerry/es2015/regexp-lastindex.js +++ b/tests/jerry/es2015/regexp-lastindex.js @@ -18,3 +18,5 @@ result = t.exec("abc abc"); assert(result[0] === "abc"); assert(result.index === 0); assert(t.lastIndex === 3); + +assert(RegExp.prototype.lastIndex === undefined) diff --git a/tests/jerry/es2015/regexp-new-target.js b/tests/jerry/es2015/regexp-new-target.js new file mode 100644 index 00000000..2a5bc64d --- /dev/null +++ b/tests/jerry/es2015/regexp-new-target.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function F(){} +var obj = Reflect.construct(RegExp, ["baz","g"], F); +assert(RegExp.prototype.exec.call(obj, "foobarbaz")[0] === "baz") +assert(obj.lastIndex === 9) +assert(obj instanceof F); diff --git a/tests/jerry/es2015/regexp-prototype-match.js b/tests/jerry/es2015/regexp-prototype-match.js new file mode 100644 index 00000000..c95126e4 --- /dev/null +++ b/tests/jerry/es2015/regexp-prototype-match.js @@ -0,0 +1,74 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var regexp = /[0-9]+/g; +var str = '2016-01-02'; +var num = 12131233; + +// Test with string input +var result = regexp[Symbol.match](str); +assert(result.toString() === "2016,01,02"); + +regexp = /[0-5]+/g; +result = regexp[Symbol.match](str); +assert(result.toString() === "201,01,02"); + +regexp = /[0-1]+/g; +result = regexp[Symbol.match](str); +assert(result.toString() === "01,01,0"); + +regexp = /([0-9]+)-([0-9]+)-([0-9]+)/g +result = regexp[Symbol.match](str); +assert(result.toString() === "2016-01-02"); + +// Test with number input +regexp = /[0-9]+/g; +result = regexp[Symbol.match](num); +assert(result.toString() === "12131233"); + +// Test with empty string +result = regexp[Symbol.match](''); +assert(result === null); + +// Test with undefined +result = regexp[Symbol.match](undefined); +assert(result === null); + +// Test when input is not a regexp +regexp = 12; + +try { + result = regexp[Symbol.match](str); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// Test with RegExp subclass where we override the [Symbol.match] function +class RegExpSub extends RegExp { + [Symbol.match](str) { + var result = RegExp.prototype[Symbol.match].call(this, str); + if (result) { + return "VALID"; + } + else + { + return "INVALID"; + } + } +} + +var regexp1 = new RegExpSub('([0-9]+)-([0-9]+)-([0-9]+)'); +result = regexp1[Symbol.match](str); +assert(result === "VALID"); diff --git a/tests/jerry/es2015/regexp-prototype-source.js b/tests/jerry/es2015/regexp-prototype-source.js new file mode 100644 index 00000000..70927961 --- /dev/null +++ b/tests/jerry/es2015/regexp-prototype-source.js @@ -0,0 +1,55 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var regexp = /fooBar/ig; +assert(regexp.source === 'fooBar'); + +assert(new RegExp().source === '(?:)'); + +assert(new RegExp('/foo/').source === '\\/foo\\/'); +assert(new RegExp('/foo/').source.length === 7); + +assert(new RegExp('bar', 'ug').source === 'bar'); + +assert(new RegExp('/\?/').source === '\\/?\\/'); +assert(new RegExp('/\?/').source.length === 5); + +assert(new RegExp('\n').source === '\\n'); + +assert(new RegExp('\r').source === '\\r'); + +assert(new RegExp('\u2028').source === '\\u2028'); + +assert(new RegExp('\u2029').source === '\\u2029'); + +assert(new RegExp('/\n/').source === '\\/\\n\\/'); +assert(new RegExp('/\n/').source.length === 6); + +assert(new RegExp(/\/\//).source === '\\/\\/'); +assert(new RegExp(/\?\//g).source === '\\?\\/'); + +try { + RegExp.prototype.source; + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var sourceProp = Object.getOwnPropertyDescriptor (RegExp.prototype, "source"); +try { + sourceProp.get.call({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regexp-prototype-test.js b/tests/jerry/es2015/regexp-prototype-test.js new file mode 100644 index 00000000..b1b4871b --- /dev/null +++ b/tests/jerry/es2015/regexp-prototype-test.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = 'something interesting'; +var regexp = new RegExp('o*'); +Object.defineProperty(regexp, 'exec', { 'get': function () {throw 42}}); + +try { + regexp.test(str); + assert(false); +} catch (e) { + assert(e === 42); +} diff --git a/tests/jerry/es2015/regexp-routines.js b/tests/jerry/es2015/regexp-routines.js new file mode 100644 index 00000000..7a750ba1 --- /dev/null +++ b/tests/jerry/es2015/regexp-routines.js @@ -0,0 +1,146 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var r = new RegExp('a', 'gimuy'); +assert (r.flags === 'gimuy'); +assert (r.toString() === '/a/gimuy'); + +try { + Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var o = { + global: true, + unicode: true, + sticky: true, + source: "str" +} + +Object.defineProperty(o, 'flags', Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags')); +assert(o.flags === "guy"); +assert (RegExp.prototype.toString.call (o) === "/str/guy"); + +Object.defineProperty(o, 'multiline', { 'get': function () {throw "abrupt flag get"; }}); +try { + o.flags + assert (false); +} catch (e) { + assert (e === "abrupt flag get"); +} + +try { + RegExp.prototype.toString.call(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (RegExp.prototype.toString.call({}) === "/undefined/undefined"); + +var o = {}; +Object.defineProperty (o, 'source', { 'get' : function () {throw "abrupt source get"; } }); +try { + RegExp.prototype.toString.call(o); + assert (false); +} catch (e) { + assert (e === "abrupt source get"); +} + +var o = {source: {toString: function() {throw "abrupt source toString";}}}; +try { + RegExp.prototype.toString.call(o); + assert (false); +} catch (e) { + assert (e === "abrupt source toString"); +} + +var o = {source: "str"}; +Object.defineProperty (o, 'flags', { 'get' : function () {throw "abrupt flags get"; } }); +try { + RegExp.prototype.toString.call(o); + assert (false); +} catch (e) { + assert (e === "abrupt flags get"); +} + +var o = {source: "str", flags: {toString: function() {throw "abrupt flags toString";}}}; +try { + RegExp.prototype.toString.call(o); + assert (false); +} catch (e) { + assert (e === "abrupt flags toString"); +} + +var o = { + global: true, + source: "str" +} + +Object.defineProperty(o, 'unicode', { 'get': function () {throw "abrupt unicode get"; }}); +try { + RegExp.prototype[Symbol.match].call(o, "str"); + assert (false); +} catch (e) { + assert (e === "abrupt unicode get"); +} + +assert ("str𐲡fgh".replace(/(?:)/gu, "x") === 'xsxtxrx𐲡xfxgxhx'); +assert ("str𐲡fgh".replace(/(?:)/g, "x") === 'xsxtxrx\ud803x\udca1xfxgxhx'); + +r = /(?:)/gu; +/* Disable fast path. */ +r.exec = function (s) { return RegExp.prototype.exec.call(this, s); }; + +assert ("str𐲡fgh".replace(r, "x") === 'xsxtxrx𐲡xfxgxhx'); +Object.defineProperty(r, 'unicode', {value: false}); +assert ("str𐲡fgh".replace(r, "x") === 'xsxtxrx\ud803x\udca1xfxgxhx'); + +r = /(?:)/gu; +assert (RegExp.prototype[Symbol.match].call(r, "str𐲡fgh").length === 8); +Object.defineProperty(r, 'unicode', {value: false}); +assert (RegExp.prototype[Symbol.match].call(r, "str𐲡fgh").length === 9); + +r = /(?:)/gy; +r.lastIndex = 2; +assert ("asd".replace(r, "x") === "xaxsxdx"); +assert (r.lastIndex === 0); + +r.lastIndex = 5; +assert ("asd".replace(r, "x") === "xaxsxdx"); +assert (r.lastIndex === 0); + +r = /(?:)/y; +r.lastIndex = 2; +assert ("asd".replace(r, "x") === "asxd"); +assert (r.lastIndex === 2); + +r.lastIndex = 5; +assert ("asd".replace(r, "x") === "asd"); +assert (r.lastIndex === 0); + +r.lastIndex = 2; +/* Disable fast path. */ +r.exec = function (s) { return RegExp.prototype.exec.call(this, s); }; +assert ("asd".replace(r, "x") === "asxd"); +assert (r.lastIndex === 2); + +r.lastIndex = 5; +assert ("asd".replace(r, "x") === "asd"); +assert (r.lastIndex === 0); + +assert (RegExp.prototype[Symbol.match].call(/a/y, "aaa").length === 1); +assert (RegExp.prototype[Symbol.match].call(/a/gy, "aaa").length === 3); diff --git a/tests/jerry/es2015/regexp-unicode.js b/tests/jerry/es2015/regexp-unicode.js new file mode 100644 index 00000000..60ac33e8 --- /dev/null +++ b/tests/jerry/es2015/regexp-unicode.js @@ -0,0 +1,361 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var result = /\0/.exec("\u0000"); +assert (result !== null); +assert (result[0] === "\u0000"); + +result = /\0/u.exec("\u0000"); +assert (result !== null); +assert (result[0] === "\u0000"); + +result = /\000/.exec("\u0000"); +assert (result !== null); +assert (result[0] === "\u0000"); + +try { + new RegExp("\\000", 'u').exec("\u0000"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\0000/.exec("\u0000\u0030"); +assert (result !== null); +assert (result[0] === "\u0000\u0030"); + +result = /\377/.exec("\u00ff"); +assert (result !== null); +assert (result[0] === "\u00ff"); + +try { + new RegExp("\\377", 'u').exec("\u00ff"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\3777/.exec("\u00ff\u0037"); +assert (result !== null); +assert (result[0] === "\u00ff\u0037"); + +try { + new RegExp("\\3777", 'u').exec("\u00ff\u0037"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\400/.exec("\u0020\u0030"); +assert (result !== null); +assert (result[0] === "\u0020\u0030"); + +try { + new RegExp("\\400", 'u').exec("\u0020\u0030"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /(\1)/.exec("\u0001"); +assert (result !== null); +assert (result[0].length === 0); + +result = /(\1)/u.exec("\u0001"); +assert (result !== null); +assert (result[0].length === 0); + +result = /(\2)/.exec("\u0002"); +assert (result !== null); +assert (result[0] === '\u0002'); + +try { + new RegExp("(\\2)", 'u').exec("\u0002"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\8/.exec("\u0038"); +assert (result !== null); +assert (result[0] === '8'); + +result = /\99/.exec("\u0039\u0039"); +assert (result !== null); +assert (result[0] === "99"); + +// CharClassEscape +assert (/\d+/.exec("123")[0] === "123"); +assert (/\D+/.exec("abc")[0] === "abc"); +assert (/\s+/.exec(" ")[0] === " "); +assert (/\S+/.exec("abc")[0] === "abc"); +assert (/\w+/.exec("abc")[0] === "abc"); +assert (/\W+/.exec("|||")[0] === "|||"); +assert (/\d+/u.exec("123")[0] === "123"); +assert (/\D+/u.exec("abc")[0] === "abc"); +assert (/\s+/u.exec(" ")[0] === " "); +assert (/\S+/u.exec("abc")[0] === "abc"); +assert (/\w+/u.exec("abc")[0] === "abc"); +assert (/\W+/u.exec("|||")[0] === "|||"); + +assert (/\d+/u.exec("\u{10CAF}") === null); +assert (/\D+/u.exec("\u{10CAF}")[0] === "\u{10CAF}"); +assert (/\s+/u.exec("\u{10CAF}") === null); +assert (/\S+/u.exec("\u{10CAF}")[0] === "\u{10CAF}"); +assert (/\w+/u.exec("\u{10CAF}") === null); +assert (/\W+/u.exec("\u{10CAF}")[0] === "\u{10CAF}"); + +result = /\xz/.exec("xz"); +assert (result !== null); +assert (result[0] === "xz"); + +try { + new RegExp("\\xz", "u").exec("xz"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\c/.exec("\\c"); +assert (result !== null); +assert (result[0] === "\\c"); + +try { + new RegExp("\\c", 'u').exec("\\c") + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +result = /\c1/.exec("\\c1"); +assert (result !== null); +assert (result[0] === "\\c1"); + +try { + new RegExp("\\c1", 'u').exec("\\c1"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("^+"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("$+"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("\\b+"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("\\B+"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/[\b]/.exec("\u0008")[0] === "\u0008"); +assert (/[\b]/u.exec("\u0008")[0] === "\u0008"); +assert (/[\B]/.exec("\u0042")[0] === "\u0042"); + +try { + new RegExp ("[\\B]", 'u').exec("\u0042"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/[\c1]/.exec("\u0011")[0] === "\u0011"); +assert (/[\c_]/.exec("\u001f")[0] === "\u001f"); +assert (/[\c]/.exec("\\")[0] === "\\"); +assert (/[\c]/.exec("c")[0] === "c"); + +try { + new RegExp("[\\c1]", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("[\\c]", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("[\\c_]", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/{{1,2}/.exec("{{")[0] === "{{"); + +try { + new RegExp("{{1,2}", 'u').exec("{{"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/a{1,2/.exec("a{1,2")[0] === "a{1,2"); + +try { + new RegExp("a{1,2", 'u').exec("a{1,2"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/\u017f/i.exec("s") === null); +assert (/\u017f/ui.exec("s")[0] === "s"); + +assert (/𐲯/.exec("𐲯")[0] === "𐲯"); +assert (/𐲯/u.exec("𐲯")[0] === "𐲯"); +assert (/𐲯*?/.exec("𐲯")[0] === "\ud803"); +assert (/𐲯*?/u.exec("𐲯")[0] === ""); +assert (/𐲯+/.exec("𐲯𐲯𐲯")[0] === "𐲯"); +assert (/𐲯+/u.exec("𐲯𐲯𐲯")[0] === "𐲯𐲯𐲯"); + +assert (/\ud803\udc96*?/.exec("𐲖")[0] === '\ud803'); +assert (/\ud803\udc96*?/u.exec("𐲖")[0] === ''); +assert (/\ud803\udc96+/.exec("𐲖𐲖𐲖")[0] === '𐲖'); +assert (/\ud803\udc96+/u.exec("𐲖𐲖𐲖")[0] === '𐲖𐲖𐲖'); + +assert (/.*𐲗𐲘/u.exec("𐲓𐲔𐲕𐲖𐲗𐲘")[0] === '𐲓𐲔𐲕𐲖𐲗𐲘'); + +assert (/[\u{10000}]/.exec("\u{10000}") === null); +assert (/[\u{10000}]/.exec("{")[0] === "{"); +assert (/[^\u{10000}]/.exec("\u{10000}")[0] === "\ud800"); +assert (/[^\u{10000}]/.exec("{") === null); + +assert (/[\uffff]/.exec("\uffff")[0] === "\uffff"); +assert (/[^\uffff]/.exec("\uffff") === null); + +assert (/[\u{10000}]/u.exec("\u{10000}")[0] === "\u{10000}"); +assert (/[\u{10000}]/u.exec("{") === null); +assert (/[^\u{10000}]/u.exec("\u{10000}") === null); +assert (/[^\u{10000}]/u.exec("{")[0] === "{"); + +assert (/[\uffff]/u.exec("\uffff")[0] === "\uffff"); +assert (/[^\uffff]/u.exec("\uffff") === null); + +assert (/a{4294967296,4294967297}/.exec("aaaa") === null); +assert (/a{4294967294,4294967295}/.exec("aaaa") === null); +assert (/a{0000000000000000001,0000000000000000002}/u.exec("aaaa")[0] === 'aa'); +assert (/(\4294967297)/.exec("\4294967297")[0] === "\4294967297"); +assert (/(\1)/u.exec("aaaa")[0] === ""); + +try { + new RegExp("a{4294967295,4294967294}", ''); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/[\d-\s]/.exec("-")[0] === "-"); +assert (/[0-\s]/.exec("-")[0] === "-"); +assert (/[\d-0]/.exec("-")[0] === "-"); + +try { + new RegExp("[\\d-\\s]", 'u').exec("-"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("[0-\\s]", 'u').exec("-"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("[\\d-0]", 'u').exec("-"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/[-]/.exec("-")[0] === "-"); +assert (/[-]/u.exec("-")[0] === "-"); +assert (/[--]/.exec("-")[0] === "-"); +assert (/[--]/u.exec("-")[0] === "-"); + +assert (/}/.exec("}")[0] === "}"); +assert (/\}/u.exec("}")[0] === "}"); + +try { + new RegExp("}", 'u').exec("}"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/]/.exec("]")[0] === "]"); +assert (/\]/u.exec("]")[0] === "]"); + +try { + new RegExp("]", 'u').exec("]"); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +assert (/(?=)*/.exec("")[0] === ""); +assert (/(?=)+/.exec("")[0] === ""); +assert (/(?=){1,2}/.exec("")[0] === ""); + +try { + new RegExp("(?=)*", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("(?=)+", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("(?=){1,2}", 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} + +try { + new RegExp("(?=){2,1}", ''); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/fail/regression-test-issue-2544.js b/tests/jerry/es2015/regression-test-issue-2544.js similarity index 79% rename from tests/jerry/fail/regression-test-issue-2544.js rename to tests/jerry/es2015/regression-test-issue-2544.js index 946751fc..38054ee5 100644 --- a/tests/jerry/fail/regression-test-issue-2544.js +++ b/tests/jerry/es2015/regression-test-issue-2544.js @@ -13,4 +13,9 @@ // limitations under the License. Object.defineProperty(Array.prototype, 0, { get : function () { throw $; } }); -Promise.race([ , this]).then(Error); +var global_err = undefined; +Promise.race([ , this]).then(Error).catch(function(err) { global_err = err; }); + +function __checkAsync() { + assert(global_err instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-2825.js b/tests/jerry/es2015/regression-test-issue-2825.js index 9b9ff6df..31530f0e 100644 --- a/tests/jerry/es2015/regression-test-issue-2825.js +++ b/tests/jerry/es2015/regression-test-issue-2825.js @@ -25,9 +25,9 @@ var B = class extends f { } C = class extends B { g() { - () => { + (() => { called = true; - }() + })() } } D = class extends C { diff --git a/tests/jerry/es2015/regression-test-issue-2891.js b/tests/jerry/es2015/regression-test-issue-2891.js new file mode 100644 index 00000000..c63d2513 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-2891.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +function f (name){ + delete this.keywords[name]; + assert (false); +} + +try { + f ("jerry"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3070.js b/tests/jerry/es2015/regression-test-issue-3070.js new file mode 100644 index 00000000..192d5459 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3070.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var r = new RegExp("([X]{6}|.*)", "g"); +var s = "a"; +s.replace(r, () => r.compile("[PqaCZlWQUT]{0}", "m")); diff --git a/tests/jerry/es2015/regression-test-issue-3084.js b/tests/jerry/es2015/regression-test-issue-3084.js index 510225f1..8ed21de4 100644 --- a/tests/jerry/es2015/regression-test-issue-3084.js +++ b/tests/jerry/es2015/regression-test-issue-3084.js @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -assert(String.prototype.repeat(1.1) === ""); +assert("".repeat(1.1) === ""); diff --git a/tests/jerry/es2015/regression-test-issue-3222.js b/tests/jerry/es2015/regression-test-issue-3222.js new file mode 100644 index 00000000..d9f81db6 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3222.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var v0 = (Array((((new String).split().constructor)(Symbol( ))))) + +try { + var $ = (new Uint8ClampedArray).set((new ((new constructor).constructor(this).Uint32Array)), v0) + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3237.js b/tests/jerry/es2015/regression-test-issue-3237.js new file mode 100644 index 00000000..06248f36 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3237.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var arrayBufferVar1 = new ArrayBuffer(12, 8); +var arrayVar1 = new Uint8Array(arrayBufferVar1, 9); +arrayVar1.lastIndexOf(15, -Math.LOG10E); diff --git a/tests/jerry/es2015/regression-test-issue-3243.js b/tests/jerry/es2015/regression-test-issue-3243.js new file mode 100644 index 00000000..7a44995f --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3243.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + (new Int8Array((new ArrayBuffer()), 1, Infinity)).reverse() + assert(false); +} catch (e) { + assert (e instanceof RangeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3250.js b/tests/jerry/es2015/regression-test-issue-3250.js new file mode 100644 index 00000000..abe121d8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3250.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var arrowFn = () => { }; +assert (arrowFn.prototype === undefined); diff --git a/tests/jerry/es2015/regression-test-issue-3252.js b/tests/jerry/es2015/regression-test-issue-3252.js new file mode 100644 index 00000000..28fded4f --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3252.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + function NoParent ( ) { } + Number.constructor( NoParent, Symbol.hasInstance, { }) + assert (false) +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3262.js b/tests/jerry/es2015/regression-test-issue-3262.js new file mode 100644 index 00000000..a154b651 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3262.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert ((new Float64Array(Object('foobar').split())).every(function (p_0) { return p_0 }) === false); diff --git a/tests/jerry/es2015/regression-test-issue-3267.js b/tests/jerry/es2015/regression-test-issue-3267.js new file mode 100644 index 00000000..2f0f92b4 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3267.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var hasProp = $ => { } +Object.preventExtensions(hasProp); +assert (Object.isSealed(hasProp) === false); + +var keys = Object.getOwnPropertyNames(hasProp); +assert (keys.length === 1); +assert (keys[0] === "length"); + diff --git a/tests/jerry/es2015/regression-test-issue-3298.js b/tests/jerry/es2015/regression-test-issue-3298.js new file mode 100644 index 00000000..57e1227b --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3298.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var $ = { $: function ( $) { } }; + +function g ( b = (local = $) ) { + var o ; + function f ( ) { return this === o } +} + +g () diff --git a/tests/jerry/es2015/regression-test-issue-3306.js b/tests/jerry/es2015/regression-test-issue-3306.js new file mode 100644 index 00000000..367e36e5 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3306.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + typeof(a); + let a; + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3348.js b/tests/jerry/es2015/regression-test-issue-3348.js new file mode 100644 index 00000000..1504193e --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3348.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + [$, this.$] = [ ]; +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3151-class.js b/tests/jerry/es2015/regression-test-issue-3355.js similarity index 96% rename from tests/jerry/es2015/regression-test-issue-3151-class.js rename to tests/jerry/es2015/regression-test-issue-3355.js index 4e864480..dc847e8f 100644 --- a/tests/jerry/es2015/regression-test-issue-3151-class.js +++ b/tests/jerry/es2015/regression-test-issue-3355.js @@ -12,4 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -do class $ { } while (0); +var $ = $ => { } +/ / diff --git a/tests/jerry/es2015/regression-test-issue-3356.js b/tests/jerry/es2015/regression-test-issue-3356.js new file mode 100644 index 00000000..6ea607fd --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3356.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var alpha = []; +var $ = {[$] : $} +obj = {} +obj[ Symbol.isConcatSpreadable ] = "\O" +alpha.concat(obj) diff --git a/tests/jerry/es2015/regression-test-issue-3360.js b/tests/jerry/es2015/regression-test-issue-3360.js new file mode 100644 index 00000000..bea34b89 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3360.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function $ (b = [ ].$) { }; +assert ($() === undefined); diff --git a/tests/jerry/es2015/regression-test-issue-3361.js b/tests/jerry/es2015/regression-test-issue-3361.js new file mode 100644 index 00000000..38dc1e92 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3361.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var fakeArray = { [ Symbol ] : 0}; +fakeArray[ Symbol.isConcatSpreadable ] = 2.756; +[].concat(fakeArray); diff --git a/tests/jerry/es2015/regression-test-issue-3363.js b/tests/jerry/es2015/regression-test-issue-3363.js new file mode 100644 index 00000000..71a327b4 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3363.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (typeof x === 'undefined'); +let { t: [ { a: b } ] } = { t: [ { a: 'a' } ] }; +assert (b === 'a'); diff --git a/tests/jerry/es2015/regression-test-issue-3364.js b/tests/jerry/es2015/regression-test-issue-3364.js new file mode 100644 index 00000000..1657ee78 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3364.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(eval(...[0]) === 0); diff --git a/tests/jerry/es2015/regression-test-issue-3376.js b/tests/jerry/es2015/regression-test-issue-3376.js new file mode 100644 index 00000000..dc070451 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3376.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +(function () { + new Promise(isFinite.toString) +})(); + +(function () { + [ ] = [ ] +}) +({}) diff --git a/tests/jerry/es2015/regression-test-issue-3381.js b/tests/jerry/es2015/regression-test-issue-3381.js new file mode 100644 index 00000000..732d7b8b --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3381.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +a: function f() {return true;} + +assert (f() === true); diff --git a/tests/jerry/es2015/regression-test-issue-3383.js b/tests/jerry/es2015/regression-test-issue-3383.js new file mode 100644 index 00000000..028d8761 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3383.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (typeof Function('[]', 0) == "function"); diff --git a/tests/jerry/es2015/regression-test-issue-3390.js b/tests/jerry/es2015/regression-test-issue-3390.js new file mode 100644 index 00000000..f1291a7a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3390.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = Promise.resolve( 'a' ); +var b = Promise.reject( 'b' ); +Promise.race( [ a , b ] ).then ( function ( x ) { var a , b ; [ a , b ] = [ 1 , 2 ]; String( a === 1 ); } , function ( x ) { } ); +Promise.race( [ b , a ] ).then ( function ( x ) { String ( false ) ;}, function ( x ) { } ); +Promise.race( [ , b , a ] ).then ( function ( x ) { String ( x === undefined ) ; }, function ( x ) { String ( false ); } ); +Promise.race( a ).then ( function ( x ) { String ( false ); }, function ( x ) { String ( x.name === "TypeError" ); } ); diff --git a/tests/jerry/es2015/regression-test-issue-3396.js b/tests/jerry/es2015/regression-test-issue-3396.js new file mode 100644 index 00000000..c40e6f0c --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3396.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function i($, b = (eval("var x"))) { + function x() {} + eval() +} +i() diff --git a/tests/jerry/es2015/regression-test-issue-3408.js b/tests/jerry/es2015/regression-test-issue-3408.js new file mode 100644 index 00000000..0398d7aa --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3408.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var array = [0, 0, obj, 0, 0]; +array.copyWithin(NaN, 67, 0); +var obj diff --git a/tests/jerry/es2015/regression-test-issue-3409.js b/tests/jerry/es2015/regression-test-issue-3409.js new file mode 100644 index 00000000..5704045d --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3409.js @@ -0,0 +1,28 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a; +Promise.race([a]).then(function() {[] = []}); +Promise.race().then(function() {}, function() { throw "'this' had incorrect value!"}) + +var a = Promise.resolve('a'); +var b = Promise.reject('b'); +Promise.race([a, b]).then(function(x) { + var [a, b] = [1, 2]; +}, function(x) {}); +Promise.race([b, a]).then(function(x) {}, function(x) {}); +Promise.race([, b, a]).then(function(x) {}, function(x) {}); +Promise.race(a).then(function(x) {}, function(x) { + String(i.name === "TypeError"); +}); diff --git a/tests/jerry/es2015/regression-test-issue-3411.js b/tests/jerry/es2015/regression-test-issue-3411.js new file mode 100644 index 00000000..e7c04a3a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3411.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a; +Promise.race([a]).then(function() {[] = []}); +Promise.race().then(function() {}, function() { throw "'this' had incorrect value!"}) diff --git a/tests/jerry/es2015/regression-test-issue-3419.js b/tests/jerry/es2015/regression-test-issue-3419.js new file mode 100644 index 00000000..ed846f37 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3419.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval ('Function("[]", 0)()'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3420.js b/tests/jerry/es2015/regression-test-issue-3420.js new file mode 100644 index 00000000..6612843b --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3420.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Array.from.call(String, $); + function $() {} + assert(fasle); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3421.js b/tests/jerry/es2015/regression-test-issue-3421.js new file mode 100644 index 00000000..4046ca24 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3421.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +for (let [] of [[],[]]); diff --git a/tests/jerry/es2015/regression-test-issue-3422.js b/tests/jerry/es2015/regression-test-issue-3422.js new file mode 100644 index 00000000..d93f23ff --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3422.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (typeof RegExp('{}') === "object"); +let {t: []} = {t: []}; diff --git a/tests/jerry/es2015/regression-test-issue-3431.js b/tests/jerry/es2015/regression-test-issue-3431.js new file mode 100644 index 00000000..a32b951c --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3431.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval ('function g({["y"]: []}) {}; g({xy: {}})'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + eval ('function g([], {}, [], {}) {}; g()'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3434.js b/tests/jerry/es2015/regression-test-issue-3434.js new file mode 100644 index 00000000..be0d90ff --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3434.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function g({ + ["y"]: { + get = 5 + } +}) {} diff --git a/tests/jerry/es2015/regression-test-issue-3437.js b/tests/jerry/es2015/regression-test-issue-3437.js new file mode 100644 index 00000000..e7cce474 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3437.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +[...RegExp.prototype.compile] = ([]); + +assert(RegExp.prototype.compile.length === 0); diff --git a/tests/jerry/es2015/regression-test-issue-3454.js b/tests/jerry/es2015/regression-test-issue-3454.js new file mode 100644 index 00000000..409a840c --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3454.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +"use strict" +try { + eval("var $ = function yield() {}"); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3455.js b/tests/jerry/es2015/regression-test-issue-3455.js new file mode 100644 index 00000000..23b5c299 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3455.js @@ -0,0 +1,42 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + [...RegExp.$.$] = String(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var o = { a : { b : { c : { d: { e : { } } } } } }; + +[...o.a.b.c.d.e] = "foo"; + +assert(o.a.b.c.d.e.length === 3); +assert(o.a.b.c.d.e[0] === "f"); +assert(o.a.b.c.d.e[1] === "o"); +assert(o.a.b.c.d.e[2] === "o"); + +[o.a.b.c.d.e] = "foo"; + +assert(o.a.b.c.d.e === "f"); + +[this.o.a.b.c.d.e] = "bar"; +assert(this.o.a.b.c.d.e === "b"); + +[...this.o.a.b.c.d.e] = "bar"; +assert(this.o.a.b.c.d.e.length === 3); +assert(this.o.a.b.c.d.e[0] === "b"); +assert(this.o.a.b.c.d.e[1] === "a"); +assert(this.o.a.b.c.d.e[2] === "r"); diff --git a/tests/jerry/es2015/regression-test-issue-3458.js b/tests/jerry/es2015/regression-test-issue-3458.js new file mode 100644 index 00000000..b9bc8a32 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3458.js @@ -0,0 +1,28 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class Animal {} +class Dog extends Animal { + static explain () { + super.f = 8 + } +} + +assert (Dog.f === undefined); +assert (Animal.f === undefined); + +Dog.explain () + +assert (Animal.f === undefined); +assert (Dog.f === 8); diff --git a/tests/jerry/es2015/regression-test-issue-3459.js b/tests/jerry/es2015/regression-test-issue-3459.js new file mode 100644 index 00000000..7bb686e3 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3459.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class MyOtherArray {} + +class MyNonArray extends Array { + static [Symbol.species] () {} +} + +(() => MyNonArray)().prototype.slice.call(new MyNonArray((0) === 1)) diff --git a/tests/jerry/es2015/regression-test-issue-3478.js b/tests/jerry/es2015/regression-test-issue-3478.js new file mode 100644 index 00000000..1e224143 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3478.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +Object.prototype["symbol"] = 0; +try { + Promise.race([]); + assert(false); +} catch(e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3479.js b/tests/jerry/es2015/regression-test-issue-3479.js new file mode 100644 index 00000000..489c95dd --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3479.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class MyObservedArray extends Array { + constructor() { + super('"use strict"; var x = "\\411";') + } [Symbol]() {} +} + +new MyObservedArray().slice() diff --git a/tests/jerry/es2015/regression-test-issue-3483.js b/tests/jerry/es2015/regression-test-issue-3483.js new file mode 100644 index 00000000..d99949a9 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3483.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function assertThrows(src) { + try { + eval(src); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +assertThrows('Setting `o.bar` to'); +assertThrows('Setting `o.bar`; Setting `o.bar` to'); +assertThrows('Setting `o.bar`; Setting `o.bar`; Setting `o.bar` to'); diff --git a/tests/jerry/es2015/regression-test-issue-3485.js b/tests/jerry/es2015/regression-test-issue-3485.js new file mode 100644 index 00000000..026164e9 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3485.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = new Float32Array([$]) + +try { + var $ = a.map(function () { $() }); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3519.js b/tests/jerry/es2015/regression-test-issue-3519.js new file mode 100644 index 00000000..c51a7d80 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3519.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function method () { + [""] = $ +} + +try { + eval ("function mm () { [new.target] = 3; }"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3527.js b/tests/jerry/es2015/regression-test-issue-3527.js new file mode 100644 index 00000000..10995259 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3527.js @@ -0,0 +1,34 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function assertThrows(src) { + try { + eval(src); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +assertThrows(`function $({ + $: { + [$.$] + } +}) {}`); + +assertThrows(`function $({ + $: { + [$] + } +}) {}`); diff --git a/tests/jerry/es2015/regression-test-issue-3534.js b/tests/jerry/es2015/regression-test-issue-3534.js new file mode 100644 index 00000000..3eb16819 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3534.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var array = [$, Infinity] +Reflect.preventExtensions(array); + +try { + var $ = array.pop() + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3536.js b/tests/jerry/es2015/regression-test-issue-3536.js new file mode 100644 index 00000000..2a996411 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3536.js @@ -0,0 +1,36 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class A { + constructor() { + var hasProp = $ => {} + Object.preventExtensions(hasProp); + assert(Object.isSealed(hasProp) === false); + } + super() { + $: $ + } +} +class B extends A { + constructor() { + super() (super.super) + } +} + +try { + new B; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3580.js b/tests/jerry/es2015/regression-test-issue-3580.js new file mode 100644 index 00000000..ae371732 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3580.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var func = function(val, idx) { + return val + idx +}; + +String([0, "X"].map(func).copyWithin([])); diff --git a/tests/jerry/es2015/regression-test-issue-3588.js b/tests/jerry/es2015/regression-test-issue-3588.js new file mode 100644 index 00000000..afa6ab9b --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3588.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test if the native function as constructor is correctly invoked +// when used as parent "class" + +class C extends print {} +new C () diff --git a/tests/jerry/es2015/regression-test-issue-3589.js b/tests/jerry/es2015/regression-test-issue-3589.js new file mode 100644 index 00000000..52576dd8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3589.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + [this,000000000,this,99999999=9999999]; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + +try { + [this,999+=8]; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3595.js b/tests/jerry/es2015/regression-test-issue-3595.js new file mode 100644 index 00000000..e91e1eab --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3595.js @@ -0,0 +1,25 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test if the native function as constructor is correctly invoked +// when used as parent "class" + +var src = "({ $($) { a(...args) }"; + +try { + eval (src); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3606.js b/tests/jerry/es2015/regression-test-issue-3606.js new file mode 100644 index 00000000..ce6e28d0 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3606.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +var expected = '{"copyWithin":true,"entries":true,"fill":true,"find":true,"findIndex":true,"keys":true,"values":true}'; +assert(JSON.stringify(Array.prototype[Symbol.unscopables]) === expected); diff --git a/tests/jerry/es2015/regression-test-issue-3611.js b/tests/jerry/es2015/regression-test-issue-3611.js new file mode 100644 index 00000000..ff616f98 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3611.js @@ -0,0 +1,40 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var tcs = [ + "for (const [] of $)", + "for (const [] in $)", + "for (let [] of $)", + "for (let [] in $)", + "for (const {} of $)", + "for (const {} in $)", + "for (let {} of $)", + "for (let {} in $)", +]; + +for (let e of tcs) { + try { + eval (e); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } + + try { + eval (e + " {}"); + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } +} diff --git a/tests/jerry/es2015/regression-test-issue-3625.js b/tests/jerry/es2015/regression-test-issue-3625.js new file mode 100644 index 00000000..93257789 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3625.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Base = function() {}.bind(); +Object.defineProperty(Base, 'prototype', { + get: function() { + return Int8Array + Function + } +}); + +try { + class C extends Base {} + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3628.js b/tests/jerry/es2015/regression-test-issue-3628.js new file mode 100644 index 00000000..7d4f4490 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3628.js @@ -0,0 +1,25 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var g = Array.bind(0, 0, 0, 0) +g.prototype = Array; +class C extends g {} +class D extends C { + constructor(a, b, c) { + eval("eval ('super (a, b, c, d)')") + + } +} +var d = new D +assert(d.length === 7); diff --git a/tests/jerry/es2015/regression-test-issue-3630.js b/tests/jerry/es2015/regression-test-issue-3630.js new file mode 100644 index 00000000..05f6e8b5 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3630.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + { + class eval {} + eval() + } + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3636.js b/tests/jerry/es2015/regression-test-issue-3636.js new file mode 100644 index 00000000..8a75d05a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3636.js @@ -0,0 +1,39 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f() {} +var B = class extends f { + constructor() { + String(Reflect.setPrototypeOf(B, null)); + super($) + } +} +C = class extends B { + g() { + return function() {} + } +} +D = class extends C { + constructor() { + super() + } + g() {} +} + +try { + new D + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3637.js b/tests/jerry/es2015/regression-test-issue-3637.js new file mode 100644 index 00000000..5cfcee34 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3637.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = [1, 2, 3, 4]; +var b = a.slice(0, { valueOf: function(){ a.length = 0; return 100; } }); + +assert(b.length === 4); + +var c = [1, 2, 3, 4]; +c.prop = 4 +var d = c.slice(0, { valueOf: function(){ c.length = 0; return 100; } }); + +assert(d.length === 4); diff --git a/tests/jerry/es2015/regression-test-issue-3640.js b/tests/jerry/es2015/regression-test-issue-3640.js new file mode 100644 index 00000000..1ac6dadb --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3640.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var B = class {} +eval = class extends B {} + +try { + eval(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3641.js b/tests/jerry/es2015/regression-test-issue-3641.js new file mode 100644 index 00000000..7f27579d --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3641.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +eval = class extends SyntaxError { + constructor() { + super() + } +} + +try { + eval() + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3647.js b/tests/jerry/es2015/regression-test-issue-3647.js new file mode 100644 index 00000000..d595591c --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3647.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +f(); +let g; +function f() { + assert(eval('function g() { return 5}; g')() === 5); +} diff --git a/tests/jerry/es2015/regression-test-issue-3655.js b/tests/jerry/es2015/regression-test-issue-3655.js new file mode 100644 index 00000000..be6063ad --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3655.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +let str = 'for (let i of id_36) function testcase() { testcase'; + +try { + eval (str); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3656.js b/tests/jerry/es2015/regression-test-issue-3656.js new file mode 100644 index 00000000..3a195cff --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3656.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +$ => $++ +[ ] diff --git a/tests/jerry/es2015/regression-test-issue-3658.js b/tests/jerry/es2015/regression-test-issue-3658.js new file mode 100644 index 00000000..ed429994 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3658.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function g({ + ["y"]: { + a + } +}) +{ + { + function a() {} + } +} diff --git a/tests/jerry/es2015/regression-test-issue-3665.js b/tests/jerry/es2015/regression-test-issue-3665.js new file mode 100644 index 00000000..fe1a7719 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3665.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var idx1 = 32.6; +var idx2 = 42.7; +var obj = { [idx1] : { [idx2] : {}}}; +([obj[idx1][idx2]] = [5.7]); + +assert (obj[idx1][idx2] === 5.7); diff --git a/tests/jerry/es2015/regression-test-issue-3671.js b/tests/jerry/es2015/regression-test-issue-3671.js new file mode 100644 index 00000000..48c0e51a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3671.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = { + get source() { + return "Iam" + }, + [Symbol.match]: true +} + +var regexp = new RegExp(obj); +assert(regexp.source === "Iam"); + +Object.defineProperty(obj, 'flags', {'get' : function () {throw 42}}); + +try { + new RegExp(obj); + assert(false); +} catch (e) { + assert(e === 42); +} diff --git a/tests/jerry/es2015/regression-test-issue-3715.js b/tests/jerry/es2015/regression-test-issue-3715.js new file mode 100644 index 00000000..9516e0aa --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3715.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class B extends Array { + constructor() { + super(); + super.f = 8; + } +} +var arg = new B() diff --git a/tests/jerry/es2015/regression-test-issue-3751.js b/tests/jerry/es2015/regression-test-issue-3751.js new file mode 100644 index 00000000..981dbc47 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3751.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`for (let i in { + id_0: 1 + }) + + (function() { + i + `); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3760.js b/tests/jerry/es2015/regression-test-issue-3760.js new file mode 100644 index 00000000..c5a67602 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3760.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var split = RegExp.prototype[Symbol.split]; + +try { + split.call({[Symbol.match]: "g"}); + assert(false); +} catch (ex) { + assert(ex instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3784.js b/tests/jerry/es2015/regression-test-issue-3784.js new file mode 100644 index 00000000..f3f905e3 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3784.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var expected = ['0', '1', '2', '3', '4', '5']; +var actual = []; + +var v1 = typeof 13.37; +var v3 = Object(v1); +var v5 = [13.37,13.37]; +var v6 = [v5]; +v3.__proto__ = v6; + +for (var v7 in v3) { + actual.push(v7); +} + +assert(actual.length === expected.length); + +for (var i = 0; i < actual.length; i++) { + assert(actual[i] === expected[i]); +} diff --git a/tests/jerry/es2015/regression-test-issue-3785.js b/tests/jerry/es2015/regression-test-issue-3785.js new file mode 100644 index 00000000..be034a84 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3785.js @@ -0,0 +1,37 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = new Proxy({length:2}, {}); +a.__proto__ = a; + +try { + a[1]; + assert (false); +} catch (e) { + assert (e instanceof RangeError); +} + +try { + a[1] = 2; + assert (false); +} catch (e) { + assert (e instanceof RangeError); +} + +try { + Array.prototype.forEach.call(a, ()=>{}); + assert (false); +} catch (e) { + assert (e instanceof RangeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3787.js b/tests/jerry/es2015/regression-test-issue-3787.js new file mode 100644 index 00000000..40a4a039 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3787.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var symbol = Symbol("s"); +var obj = {demo: "3"}; +obj[symbol] = 3; + +var proxy = new Proxy(obj, []); +var str = JSON.stringify(proxy); + +assert(str === '{"demo":"3"}'); diff --git a/tests/jerry/es2015/regression-test-issue-3812.js b/tests/jerry/es2015/regression-test-issue-3812.js new file mode 100644 index 00000000..7d71decb --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3812.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f (a) { + assert(a[0] === '𞹴'); +} + +f`𞹴`; diff --git a/tests/jerry/es2015/regression-test-issue-3814.js b/tests/jerry/es2015/regression-test-issue-3814.js new file mode 100644 index 00000000..08024236 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3814.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f () {} + +assert((new f) instanceof new Proxy(f, {})) diff --git a/tests/jerry/es2015/regression-test-issue-3817.js b/tests/jerry/es2015/regression-test-issue-3817.js new file mode 100644 index 00000000..93d24871 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3817.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var replace = RegExp.prototype[Symbol.replace]; +replace.call({ exec : ( ) => { return { } } }, '^o𓙦һ', "a"); diff --git a/tests/jerry/es2015/regression-test-issue-3819.js b/tests/jerry/es2015/regression-test-issue-3819.js new file mode 100644 index 00000000..c635c1d1 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3819.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + typeof (global.v2) = 123; + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3820.js b/tests/jerry/es2015/regression-test-issue-3820.js new file mode 100644 index 00000000..8326181d --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3820.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + (isNaN(parseFloat("."))) = 'abcd'; + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3822.js b/tests/jerry/es2015/regression-test-issue-3822.js new file mode 100644 index 00000000..e126e4b9 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3822.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`function f ({array, 'a', { value: 'foo', enumerable: true } : 36}){}`); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3823.js b/tests/jerry/es2015/regression-test-issue-3823.js new file mode 100644 index 00000000..1e67b950 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3823.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`function f ({"aba,a"}){}`); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3824.js b/tests/jerry/es2015/regression-test-issue-3824.js new file mode 100644 index 00000000..ee677834 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3824.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`var a = {"foo//b", };`); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3825.js b/tests/jerry/es2015/regression-test-issue-3825.js new file mode 100644 index 00000000..5419d8d8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3825.js @@ -0,0 +1,34 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`var errorMessage = "toStringThrows" + + var toStringThrows = { + "foo//bar/baz//foo" + } + + try { + var obj = {}; + obj[toStringThrows] = 3; + assert(false); + } catch (e) { + assert(e.message == errorMessage); + } + `); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3836.js b/tests/jerry/es2015/regression-test-issue-3836.js new file mode 100644 index 00000000..c8df8d57 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3836.js @@ -0,0 +1,56 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function validate_typedarray (typedarray, result) { + assert(typedarray.length === result.length); + for (var i = 0; i < typedarray.length; i++) { + assert(typedarray[i] === result[i]); + } +} + +var v1 = new Float64Array(6); +v1.buffer.constructor = Uint8Array; +var v2 = new Float64Array(v1); + +assert(v2.buffer.constructor === Uint8Array); +validate_typedarray(v2, [0, 0, 0, 0, 0, 0]); + +var v3 = new Uint32Array(6); +v3.buffer.constructor = Float64Array; +var v4 = new Uint8Array(v3); + +assert(v4.buffer.constructor === Float64Array); +validate_typedarray(v4, [0, 0, 0, 0, 0, 0]); + +var v5 = new Uint32Array(6); +v5.buffer.constructor = Set; +var v6 = new Uint8Array(v5); + +assert(v6.buffer.constructor === Set); +validate_typedarray(v6, [0, 0, 0, 0, 0, 0]); + +var species_called = false; + +var v7 = new Float64Array(6); +var v8 = v7.buffer; +v8.constructor = { + get [Symbol.species] (){ + species_called = true; + return Uint8Array; + } +} +var v9 = new Float64Array(v7); + +assert(species_called); +assert(Reflect.getPrototypeOf(v9.buffer) === Uint8Array.prototype); diff --git a/tests/jerry/es2015/regression-test-issue-3837.js b/tests/jerry/es2015/regression-test-issue-3837.js new file mode 100644 index 00000000..b368fbaf --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3837.js @@ -0,0 +1,33 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function dummy () +{ + "D" + "a"; +} + +var p1Handler = { getOwnPropertyDescriptor: dummy }; +var p1 = new Proxy({}, p1Handler); + +function dummyString () +{ + return "a"; +} + +var p2Handler = { deleteProperty: dummyString }; +var p2 = new Proxy(p1, p2Handler); + +var result = (delete p2[1]); + +assert (result); diff --git a/tests/jerry/es2015/regression-test-issue-3845.js b/tests/jerry/es2015/regression-test-issue-3845.js new file mode 100644 index 00000000..4edc090d --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3845.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`typeof (a) = 1 === 'undefined';`); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3849.js b/tests/jerry/es2015/regression-test-issue-3849.js new file mode 100644 index 00000000..cfcdb794 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3849.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval(`[]=$--['']`); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + diff --git a/tests/jerry/es2015/regression-test-issue-3860.js b/tests/jerry/es2015/regression-test-issue-3860.js new file mode 100644 index 00000000..0aa78f1a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3860.js @@ -0,0 +1,53 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Object (...1, {}); + assert (false); +} catch (ex) { + // expected error: "TypeError: object is not iterable" + assert (ex instanceof TypeError); +} + +try { + Object (...1, {}, {}); + assert (false); +} catch (ex) { + // expected error: "TypeError: object is not iterable" + assert (ex instanceof TypeError); +} + +try { + Object (...1, { "prop": 2 }, 1, { "prop": 2 }); + assert (false); +} catch (ex) { + // expected error: "TypeError: object is not iterable" + assert (ex instanceof TypeError); +} + +try { + Object (...1, "str"); + assert (false); +} catch (ex) { + // expected error: "TypeError: object is not iterable" + assert (ex instanceof TypeError); +} + +try { + Object (...[], { "prop": 2 }, 1, { "prop": 2 }, ...1); + assert (false); +} catch (ex) { + // expected error: "TypeError: object is not iterable" + assert (ex instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3861.js b/tests/jerry/es2015/regression-test-issue-3861.js new file mode 100644 index 00000000..bf393a6a --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3861.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + (function() { + function* generatorFn() {} + g = generatorFn() + ownProto = Object.getPrototypeOf(g) + sharedProto = Object.getPrototypeOf(ownProto) + propertyIsEnumerable(sharedProto) + })() + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3862.js b/tests/jerry/es2015/regression-test-issue-3862.js new file mode 100644 index 00000000..292059a4 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3862.js @@ -0,0 +1,29 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var target = function() {}; +var handler = { + get() { + if ($); + } +}; + +var o = new Proxy(target, handler); + +try { + Reflect.construct(Function, ['c'], o); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3866.js b/tests/jerry/es2015/regression-test-issue-3866.js new file mode 100644 index 00000000..79711b2c --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3866.js @@ -0,0 +1,34 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a; +var b; +var called = false; +Promise.race([a, b]); +Promise.race([b, a]); +Promise.race([, b, a]); +Promise.race().then(function() {}, function() { + let str; + function getStr() { + return $ `$` + } + var $ = getStr() +}).catch(e => { + called = true; + assert (e instanceof TypeError); +}) + +function __checkAsync() { + assert(called); +} diff --git a/tests/jerry/es2015/regression-test-issue-3868.js b/tests/jerry/es2015/regression-test-issue-3868.js new file mode 100644 index 00000000..82a25273 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3868.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = new Proxy({}, {}); + +try { + for (var $ in a); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3870.js b/tests/jerry/es2015/regression-test-issue-3870.js new file mode 100644 index 00000000..9937e027 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3870.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (new RegExp("\ud800", "u").exec("\ud800")[0] === "\ud800"); diff --git a/tests/jerry/es2015/regression-test-issue-3871.js b/tests/jerry/es2015/regression-test-issue-3871.js new file mode 100644 index 00000000..3ae9f73b --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3871.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + new RegExp('"\\u', 'u'); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3880.js b/tests/jerry/es2015/regression-test-issue-3880.js new file mode 100644 index 00000000..ec99fb76 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3880.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +RegExp.prototype.constructor = "" +var r = /a/; +assert (r.test ("a")); + +RegExp.prototype.constructor = {} +r = /b/; +assert (r.test ("b")); diff --git a/tests/jerry/es2015/regression-test-issue-3893.js b/tests/jerry/es2015/regression-test-issue-3893.js new file mode 100644 index 00000000..7334c0e6 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3893.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +Object.prototype.toString = function () { + return a`` ; +}; diff --git a/tests/jerry/es2015/regresssion-test-issue-3302.js b/tests/jerry/es2015/regresssion-test-issue-3302.js new file mode 100644 index 00000000..46e42d9a --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3302.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function g ( a, b = a ) { + function a ( ) { } + function $ ( ) { } + eval ( "" ) +} +g ( ); + +$ = function ( ) { + function x ( ) { } +} + +function j ( ) { } diff --git a/tests/jerry/es2015/regresssion-test-issue-3395.js b/tests/jerry/es2015/regresssion-test-issue-3395.js new file mode 100644 index 00000000..3f653953 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3395.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +for (var [] of [[], []]) + "".split(new RegExp()) diff --git a/tests/jerry/es2015/regresssion-test-issue-3713.js b/tests/jerry/es2015/regresssion-test-issue-3713.js new file mode 100644 index 00000000..7dc12b6b --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3713.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function $(b = eval()) { + "" + eval() +} diff --git a/tests/jerry/es2015/regresssion-test-issue-3727.js b/tests/jerry/es2015/regresssion-test-issue-3727.js new file mode 100644 index 00000000..64b897b9 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3727.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +Function("a = 5, b, c = function() { for (var a = 0; a < 4; a++) ; return a; } ()", "eval ('super (a, b, c, d)')") diff --git a/tests/jerry/es2015/regresssion-test-issue-3841.js b/tests/jerry/es2015/regresssion-test-issue-3841.js new file mode 100644 index 00000000..3e0e8ccd --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3841.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval('$?$:$=>{ }?{ }:$') + assert(false) +} catch (e) { + assert(e instanceof SyntaxError) +} diff --git a/tests/jerry/es2015/regresssion-test-issue-3842.js b/tests/jerry/es2015/regresssion-test-issue-3842.js new file mode 100644 index 00000000..918b3ef9 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3842.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval('while(0 ? 0 : ()=>{} | {})') + assert(false) +} catch (e) { + assert(e instanceof SyntaxError) +} diff --git a/tests/jerry/es2015/regresssion-test-issue-3856.js b/tests/jerry/es2015/regresssion-test-issue-3856.js new file mode 100644 index 00000000..7040a534 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3856.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +let str = ''; +function async() {} + +async(str) diff --git a/tests/jerry/es2015/regresssion-test-issue-3857.js b/tests/jerry/es2015/regresssion-test-issue-3857.js new file mode 100644 index 00000000..7cd6c40b --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3857.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function async() {} + +new async diff --git a/tests/jerry/es2015/regresssion-test-issue-3869.js b/tests/jerry/es2015/regresssion-test-issue-3869.js new file mode 100644 index 00000000..26cb32f1 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3869.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval('function a ({ *x:x }) {}') + assert(false) +} catch (e) { + assert(e instanceof SyntaxError) +} diff --git a/tests/jerry/es2015/regresssion-test-issue-3888.js b/tests/jerry/es2015/regresssion-test-issue-3888.js new file mode 100644 index 00000000..65d3e399 --- /dev/null +++ b/tests/jerry/es2015/regresssion-test-issue-3888.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function i(id_0, b = (eval("var x"))) { + function x() {} + eval(!eval("var x = {}; x instanceof assert;")) +} +i() diff --git a/tests/jerry/es2015/set-iterators.js b/tests/jerry/es2015/set-iterators.js index 13668817..31423a35 100644 --- a/tests/jerry/es2015/set-iterators.js +++ b/tests/jerry/es2015/set-iterators.js @@ -106,3 +106,49 @@ for (var i = 0; i < elementCount; i++) { } assert(s.size === 0); + +s = new Set ([0, 1]); +var expected = [0, 1, 2, 4, 5, 6, 3]; +var loopCount = 0; + +s.forEach(function(element) { + if (loopCount === 0) { + for (var i = 0; i < expected.length ; i++) { + s.add(i); + } + s.delete(3); + s.add(3); + } + assert(element === expected[loopCount++]); +}); + +assert(loopCount === expected.length); + +s = new Set([0, 1, 2, 3, 4, 5, 6]); +expected = [0, 1]; +loopCount = 0; + +for (var value of s) { + if (loopCount === 0) { + s.clear(); + s.add(1); + } + + assert(value === expected[loopCount++]); +} + +s = new Set([0]) +expected = [0, 1]; +loopCount = 0; + +for (var value of s) { + if (loopCount === 0) { + s.add(2); + s.delete(2); + s.add(3); + s.delete(3); + s.add(1); + } + + assert(value === expected[loopCount++]); +} diff --git a/tests/jerry/es2015/set.js b/tests/jerry/es2015/set.js index 42477f99..46bbd0ae 100644 --- a/tests/jerry/es2015/set.js +++ b/tests/jerry/es2015/set.js @@ -91,3 +91,48 @@ assert(set.size === 0); set.add(3); assert(set.delete(3)); assert(!set.delete(3)); + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +var closed = false; +var iter = createIterable([1, 2, 3], { + 'return': function(){ closed = true; return {}; } +}); +var add = Set.prototype.add; +Set.prototype.add = function(){ throw 0 }; +try { + new Set(iter); +} catch(e){} +Set.prototype.add = add; + +assert(closed === true); + +/* Test third argument of callback */ +var s = new Set([1, 2, 3]); + +s.forEach(function(value, key, thisArg) { + assert (typeof thisArg === "object"); + assert(thisArg === s); +}); + +var set = new Set(); +set.add(-0); +var k; +set.forEach(function (value) { + k = 1 / value; +}); + +assert(k === Infinity); +assert(set.has(+0) === true); diff --git a/tests/jerry/es2015/string-fromcodepoint.js b/tests/jerry/es2015/string-fromcodepoint.js new file mode 100644 index 00000000..b4e10626 --- /dev/null +++ b/tests/jerry/es2015/string-fromcodepoint.js @@ -0,0 +1,64 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Tests with valid inputs +assert(String.fromCodePoint(42) === "*") +assert(String.fromCodePoint(65, 90) === "AZ"); +assert(String.fromCodePoint(0x404) === "Є"); +assert(String.fromCodePoint(194564) === "你"); +assert(String.fromCodePoint(0x1D306, 0x61, 0x1D307) === "𝌆a𝌇"); +assert(String.fromCodePoint(0x1F303) === "🌃"); + +// Tests with invalid inputs +try { + assert(String.fromCodePoint('_')); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} + +try { + assert(String.fromCodePoint(Infinity)); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} + +try { + assert(String.fromCodePoint(-1)); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} + +try { + assert(String.fromCodePoint(3.14)); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} + +try { + assert(String.fromCodePoint(3e-2)); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} + +try { + assert(String.fromCodePoint(NaN)); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} diff --git a/tests/jerry/es2015/string-prototype-codepointat.js b/tests/jerry/es2015/string-prototype-codepointat.js new file mode 100644 index 00000000..6f50af96 --- /dev/null +++ b/tests/jerry/es2015/string-prototype-codepointat.js @@ -0,0 +1,54 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = "A🌃B\uD800"; +var obj = {}; + +// Test with normal inputs +assert(str.codePointAt(0) === 65); +assert(str.codePointAt(1) === 127747); +assert(str.codePointAt(2) === 57091); +assert(str.codePointAt(3) === 66); +assert(str.codePointAt(4) === 55296); + +// Test with string +assert(str.codePointAt("a") === 65); +assert(str.codePointAt("B") === 65); + +// Test with object +assert(str.codePointAt(obj) === 65); + +// Test with NaN +assert(str.codePointAt(NaN) === 65); + +// Test when the input >= length +assert(str.codePointAt(5) === undefined); +assert(str.codePointAt(10) === undefined); + +// Test witn negative +assert(str.codePointAt(-1) === undefined); +assert(str.codePointAt(-5) === undefined); +assert(str.codePointAt(-0) === 65); + +// Test with undefined and +/- Infinity +assert(str.codePointAt(undefined) === 65); +assert(str.codePointAt(Infinity) === undefined); +assert(str.codePointAt(-Infinity) === undefined); + +// Test with boolean +assert(str.codePointAt(true) === 127747); +assert(str.codePointAt(false) === 65); + +// Test when input > UINT32_MAX +assert(str.codePointAt(4294967299) === undefined); diff --git a/tests/jerry/es2015/string-prototype-endswith.js b/tests/jerry/es2015/string-prototype-endswith.js index a08e9cfc..b92ccdc0 100644 --- a/tests/jerry/es2015/string-prototype-endswith.js +++ b/tests/jerry/es2015/string-prototype-endswith.js @@ -61,3 +61,20 @@ try { } catch (e) { assert (e instanceof TypeError); } + +z[Symbol.match] = false; +assert(y.endsWith(z) === false); + +try { + "foo".endsWith({[Symbol.match] : true}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + "foo".endsWith({get [Symbol.match] () { throw 5}}); + assert(false); +} catch (e) { + assert(e === 5); +} diff --git a/tests/jerry/es2015/string-prototype-includes.js b/tests/jerry/es2015/string-prototype-includes.js index 36508b2c..1fdb0ef8 100644 --- a/tests/jerry/es2015/string-prototype-includes.js +++ b/tests/jerry/es2015/string-prototype-includes.js @@ -60,3 +60,20 @@ try { } catch (e) { assert (e instanceof TypeError); } + +z[Symbol.match] = false; +assert(y.includes(z) === false); + +try { + "foo".includes({[Symbol.match] : true}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + "foo".includes({get [Symbol.match] () { throw 5}}); + assert(false); +} catch (e) { + assert(e === 5); +} diff --git a/tests/jerry/es2015/string-prototype-match.js b/tests/jerry/es2015/string-prototype-match.js new file mode 100644 index 00000000..02e818a4 --- /dev/null +++ b/tests/jerry/es2015/string-prototype-match.js @@ -0,0 +1,82 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class NewRegExp extends RegExp { + [Symbol.match](str) { + var result = RegExp.prototype[Symbol.match].call(this, str); + var successful = 0; + if (result) { + successful = 1; + } + return successful; + } +} + +var str = 'This is a random string.'; +var regexp = new NewRegExp(/[A-Z]/g); +assert(str.match(regexp) === 1); + +try { + String.prototype.match.call(null, regexp); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var regexp2 = /[A-Z]/g; +regexp2[Symbol.match] = "foo"; + +try { + str.match(regexp2); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +Object.defineProperty (regexp2, Symbol.match, { get () { throw 5 }}); + +try { + str.match(regexp2); + assert(false); +} catch (e) { + assert(e === 5); +} + +var wrong_sytnax = "str.match(/[A-5]/g"; + +try { + eval(wrong_sytnax); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} + +delete(RegExp.prototype[Symbol.match]); + +try { + str.match(regexp); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +var regexp3 = "foo"; +RegExp.prototype[Symbol.match] = 3; + +try { + str.match(regexp3); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/string-prototype-split.js b/tests/jerry/es2015/string-prototype-split.js new file mode 100644 index 00000000..be23a55f --- /dev/null +++ b/tests/jerry/es2015/string-prototype-split.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = "foo//bar/baz//foo"; +res = str.split("a", Infinity); +assert (res.length === 3); +assert (res[0] === "foo//b"); +assert (res[1] === "r/b"); +assert (res[2] === "z//foo"); + +res = str.split(/\/\//, -1); +assert (res.length === 0); diff --git a/tests/jerry/es2015/string-prototype-startswith.js b/tests/jerry/es2015/string-prototype-startswith.js index 8926ce67..3f23487f 100644 --- a/tests/jerry/es2015/string-prototype-startswith.js +++ b/tests/jerry/es2015/string-prototype-startswith.js @@ -15,7 +15,10 @@ var x = "My cat is awesome"; assert (x.startsWith ("My")); assert (x.startsWith ("cat", 3)); +assert (x.startsWith ("awesome", 10)); assert (x.startsWith ("")); +assert (x.startsWith ("", 1)); +assert (x.startsWith ("", 17)); assert (x.startsWith ([])); assert (x.startsWith ("doggo") === false); @@ -51,3 +54,20 @@ try { } catch (e) { assert (e instanceof TypeError); } + +y[Symbol.match] = false; +assert(x.startsWith(y) === false); + +try { + "foo".startsWith({[Symbol.match] : true}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + "foo".startsWith({get [Symbol.match] () { throw 5}}); + assert(false); +} catch (e) { + assert(e === 5); +} diff --git a/tests/jerry/es2015/string-raw-crash-escaping-backslash.js b/tests/jerry/es2015/string-raw-crash-escaping-backslash.js new file mode 100644 index 00000000..f5b29bc0 --- /dev/null +++ b/tests/jerry/es2015/string-raw-crash-escaping-backslash.js @@ -0,0 +1,26 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This test must be left unchanged - testing JerryScript crash */ + +try +{ + var s = 'print(String.raw`\\`)\n// `'; + eval (s) + asserts(false) +} +catch (error) +{ +} diff --git a/tests/jerry/es2015/string-raw.js b/tests/jerry/es2015/string-raw.js new file mode 100644 index 00000000..5710271a --- /dev/null +++ b/tests/jerry/es2015/string-raw.js @@ -0,0 +1,71 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertThrows(str, error) { + try { + eval(str); + assert(false); + } catch (e) { + if (typeof error === "function") { + assert(e instanceof error); + } else { + assert(e === error) + } + } +} + +// https://www.ecma-international.org/ecma-262/6.0/#sec-string.raw 21.1.2.4 +// Note: the string error messages represents the nth step of the routine +var abruptTests = [ + ["undefined", TypeError], // 3. + ["{ get raw() { throw '5'; } }", '5'], + ["{ raw : undefined }", TypeError], // 5.toObject + ["{ raw : { get length() { throw '7.1'; } } }", '7.1'], + ["{ raw : { length : { toString() { throw '7.2'; } } } }", '7.2'], + ["{ raw : { length: 2, get '0'() { throw '12.b.1'} } }", '12.b.1'], + ["{ raw : { length: 2, '0' : { toString() { throw '12.b.2';} } } }", '12.b.2'], + ["{ raw : { length: 2, '0' : 1 } }, { toString() { throw '12.h';} }", '12.h'], +]; + +abruptTests.forEach(e => { + assertThrows("String.raw(" + e[0] + ")", e[1]); +}); + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw +assert(String.raw`Hi\n${2+3}!` === 'Hi\\n5!'); +assert(String.raw`Hi\u000A!` === 'Hi\\u000A!'); + +let name = 'Bob'; +assert(String.raw`Hi\n${name}!` === "Hi\\nBob!"); + +let str = String.raw({ + raw: ['foo', 'bar', 'baz'] +}, 2 + 3, 'Java' + 'Script'); +assert(str === "foo5barJavaScriptbaz"); + +assert(String.raw({ raw: 'test' }, 0, 1, 2) === "t0e1s2t"); + +var get = []; +var raw = new Proxy({length: 2, 0: '', 1: ''}, { get: function(o, k) { get.push(k); return o[k]; }}); +var p = new Proxy({raw: raw}, { get: function(o, k) { get.push(k); return o[k]; }}); +String.raw(p); +assert(get + '' === "raw,length,0,1"); + +assert(String.raw`\\` == "\\\\") +assert(String.raw`\`` == "\\`") +assert(String.raw`\ +\ +` == "\\\n\\\n") +assert(String.raw`\
` == "\\\u2029") diff --git a/tests/jerry/es2015/super-assignment.js b/tests/jerry/es2015/super-assignment.js new file mode 100644 index 00000000..696bf6c6 --- /dev/null +++ b/tests/jerry/es2015/super-assignment.js @@ -0,0 +1,75 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var setterCalled = false; + +class Base { + func () { + return 5; + } + funcArrow () { + return () => 5; + } + ["com" + "puted"] () { + return 10; + } + get getter () { + return 6; + } + set setter (a) { + setterCalled = true; + } + getSuperValueOf() { + return super.valueOf; + } +} + +class Derived extends Base { + func () { + return super.func(); + } + funcArrow () { + return () => super.func(); + } + ["com" + "puted"] () { + return super["com" + "puted"](); + } + get getter () { + return super.getter; + } + set setter (a) { + super.setter = a; + } + deleteSuperReference () { + delete super.a; + } +} + +var derived = new Derived; +var base = new Base; + +assert (derived.func() === 5); +assert (derived.funcArrow()() === 5); +assert (derived.computed() === 10); +assert (derived.getter === 6); +derived.setter = 7; +assert (setterCalled === true); +assert (base.getSuperValueOf() === Object.prototype.valueOf); + +try { + derived.deleteSuperReference(); + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/symbol-isconcatspreadable.js b/tests/jerry/es2015/symbol-isconcatspreadable.js new file mode 100644 index 00000000..96063402 --- /dev/null +++ b/tests/jerry/es2015/symbol-isconcatspreadable.js @@ -0,0 +1,81 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test with regular arrays +var alpha = ['a', 'b', 'c']; +var numeric = [1, 2, 3]; + +var alphaNumeric = alpha.concat(numeric); +assert(JSON.stringify(alphaNumeric) === '["a","b","c",1,2,3]'); +assert(alphaNumeric.length === 6); + +numeric[Symbol.isConcatSpreadable] = false; +alphaNumeric = alpha.concat(numeric); +assert(JSON.stringify(alphaNumeric) === '["a","b","c",[1,2,3]]'); +assert(alphaNumeric.length === 4); + +numeric[Symbol.isConcatSpreadable] = true; + +// Test with array-like object +var fakeArray = { + [Symbol.isConcatSpreadable]: true, + length: 2, + 0: 4, + 1: 5 +} + +var numericArray = numeric.concat(fakeArray); +assert(JSON.stringify(numericArray) === '[1,2,3,4,5]'); +assert(numericArray.length === 5); + +fakeArray[Symbol.isConcatSpreadable] = false; +numericArray = numeric.concat(fakeArray); +assert(JSON.stringify(numericArray) === '[1,2,3,{"0":4,"1":5,"length":2}]'); +assert(numericArray.length === 4); + +// Test with object +var obj = { 0: 'd' }; + +var alphaObj = alpha.concat(obj); +assert(JSON.stringify(alphaObj) === '["a","b","c",{"0":"d"}]'); +assert(alphaObj.length === 4); + +obj[Symbol.isConcatSpreadable] = true; +alphaObj = alpha.concat(obj); +assert(JSON.stringify(alphaObj) === '["a","b","c"]'); +assert(alphaObj.length === 3); + +// Test with boolean +var bool = true; +var numericBool = numeric.concat(bool); +assert(JSON.stringify(numericBool) === '[1,2,3,true]'); +assert(numericBool.length === 4); + +bool[Symbol.isConcatSpreadable] = false; +numericBool = numeric.concat(bool); +assert(JSON.stringify(numericBool) === '[1,2,3,true]'); +assert(numericBool.length === 4); + +// Test when unable to concat +var array1 = []; +var array2 = []; +Object.defineProperty(array2, '0', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + array1.concat(array2); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} diff --git a/tests/jerry/es2015/symbol-prototype-tostring.js b/tests/jerry/es2015/symbol-prototype-tostring.js index 7c16c07a..43a6c5c1 100644 --- a/tests/jerry/es2015/symbol-prototype-tostring.js +++ b/tests/jerry/es2015/symbol-prototype-tostring.js @@ -33,4 +33,10 @@ assert (String (foo) === "Symbol(foo)"); var fooObj = Object (foo); assert (fooObj.toString () === "Symbol(foo)"); -assert (String (fooObj) === "Symbol(foo)"); + +try { + String (fooObj); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/symbol-prototype.toprimitive.js b/tests/jerry/es2015/symbol-prototype.toprimitive.js new file mode 100644 index 00000000..f174e844 --- /dev/null +++ b/tests/jerry/es2015/symbol-prototype.toprimitive.js @@ -0,0 +1,30 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var obj2 = { + [Symbol.toPrimitive](hint) { + if (hint == 'number') { + return 10; + } + if (hint == 'string') { + return 'hello'; + } + return true; + } + }; + + assert(+obj2 === 10); + assert(`${obj2}` === "hello"); + assert(obj2 + '' === "true"); diff --git a/tests/jerry/es2015/symbol-replace.js b/tests/jerry/es2015/symbol-replace.js new file mode 100644 index 00000000..46de3288 --- /dev/null +++ b/tests/jerry/es2015/symbol-replace.js @@ -0,0 +1,674 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var replace = RegExp.prototype[Symbol.replace]; + +try { + replace.call (0, "string", "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + replace.call (new RegExp(), { + toString: () => { + throw "abrupt string" + } + }, "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt string"); +} + +try { + replace.call (new RegExp(), "string", { + toString: () => { + throw "abrupt replace" + } + }); + assert (false); +} catch (e) { + assert (e === "abrupt replace"); +} + +try { + replace.call ({ + get global() { + throw "abrupt global" + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt global"); +} + +try { + replace.call ({ + global: true, + set lastIndex(idx) { + throw "abrupt lastIndex" + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt lastIndex"); +} + +try { + replace.call ({ + get exec() { + throw "abrupt exec" + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt exec"); +} + +try { + replace.call ({ + exec: RegExp.prototype.exec + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + replace.call ({ + exec: 42 + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + replace.call ({ + exec: () => { + throw "abrupt exec result" + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt exec result"); +} + +try { + replace.call ({ + exec: () => { + return 1 + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + replace.call ({ + exec: () => { + return { + get length() { + throw "abrupt result length" + } + } + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt result length"); +} + +try { + replace.call ({ + global: true, + exec: () => { + return { + length: 1, + get 0() { + throw "abrupt match" + } + } + } + }, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt match"); +} + +try { + replace.call ({ + global: true, + exec: () => { + return { + length: 1, + get 0() { + return { + toString: () => { + throw "abrupt match toString" + } + } + } + } + } + }, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt match toString"); +} + +var result_obj = { + toString: () => { + Object.defineProperty (result_obj, 'toString', { + value: () => { + throw "abrupt match toString delayed"; + } + }); + return "str"; + } +} + +var first = true; +try { + replace.call ({ + global: true, + exec: () => { + if (!first) { + return null; + } + + first = false; + return { + length: 1, + get 0() { + return result_obj; + } + } + } + }, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt match toString delayed"); +} + +try { + replace.call ({ + global: true, + get lastIndex() { + throw "abrupt lastIndex get" + }, + set lastIndex(i) {}, + exec: () => { + return { + length: 1, + get 0() { + return { + toString: () => { + return "" + } + } + } + } + } + }, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt lastIndex get"); +} + +try { + replace.call ({ + global: true, + get lastIndex() { + return { + valueOf: () => { + throw "abrupt lastIndex toNumber" + } + } + }, + set lastIndex(i) {}, + exec: () => { + return { + length: 1, + get 0() { + return { + toString: () => { + return "" + } + } + } + } + } + }, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt lastIndex toNumber"); +} + +var o = { + global: true, + exec: () => { + return { + length: 1, + get 0() { + return { + toString: () => { + return "" + } + } + } + } + } +} +Object.defineProperty (o, 'lastIndex', { + configurable: true, + get: () => { + Object.defineProperty (o, 'lastIndex', { + get: () => { + return { + valueOf: () => { + return 42 + } + }; + }, + set: (i) => { + throw "abrupt lastIndex put"; + }, + configurable: true + }); + return { + valueOf: () => { + return 24 + } + }; + }, + set: (i) => {} +}); + +try { + replace.call (o, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt lastIndex put"); +} + +o = { + global: true, + exec: () => { + return { + length: 1, + get 0() { + return { + toString: () => { + return "" + } + } + } + } + }, +}; +Object.defineProperty (o, 'lastIndex', { + get: () => { + Object.defineProperty (o, 'lastIndex', { + value: 0, + writable: false + }); + return 0; + }, + set: () => {} +}); + +try { + replace.call (o, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +o = { + global: true +}; +Object.defineProperty (o, 'exec', { + configurable: true, + value: () => { + Object.defineProperty (o, 'exec', { + get: () => { + throw "abrupt exec" + }, + set: (v) => {} + }); + return { + length: 1, + 0: "thisisastring" + } + } +}); + +try { + replace.call (o, + "string", + "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt exec"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 1, + 0: "str", + get index() { + throw "abrupt index" + } + } + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt index"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 1, + 0: "str", + get index() { + return { + valueOf: () => { + throw "abrupt index toNumber" + } + } + } + } + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt index toNumber"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 2, + 0: "str", + index: 0, + get 1() { + throw "abrupt capture" + } + } + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt capture"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 2, + 0: "str", + index: 0, + 1: { + toString: () => { + throw "abrupt capture toString" + } + } + } + } + }, "string", "replace"); + assert (false); +} catch (e) { + assert (e === "abrupt capture toString"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 2, + 0: "str", + index: 0, + 1: "st" + } + } + }, "string", () => { + throw "abrupt replace" + }); + assert (false); +} catch (e) { + assert (e === "abrupt replace"); +} + +try { + replace.call ({ + exec: () => { + return { + length: 2, + 0: "str", + index: 0, + 1: "st" + } + } + }, "string", () => { + return { + toString: () => { + throw "abrupt replace toString" + } + } + }); + assert (false); +} catch (e) { + assert (e === "abrupt replace toString"); +} + +try { + replace.call (/abc/, "abc", () => { + throw "fastpath abrupt replace" + }); + assert (false); +} catch (e) { + assert (e === "fastpath abrupt replace"); +} + +try { + replace.call (/abc/, "abc", () => { + return { + toString: () => { + throw "fastpath abrupt replace" + } + } + }); + assert (false); +} catch (e) { + assert (e === "fastpath abrupt replace"); +} + +assert (replace.call (/abc/, "abc", "xyz") === "xyz"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "xyz") === "abxyzfg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$$-") === "ab-$-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$&-") === "ab-cde-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$`-") === "ab-ab-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$'-") === "ab-fg-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$0-") === "ab-$0-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$1-") === "ab-c-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$2-") === "ab-d-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$3-") === "ab-d-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$4-") === "ab--fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$5-") === "ab-e-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$6-") === "ab-$6-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$00-") === "ab-$00-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$01-") === "ab-c-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$10-") === "ab-c0-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$99-") === "ab-$99-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "-$$1-") === "ab-$1-fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "$") === "ab$fg"); +assert (replace.call (/(c)((d)|(x))(e)/, "abcdefg", "$@") === "ab$@fg"); + +replace.call (/(c)((d)|(x))(e)/, "abcdefg", function () { + assert (arguments[0] === "cde"); + assert (arguments[1] === "c"); + assert (arguments[2] === "d"); + assert (arguments[3] === "d"); + assert (arguments[4] === undefined); + assert (arguments[5] === "e"); + assert (arguments[6] === 2); + assert (arguments[7] === "abcdefg"); +}); + +var re = /ab/g; +assert (replace.call (re, "-ab-ab-ab-ab-", "cd") === "-cd-cd-cd-cd-"); +assert (re.lastIndex === 0); + +re.lastIndex = 5; +assert (replace.call (re, "-ab-ab-ab-ab-", "cd") === "-cd-cd-cd-cd-"); +assert (re.lastIndex === 0); + +assert (replace.call (/(?:)/g, "string", "Duck") === "DucksDucktDuckrDuckiDucknDuckgDuck"); + +class Regexplike { + constructor() { + this.index = 0; + this.global = true; + } + + exec() { + if (this.index > 0) { + return null; + } + + this.index = 39; + var result = { + length: 1, + 0: "Duck", + index: this.index + }; + return result; + } +} + +re = new Regexplike(); + +/* Well-behaved RegExp-like object. */ +assert (replace.call (re, "What have you brought upon this cursed land", "$&") === "What have you brought upon this cursed Duck"); + +var replace_count = 0; + +function replacer() { + replace_count++; + return arguments[0]; +} + +re.index = 0; +re.exec = function () { + if (this.index > 3) { + return null; + } + + var result = { + length: 1, + 0: "Duck", + index: this.index++ + }; + return result; +} + +/* Mis-behaving RegExp-like object, replace function is called on each match, but the result is ignored for inconsistent matches. */ +assert (replace.call (re, "Badger", replacer) === "Ducker"); +assert (replace_count === 4); + +re.index = 0; +assert (replace.call (re, "Badger", "Ord") === "Order"); + +try { + replace.call (RegExp.prototype, "string", "replace"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert(replace.call({ exec : ( ) => { return { } } }, 'һ', "a") === "a"); +assert(replace.call({ exec : ( ) => { return { } } }, 'һһһһһһһһһ', "a") === "a"); +assert(replace.call({ exec : ( ) => { return { } } }, 'һһһһһһһһһһ', "a") === "aһ"); + +/* Object with custom @@replace method */ +var o = {} +o[Symbol.replace] = function () { + return "Duck" +}; +assert ("string".replace (o, "Mallard") === "Duck"); + +o[Symbol.replace] = 42; +try { + "string".replace (o, "Duck"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +Object.defineProperty (o, Symbol.replace, { + get: () => { + throw "abrupt @@replace get" + }, + set: (v) => {} +}); + +try { + "string".replace (o, "Duck"); + assert (false); +} catch (e) { + assert (e === "abrupt @@replace get"); +} + +o = {}; +o[Symbol.replace] = function () { + throw "abrupt @@replace" +}; +try { + "string".replace (o, "str"); + assert (false); +} catch (e) { + assert (e === "abrupt @@replace") +} + +class Regexplike2 { + exec() { + return {} + } +} +re = new Regexplike2(); +assert (replace.call (re, "1") === "undefined"); diff --git a/tests/jerry/es2015/symbol-search.js b/tests/jerry/es2015/symbol-search.js new file mode 100644 index 00000000..5f664d5e --- /dev/null +++ b/tests/jerry/es2015/symbol-search.js @@ -0,0 +1,228 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var search = RegExp.prototype[Symbol.search]; + +try { + search.call (0, "string"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + search.call (new RegExp(), { + toString: () => { + throw "abrupt string" + } + }); + assert (false); +} catch (e) { + assert (e === "abrupt string"); +} + +try { + search.call ({ + get lastIndex() { + throw "abrupt get lastIndex" + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt get lastIndex"); +} + +try { + search.call ({ + get lastIndex() { + return 3; + }, + set lastIndex(idx) { + throw "abrupt set lastIndex" + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt set lastIndex"); +} + +try { + search.call ({ + get exec() { + throw "abrupt exec" + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt exec"); +} + +try { + search.call ({ + exec: RegExp.prototype.exec + }, "string"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + search.call ({ + exec: 42 + }, "string"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + search.call ({ + exec: () => { + throw "abrupt exec result" + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt exec result"); +} + +try { + search.call ({ + exec: () => { + return 1 + } + }, "string"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + search.call ({ + exec: () => { + return { + get index() { + throw "abrupt index" + } + } + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt index"); +} + +assert (search.call (/abc/, "abc") === 0); +assert (search.call (/abc/, "strabc") === 3); +assert (search.call (/abc/, "bcd") === -1); + +class Regexplike { + constructor() { + this.index = 0; + this.global = true; + } + + exec() { + if (this.index > 0) { + return null; + } + + this.index = 42; + var result = { + length: 1, + 0: "Duck", + index: this.index + }; + return result; + } +} + +re = new Regexplike(); +assert (search.call (re, "str") === 42); + +/* Object with custom @@search method */ +var o = {} +o[Symbol.search] = function () { + return 4; +}; +assert ("string".search (o) === 4); + +o[Symbol.search] = 42; +try { + "string".search (o); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +Object.defineProperty (o, Symbol.search, { + get: () => { + throw "abrupt @@search get" + }, + set: (v) => {} +}); + +try { + "string".search (o); + assert (false); +} catch (e) { + assert (e === "abrupt @@search get"); +} + +o = {}; +o[Symbol.search] = function () { + throw "abrupt @@search" +}; +try { + "string".search (o); + assert (false); +} catch (e) { + assert (e === "abrupt @@search") +} + +o = { + exec: function () { return {index: "Duck"}; }, +}; +assert ("string".search (o) === 1); + +o[Symbol.search] = RegExp.prototype[Symbol.search]; +assert ("string".search (o) === "Duck"); + +o = { + lastIndex: "Duck", + exec: () => { + return "Duck"; + } +} + +try { + RegExp.prototype[Symbol.search].call (o, "Duck"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +o = { + exec: () => { + return { 0: "Duck", index: 0 }; + }, + get lastIndex () { + return "Duck"; + }, + set lastIndex (v) { + return "Duck"; + } +} + +assert (RegExp.prototype[Symbol.search].call (o, "str") === 0); diff --git a/tests/jerry/es2015/symbol-split.js b/tests/jerry/es2015/symbol-split.js new file mode 100644 index 00000000..0c17e21e --- /dev/null +++ b/tests/jerry/es2015/symbol-split.js @@ -0,0 +1,109 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var split = RegExp.prototype[Symbol.split]; + +try { + split.call (0, "string"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + split.call (new RegExp(), { + toString: () => { + throw "abrupt string" + } + }); + assert (false); +} catch (e) { + assert (e === "abrupt string"); +} + +try { + var o = {}; + o.constructor = "ctor"; + split.call (o, "str"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + var o = {}; + var c = {}; + o.constructor = c; + Object.defineProperty (c, Symbol.species, { get: function () { throw "abrupt species";} }); + + split.call (o, "str"); + assert (false); +} catch (e) { + assert (e === "abrupt species"); +} + +try { + split.call ({ + get flags() { + throw "abrupt flags"; + } + }, "string"); + assert (false); +} catch (e) { + assert (e === "abrupt flags"); +} + +try { + split.call ({ toString: function () { return "s"; }, flags: "g"}, + "string", + { valueOf: function () { throw "abrupt limit"; } }); + assert (false); +} catch (e) { + assert (e === "abrupt limit"); +} + +var exec = RegExp.prototype.exec; + +try { + Object.defineProperty(RegExp.prototype, "exec", { get : function() { throw "abrupt get exec"; }}) + split.call ({ toString: function () { return "s"; }, flags: "g"}, + "string") + assert (false); +} catch (e) { + assert (e === "abrupt get exec"); +} + +try { + Object.defineProperty(RegExp.prototype, "exec", { value: function (str) { + this.lastIndex++; + return { get length() { throw "abrupt match length"; }} + }}); + split.call ({ toString: function () { return "s"; }, flags: "g"}, + "string"); + assert (false); +} catch (e) { + assert (e === "abrupt match length"); +} + +try { + Object.defineProperty(RegExp.prototype, "exec", { value: function (str) { + this.lastIndex++; + return { length: 2, get 1() { throw "abrupt capture"; }} + }}); + split.call ({ toString: function () { return "s"; }, flags: "g"}, + "string"); + assert (false); +} catch (e) { + assert (e === "abrupt capture"); +} diff --git a/tests/jerry/es2015/symbol-unscopables.js b/tests/jerry/es2015/symbol-unscopables.js new file mode 100644 index 00000000..109c06e0 --- /dev/null +++ b/tests/jerry/es2015/symbol-unscopables.js @@ -0,0 +1,127 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = { + prop1: 42, + prop2: 13, + prop3: "foo", + prop4: 1 +}; + +var obj2 = { + foo: "foo" +}; + +obj[Symbol.unscopables] = { + prop1: false, + prop2: true, + prop3: undefined, + prop4: obj2 +}; + +with (obj) +{ + assert(prop1 === 42); + + try { + prop2; + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } + + assert (prop3 === "foo"); + + try { + prop4; + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } + + try { + prop5; + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } +} + +var obj2 = {}; +Object.defineProperty(obj2, Symbol.unscopables, { get: function () { throw 42; } }); + +with (obj2) { + try { + prop; + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } +} + +var obj3 = { foo: 12 }; +Object.defineProperty(obj3, Symbol.unscopables, { get: function () { throw 42; } }); + +with (obj3) { + try { + typeof foo; + } catch (e) { + assert(e === 42); + } +} + +var symbol_obj = Array.prototype[Symbol.unscopables]; +assert(symbol_obj.copyWithin === true); +assert(symbol_obj.entries === true); +assert(symbol_obj.fill === true); +assert(symbol_obj.find === true); +assert(symbol_obj.findIndex === true); +assert(symbol_obj.keys === true); +assert(symbol_obj.values === true); + +assert(Object.getPrototypeOf(Array.prototype[Symbol.unscopables]) === null); + +var obj3 = Object.getOwnPropertyDescriptor(Array.prototype[Symbol.unscopables], "find"); +assert(obj3.value === true); +assert(obj3.writable === true); +assert(obj3.enumerable == true); +assert(obj3.configurable == true); + +var a = { foo: 1, bar: 2 }; +a[Symbol.unscopables] = { bar: true }; +with (a) { + assert(foo === 1); + assert(typeof bar === "undefined"); +} + +let track = []; +let proxy = new Proxy({ a : 4, [Symbol.unscopables] : [] }, { + has (t, p) { + track.push(p); + return Reflect.has(...arguments); + }, + get (t, p, r) { + track.push(p); + return Reflect.get(...arguments); + } +}); + +with (proxy){ + a; +} + +assert(track.length == 3); +assert(track[0] === 'a'); +assert(track[1] === Symbol.unscopables); +assert(track[2] === 'a'); diff --git a/tests/jerry/es2015/symbol.js b/tests/jerry/es2015/symbol.js index 329a7c51..c23308ba 100644 --- a/tests/jerry/es2015/symbol.js +++ b/tests/jerry/es2015/symbol.js @@ -85,6 +85,11 @@ var a = ['hasInstance', a.forEach (function (e) { assert (Symbol[e].toString() === ('Symbol(Symbol.' + e +')')); assert (typeof Symbol[e] === 'symbol'); + /* Check for property descriptor ES 6 19.4.2.2 - 19.4.2.14 */ + var desc = Object.getOwnPropertyDescriptor(Symbol, e) + assert (desc.writable === false); + assert (desc.enumerable === false); + assert (desc.configurable === false); }); var obj = {}; diff --git a/tests/jerry/es2015/tagged-template-literal.js b/tests/jerry/es2015/tagged-template-literal.js new file mode 100644 index 00000000..a54154e8 --- /dev/null +++ b/tests/jerry/es2015/tagged-template-literal.js @@ -0,0 +1,139 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals +// Tagged templates +var person = 'Mike'; +var age = 28; + +function myTag(strings, personExp, ageExp) { + assert(strings[0] == "That "); + assert(strings[1] == " is a "); + var str0 = strings[0]; + var str1 = strings[1]; + + var ageStr; + if (ageExp > 99){ + ageStr = 'centenarian'; + } else { + ageStr = 'youngster'; + } + + return `${str0}${personExp}${str1}${ageStr}`; +} + +var output = myTag`That ${ person } is a ${ age }`; +assert(output === "That Mike is a youngster"); + +function template(strings, ...keys) { + return (function(...values) { + var dict = values[values.length - 1] || {}; + var result = [strings[0]]; + keys.forEach(function(key, i) { + var value = Number.isInteger(key) ? values[key] : dict[key]; + result.push(value, strings[i + 1]); + }); + return result.join(''); + }); +} + +var t1Closure = template`${0}${1}${0}!`; +assert(t1Closure('Y', 'A') === "YAY!"); +var t2Closure = template`${0} ${'foo'}!`; +assert(t2Closure('Hello', {foo: 'World'}) === "Hello World!"); + +// Raw strings +(function () { + function tag(strings) { + assert(strings.raw[0].length === 40); + } + + tag`string text line 1 \n string text line 2`; +})(); + +assert (String.raw`Hi\n${2+3}!` === "Hi\\n5!"); + +(function () { + function empty(strings, ...params) { + assert(strings.length === 4); + assert(strings.raw.length === 4); + assert(params.length === 3); + strings.forEach ((e) => assert (e === "")); + strings.raw.forEach ((e) => assert (e === "")); + params.forEach ((e) => assert (e === 1)); + } + + empty`${1}${1}${1}`; +})(); + +(function () { + function f (str) { + return str.raw[0].length; + } + assert (eval("f`a\u2029b`") === 3); +})(); + +(function () { + function testRaw(parts, a, b) { + assert(parts instanceof Array); + assert(parts.raw instanceof Array); + assert(parts.length === 3); + assert(parts[0] === "str"); + assert(parts[1] === "escaped\n"); + assert(parts[2] === ""); + assert(parts.raw.length === 3); + assert(parts.raw[0] === "str"); + assert(parts.raw[1] === "escaped\\n"); + assert(parts.raw[2] === ""); + assert(a === 123); + assert(b === 456); + return true; + } + + assert(testRaw `str${123}escaped\n${456}` === true); +})(); + +// TemplateStrings call site caching +(function () { + let str = (arr) => arr; + function getStr() { + return str`foo`; + } + var chainedCall = getStr(); + var localCall = str`foo`; + assert(chainedCall === getStr() && chainedCall !== localCall); +})(); + +// TemplateStrings permanent caching +(function () { + let str = (arr) => arr; + function getStr() { + return str`foo`; + } + var chainedCall = getStr(); + var localNew = new getStr(); + assert(chainedCall === getStr() && chainedCall === localNew); +})(); + +var templateObject; + +(function(p) { + templateObject = p; +})`str`; + +var desc = Object.getOwnPropertyDescriptor(templateObject, '0'); +assert(desc.writable === false); +assert(desc.enumerable === true); +assert(desc.configurable === false); diff --git a/tests/jerry/es2015/template_string.js b/tests/jerry/es2015/template_string.js index fc5c2861..6f6a3c3b 100644 --- a/tests/jerry/es2015/template_string.js +++ b/tests/jerry/es2015/template_string.js @@ -41,9 +41,9 @@ switch (1) { default: - `` - `abc` - `ab${a+b}${ `x` }c` + ``; + `abc`; + `ab${a+b}${ `x` }c`; assert (`` === ''); assert (`abc` === 'abc'); @@ -90,3 +90,15 @@ must_throw ("`${}`"); must_throw ("`${1}"); must_throw ("`${1}.${"); must_throw ("`${1}.${2}"); + +// line break normalization +var cr = eval("`a" + String.fromCharCode(13) + "b`"); +var lf = eval("`a" + String.fromCharCode(10) + "b`"); +var crlf = eval("`a" + String.fromCharCode(13,10) + "b`"); + +assert(cr.length === 3); +assert(lf.length === 3); +assert(crlf.length === 3); +assert(cr[1] === lf[1]); +assert(lf[1] === crlf[1]); +assert(crlf[1] === '\n'); diff --git a/tests/jerry/es2015/to-number-string.js b/tests/jerry/es2015/to-number-string.js new file mode 100644 index 00000000..8bf56fb3 --- /dev/null +++ b/tests/jerry/es2015/to-number-string.js @@ -0,0 +1,49 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert(+"0b1101001" === 105); +assert(+"0B1101001" === 105); +assert(+"0o767" === 503); +assert(+"0O767" === 503); + +function assertNaN(str) { + assert(isNaN(+str)); +} + +assertNaN("0b"); +assertNaN("0b12"); +assertNaN("0b10101100103"); +assertNaN("0b101foo"); +assertNaN("0bfoo101"); +assertNaN("0b12345"); + +assertNaN("0B"); +assertNaN("0B12"); +assertNaN("0B10101100103"); +assertNaN("0B101foo"); +assertNaN("0Bfoo101"); +assertNaN("0B12345"); + +assertNaN("0o"); +assertNaN("0o1289"); +assertNaN("0o88888"); +assertNaN("0o12345foo"); +assertNaN("0ofoo12345"); + +assertNaN("0O"); +assertNaN("0O1289"); +assertNaN("0O88888"); +assertNaN("0O12345foo"); +assertNaN("0Ofoo12345"); diff --git a/tests/jerry/es2015/try-catch.js b/tests/jerry/es2015/try-catch.js new file mode 100644 index 00000000..3e18c774 --- /dev/null +++ b/tests/jerry/es2015/try-catch.js @@ -0,0 +1,130 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var e = -1 + +function f1() +{ + assert(e === undefined) + try { + throw 0 + } catch (e) { + var e = 1 + assert(e === 1) + } + assert(e === undefined) +} +f1() + +function f2() +{ + assert(e === undefined) + try { + throw 0 + } catch (e) { + { + var e = 2 + assert(e === 2) + } + assert(e === 2) + } + assert(e === undefined) +} +f2() + +function f3() +{ + assert(e === -1) + try { + throw [0] + } catch ([e]) { + { + try { + eval("var e = 2") + assert(false) + } catch (e) { + assert(e instanceof SyntaxError) + } + } + assert(e === 0) + } + assert(e === -1) +} +f3() + +function f4() +{ + assert(e === undefined) + try { + throw 0 + } catch (e) { + { + function e() { return 3 } + assert(e() === 3) + } + assert(e === 0) + } + assert(e() === 3) +} +f4() + +function f5() +{ + assert(e === -1) + try { + throw 0 + } catch (e) { + { + eval("function e() { return 3 } assert(e === 0)") + assert(e === 0) + } + assert(e === 0) + } + assert(e() === 3) +} +f5() + +function f6() +{ + let e = 4; + assert(e === 4) + try { + throw 0 + } catch (e) { + { + function e() { return 5 } + assert(e() === 5) + } + assert(e === 0) + } + assert(e === 4) +} +f6() + +function f7() +{ + let e = 6; + assert(e === 6) + try { + throw 0 + } catch (e) { + { + eval("function e() { return 7 } assert(e() === 7)") + } + assert(e === 0) + } + assert(e === 6) +} +f7() diff --git a/tests/jerry/es2015/try-pattern.js b/tests/jerry/es2015/try-pattern.js new file mode 100644 index 00000000..28b7cc2c --- /dev/null +++ b/tests/jerry/es2015/try-pattern.js @@ -0,0 +1,94 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function check_syntax_error(code) +{ + try { + eval(code); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +check_syntax_error("try {} catch() {}"); +check_syntax_error("try {} catch([a] {}"); +check_syntax_error("try {} catch([a] = [1]) {}"); +check_syntax_error("try {} catch({a} = {a:1}) {}"); +check_syntax_error("try {} catch(a,) {}"); +check_syntax_error("try {} catch(a) { function a() {} }"); +check_syntax_error("try {} catch(a) { { function a() {} } function a() {} }"); +check_syntax_error("try {} catch([a]) { var a }"); +check_syntax_error("try {} catch([a]) { { var a } }"); +check_syntax_error("try {} catch([a]) { function a() {} }"); + +try { + throw [1,2] + assert(false) +} catch ([a, b]) { + assert(a === 1) + assert(b === 2) +} + +try { + throw { x:1, y:2 } + assert(false) +} catch ({x, 'y':b}) { + assert(x === 1) + assert(b === 2) +} + +try { + throw [1,2] + assert(false) +} catch ([a, b]) { + eval("assert(a === 1)") + eval("assert(b === 2)") +} + +try { + throw { x:1, y:2 } + assert(false) +} catch ({x, 'y':b}) { + eval("assert(x === 1)") + eval("assert(b === 2)") +} + +try { + try { + throw [] + assert(false) + } catch ([a = b, b]) { + assert(false) + } +} catch (e) { + assert(e instanceof ReferenceError) +} + +try { + throw [{a : 5}]; +} catch([{a}]) { + assert(a === 5); +} + +var catchReached = false; +try { + throw [{}]; + assert(false); +} catch([{}]) { + catchReached = true; +} + +assert(catchReached); diff --git a/tests/jerry/es2015/typedarray-from.js b/tests/jerry/es2015/typedarray-from.js new file mode 100644 index 00000000..cab6b979 --- /dev/null +++ b/tests/jerry/es2015/typedarray-from.js @@ -0,0 +1,157 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var typedArrayConstructors = [ + Uint8Array, + Int8Array, + Uint16Array, + Int16Array, + Uint32Array, + Int32Array, + Uint8ClampedArray, + Float32Array, + Float64Array +]; + +var set = new Set([1,2,3]); + +var foo = {}; +var bar = {}; +var weak_set = new WeakSet(); +weak_set.add(foo); +weak_set.add(bar); + +var string = new String('123'); + +var map = new Map(); +map.set(0, 'zero'); +map.set(1, 'one'); + +var weak_map = new WeakMap(); +weak_map.set(foo, 'foo'); +weak_map.set(bar, 'bar'); + +var string = '123'; + +for (var constructor of typedArrayConstructors) +{ + assert(constructor.from.length === 1); + + try { + function f() {constructor.from.call(Array, []);} + } catch (e) { + assert(e instanceof TypeError); + } + + assert(constructor.from(set).toString() === '1,2,3'); + assert(constructor.from(weak_set).toString() === ''); + + if (constructor == Float32Array || constructor == Float64Array) + { + assert(constructor.from(map).toString() === 'NaN,NaN'); + } + else + { + assert(constructor.from(map).toString() === '0,0'); + } + + assert(constructor.from(weak_map).toString() === ''); + assert(constructor.from(string).toString() === '1,2,3'); + + try { + function f() {constructor.from.call({}, []);} + } catch (e) { + assert(e instanceof TypeError); + } + + try { + function f() {constructor.from.call([], []);} + } catch (e) { + assert(e instanceof TypeError); + } + + try { + function f() {constructor.from.call(1, []);} + } catch (e) { + assert(e instanceof TypeError); + } + + try { + function f() {constructor.from.call(undefined, []);} + } catch (e) { + assert(e instanceof TypeError); + } + + assert(constructor.from([1,2,3,4]).toString() === '1,2,3,4'); + assert(constructor.from([12,45]).toString() === '12,45'); + assert(constructor.from(NaN).toString() === ''); + assert(constructor.from(Infinity).toString() === ''); + + assert(constructor.from([4,5,6], x => x + 1).toString() === '5,6,7'); + assert(constructor.from([2,4,8], x => x * 2).toString() === '4,8,16'); + + try { + constructor.from([1,2,3], x => {throw 5}); + assert(false); + } catch (e) { + assert(e === 5); + } + + try { + constructor.from([Symbol.match]); + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } + + try { + constructor.from([1,1,1], 'foo'); + assert(false); + } catch (e) { + assert (e instanceof TypeError); + } + + try { + function f() {constructor.from(null)} + } catch (e) { + assert(e instanceof TypeError); + } + + try { + function f() {constructor.from(undefined);} + } catch (e) { + assert(e instanceof TypeError); + } + + var called = 0; + var arr = [1,2,3]; + var obj = {}; + + function testIterator() { + called++; + return arr[Symbol.iterator](); + } + + var getCalled = 0; + Object.defineProperty(obj, Symbol.iterator, { + get: function() { + getCalled++; + return testIterator; + }, + }); + + assert(constructor.from(obj).toString() === '1,2,3'); + assert(called === 1); + assert(getCalled === 1); +} diff --git a/tests/jerry/es2015/typedarray-of.js b/tests/jerry/es2015/typedarray-of.js new file mode 100644 index 00000000..7735b646 --- /dev/null +++ b/tests/jerry/es2015/typedarray-of.js @@ -0,0 +1,131 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var int_typedarrays = [ + Uint8ClampedArray, + Uint8Array, + Uint16Array, + Uint32Array, + Int8Array, + Int16Array, + Int32Array +]; + +var float_typedarrays = [ + Float32Array, + Float64Array, +]; + +var obj = { + 0: 0, + 1: 1 +}; + +int_typedarrays.forEach(function(e){ + try { + e.of.call(undefined); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + try { + e.of.call(obj); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + // Test with regulat inputs + assert(e.of(1,2,3).toString() === "1,2,3"); + assert(e.of(12,4,5,0).toString() === "12,4,5,0"); + assert(e.of(23).toString() === "23"); + + // Test with string inputs + assert(e.of("12",4).toString() === "12,4"); + assert(e.of(1,2,"foo").toString() === "1,2,0"); + + // Test with undefined + assert(e.of(undefined).toString() === "0"); + + // Test with object + assert(e.of(obj).toString() === "0"); + + // Test with NaN + assert(e.of(NaN).toString() === "0"); +}); + +float_typedarrays.forEach(function(e){ + try { + e.of.call(undefined); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + try { + e.of.call(obj); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + // Test with regulat inputs + assert(e.of(1,2,3).toString() === "1,2,3"); + assert(e.of(12,4,5,0).toString() === "12,4,5,0"); + assert(e.of(23).toString() === "23"); + + // Test with string inputs + assert(e.of("12",4).toString() === "12,4"); + assert(e.of(1,2,"foo").toString() === "1,2,NaN"); + assert(e.of("-12").toString() === "-12"); + + // Test with undefined + assert(e.of(undefined).toString() === "NaN"); + + // Test with object + assert(e.of(obj).toString() === "NaN"); + + // Test with NaN + assert(e.of(NaN).toString() === "NaN"); +}); + +// Test with negative inputs +var a = Uint8ClampedArray.of(-8); +assert(a.toString() === "0"); + +a = Uint8Array.of(-8); +assert(a.toString() === "248"); + +a = Uint16Array.of(-8); +assert(a.toString() === "65528"); + +a = Uint32Array.of(-8); +assert(a.toString() === "4294967288"); + +a = Int8Array.of(-8); +assert(a.toString() === "-8"); + +a = Int16Array.of(-8); +assert(a.toString() === "-8"); + +a = Int32Array.of(-8); +assert(a.toString() === "-8"); + +a = Float32Array.of(-8); +assert(a.toString() === "-8"); + +a = Float64Array.of(-8); +assert(a.toString() === "-8"); diff --git a/tests/jerry/es2015/weakmap.js b/tests/jerry/es2015/weakmap.js new file mode 100644 index 00000000..d842872e --- /dev/null +++ b/tests/jerry/es2015/weakmap.js @@ -0,0 +1,184 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var m1 = new WeakMap(); +var k1 = {}; +assert (m1.set (k1, 3.14) instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === 3.14); + +k1 = {}; +gc (); /* This will remove the entry, but there is no way to validate it from js. */ + +assert (m1.has (k1) === false); +assert (m1.delete(k1) === false); +assert (m1.set (k1, "asd" + "fgh") instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === "asdfgh"); + +assert (m1.delete ("str") === false); +assert (m1.has (42) === false); +assert (m1.get (42) === undefined); +try { + m1.set (42, 42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +gc (); +assert (m1.delete(k1) === true); +gc (); +assert (m1.has (k1) === false); +k1 = {}; +gc (); + +Object.freeze(k1); +assert (m1.set (k1, "frozen") instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === "frozen"); +k1 = {}; +gc (); + +var m2 = new WeakMap(); + +m1.set (k1, "str" + "str"); +m2.set (k1, 42.42); + +k1 = {}; +gc (); +var k2 = {}; + +m1.set (k1, "str" + "str"); +m1.set (k2, "str2" + "str2"); +m2.set (k1, 42.42); +m2.set (k2, Infinity); + +m2.delete (k1); +gc (); +k1 = {}; +k2 = {}; +gc (); + +var k3 = {}; +m1 = new WeakMap(); +m1.set(k1, "str" + "str"); +m1.set(k2, "str2" + "str2"); +m1.set(k3, "str3" + "str3"); +k1 = undefined; +k2 = undefined; +k3 = undefined; +m1 = undefined; +gc(); + +try { + WeakMap(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + WeakMap.prototype.get.call({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (new WeakMap(null) instanceof WeakMap); + +k1 = {}; +k2 = {}; +m1 = new WeakMap([[k1, 1.2], [k2, 1.3]]); +assert (m1.has (k1)); +assert (m1.has (k2)); +assert (m1.get (k1) === 1.2); +assert (m1.get (k2) === 1.3); +gc(); +m1 = undefined; +gc(); + +m1 = new WeakMap(); +m1.set(k1, "str"); +m1.set(k1, "4"); +m1.set(k1, null); +m1.set(k1, 42); +assert (m1.has (k1)); +k1 = {}; +gc(); + +m1 = new WeakMap(); +m1.set(k1, "str"); +m1.set(k1, "4"); +m1.set(k1, 42); +m1.set(k1, null); +assert (m1.has (k1)); +m1 = new WeakMap(); +gc(); + +try { + new WeakMap([[1,2],[3,4]]); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +var closed = false; +var iter = createIterable([1, 2, 3], { + 'return': function(){ closed = true; return {}; } +}); +try { + new WeakMap(iter); +} catch(e){} + +assert(closed === true); + +m1.set([], []); + +assert (WeakMap.prototype.toString() === "[object WeakMap]"); + +WeakMap.prototype.set = function () { throw "abrupt set" }; + +try { + new WeakMap([[{}, 1]]); + assert (false); +} catch (e) { + assert (e === "abrupt set"); +} + +Object.defineProperty(WeakMap.prototype, 'set', { + get: () => { throw "abrupt set getter" } +}); + +try { + new WeakMap([]); + assert (false); +} catch (e) { + assert (e === "abrupt set getter"); +} diff --git a/tests/jerry/es2015/weakset.js b/tests/jerry/es2015/weakset.js new file mode 100644 index 00000000..d026d1ad --- /dev/null +++ b/tests/jerry/es2015/weakset.js @@ -0,0 +1,168 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var m1 = new WeakSet(); + +var k1 = {}; +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); + +k1 = {}; +gc (); /* This will remove the entry, but there is no way to validate it from js. */ + +assert (m1.has (k1) === false); +assert (m1.delete(k1) === false); +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); + +assert (m1.delete ("str") === false); +assert (m1.has (42) === false); + +try { + m1.add (42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +gc (); +assert (m1.delete(k1) === true); +gc (); +assert (m1.has (k1) === false); +k1 = {}; +gc (); + +Object.freeze(k1); +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); +k1 = {}; +gc (); + +var m2 = new WeakSet(); + +k1 = {}; +gc (); +var k2 = {}; + +m1.add (k1); +m1.add (k2); +m2.add (k1); +m2.add (k2); + +m2.delete (k1); +gc (); +k1 = {}; +k2 = {}; +gc (); + +new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet())))))); +gc(); + +try { + WeakSet(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + WeakSet.prototype.get.call({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (new WeakSet(null) instanceof WeakSet); + +k1 = {}; +k2 = {}; +m1 = new WeakSet([k1, k2]); +assert (m1.has (k1)); +assert (m1.has (k2)); +gc(); +m1 = undefined; +gc(); + +m1 = new WeakSet(); +k1 = {}; +m1.add (k1); +m1.add (k1); +m1.add (k1); +assert (m1.has (k1)); +k1 = {}; +gc(); + +m1 = new WeakSet(); +m1.add (k1); +m1.add (k1); +m1.add (k1); +assert (m1.has (k1)); +m1 = new WeakSet(); +gc(); + +try { + new WeakSet([1,2,3,4]); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +function createIterable(arr, methods = {}) { + let iterable = function *() { + let idx = 0; + while (idx < arr.length) { + yield arr[idx]; + idx++; + } + }(); + iterable['return'] = methods['return']; + iterable['throw'] = methods['throw']; + + return iterable; +}; + +var closed = false; +var iter = createIterable([1, 2, 3], { + 'return': function(){ closed = true; return {}; } +}); +try { + new WeakMap(iter); +} catch(e){} + +assert(closed === true); + +m1.add([]); + +assert (WeakSet.prototype.toString() === "[object WeakSet]"); + +WeakSet.prototype.add = function () { throw "abrupt add" }; + +try { + new WeakSet([{}]); + assert (false); +} catch (e) { + assert (e === "abrupt add"); +} + +Object.defineProperty(WeakSet.prototype, 'add', { + get: () => { throw "abrupt add getter" } +}); + +try { + new WeakSet([]); + assert (false); +} catch (e) { + assert (e === "abrupt add getter"); +} diff --git a/tests/jerry/es5.1/array-prototype-push.js b/tests/jerry/es5.1/array-prototype-push.js new file mode 100644 index 00000000..17db8611 --- /dev/null +++ b/tests/jerry/es5.1/array-prototype-push.js @@ -0,0 +1,34 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var o = { length : 4294967294, push : Array.prototype.push }; +assert(o.push("x") === 4294967295); +assert(o.length === 4294967295); +assert(o[4294967294] === "x"); + +try { + assert(o.push("y") === 4294967296); +} catch (e) { + assert(false); +} +assert(o.length === 4294967296); +assert(o[4294967295] === "y"); + +try { + assert(o.push("z") === 1); +} catch (e) { + assert(false); +} +assert(o.length === 1); +assert(o[0] === "z"); diff --git a/tests/jerry/es5.1/builtin-prototypes.js b/tests/jerry/es5.1/builtin-prototypes.js new file mode 100644 index 00000000..c4be5bfe --- /dev/null +++ b/tests/jerry/es5.1/builtin-prototypes.js @@ -0,0 +1,81 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert (Object.prototype.toString.call (String.prototype) === '[object String]'); +assert (String.prototype.toString() === ""); + +assert (Object.prototype.toString.call (Boolean.prototype) === '[object Boolean]'); +assert (Boolean.prototype.valueOf() === false); + +assert (Object.prototype.toString.call (Number.prototype) === '[object Number]'); +assert (Number.prototype.valueOf() === 0); + +assert (Object.prototype.toString.call (Date.prototype) === '[object Date]'); +assert (isNaN(Date.prototype.valueOf())); + +assert (isNaN (Date.prototype.setTime())); +assert (isNaN (Date.prototype.setMilliseconds())); +assert (isNaN (Date.prototype.setUTCMilliseconds())); +assert (isNaN (Date.prototype.setSeconds())); +assert (isNaN (Date.prototype.setUTCSeconds())); +assert (isNaN (Date.prototype.setMinutes())); +assert (isNaN (Date.prototype.setUTCMinutes())); +assert (isNaN (Date.prototype.setHours())); +assert (isNaN (Date.prototype.setUTCHours())); +assert (isNaN (Date.prototype.setDate())); +assert (isNaN (Date.prototype.getUTCDate())); +assert (isNaN (Date.prototype.setMonth())); +assert (isNaN (Date.prototype.setUTCMonth())); +assert (isNaN (Date.prototype.setFullYear())); +assert (isNaN (Date.prototype.setUTCFullYear())); + +assert (Object.prototype.toString.call (RegExp.prototype) === '[object RegExp]'); + +assert (RegExp.prototype.source === "(?:)"); +assert (RegExp.prototype.global === false); +assert (RegExp.prototype.ignoreCase === false); +assert (RegExp.prototype.multiline === false); + +RegExp.prototype.source = "a"; +RegExp.prototype.global = true; +RegExp.prototype.ignoreCase = true; +RegExp.prototype.multiline = true; +assert (RegExp.prototype.source === "(?:)"); +assert (RegExp.prototype.global === false); +assert (RegExp.prototype.ignoreCase === false); +assert (RegExp.prototype.multiline === false); + +delete RegExp.prototype.source; +delete RegExp.prototype.global; +delete RegExp.prototype.ignoreCase; +delete RegExp.prototype.multiline; +assert (RegExp.prototype.source === "(?:)"); +assert (RegExp.prototype.global === false); +assert (RegExp.prototype.ignoreCase === false); +assert (RegExp.prototype.multiline === false); + +var prototypes = [ + Error.prototype, + EvalError.prototype, + RangeError.prototype, + ReferenceError.prototype, + SyntaxError.prototype, + TypeError.prototype, + URIError.prototype +] + +prototypes.forEach (function (proto) { + assert (Object.prototype.toString.call (proto) === '[object Error]'); +}) diff --git a/tests/jerry/es5.1/func-decl.js b/tests/jerry/es5.1/func-decl.js new file mode 100644 index 00000000..4529e580 --- /dev/null +++ b/tests/jerry/es5.1/func-decl.js @@ -0,0 +1,25 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f() { + return 'foo'; +} +assert ((function() { + if (1 === 0) { + function f() { + return 'bar'; + } + } + return f(); +})() === 'bar'); diff --git a/tests/jerry-test-suite/15/15.03/15.03.03/15.03.03.02/15.03.03.02-001.js b/tests/jerry/es5.1/func-length.js similarity index 95% rename from tests/jerry-test-suite/15/15.03/15.03.03/15.03.03.02/15.03.03.02-001.js rename to tests/jerry/es5.1/func-length.js index 16056111..b8df0170 100644 --- a/tests/jerry-test-suite/15/15.03/15.03.03/15.03.03.02/15.03.03.02-001.js +++ b/tests/jerry/es5.1/func-length.js @@ -16,4 +16,4 @@ var desc = Object.getOwnPropertyDescriptor(Function, "length"); assert(desc.value === 1 && desc.writable === false && desc.enumerable === false && - desc.configurable === false); \ No newline at end of file + desc.configurable === false); diff --git a/tests/jerry/es5.1/object-methods.js b/tests/jerry/es5.1/object-methods.js new file mode 100644 index 00000000..6331d401 --- /dev/null +++ b/tests/jerry/es5.1/object-methods.js @@ -0,0 +1,89 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Object.getOwnPropertyNames("hello"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.preventExtensions(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.isExtensible(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.seal(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.isSealed(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.freeze(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try +{ + Object.isFrozen(42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Object.keys("hello"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Object.getOwnPropertyNames("hello"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Object.getOwnPropertyDescriptor("hello", '1'); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es5.1/regexp-construct.js b/tests/jerry/es5.1/regexp-construct.js new file mode 100644 index 00000000..6f20bb12 --- /dev/null +++ b/tests/jerry/es5.1/regexp-construct.js @@ -0,0 +1,25 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var r = RegExp ("a","gim"); +var r2; + +try { + r2 = RegExp (r,"gim"); + assert(false); +} +catch ( e ) +{ + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es5.1/regexp-routines.js b/tests/jerry/es5.1/regexp-routines.js new file mode 100644 index 00000000..fdd864c5 --- /dev/null +++ b/tests/jerry/es5.1/regexp-routines.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + RegExp.prototype.toString.call ({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/regression-test-issue-1065.js b/tests/jerry/es5.1/regression-test-issue-1065.js similarity index 100% rename from tests/jerry/regression-test-issue-1065.js rename to tests/jerry/es5.1/regression-test-issue-1065.js diff --git a/tests/jerry/regression-test-issue-1080.js b/tests/jerry/es5.1/regression-test-issue-1080.js similarity index 100% rename from tests/jerry/regression-test-issue-1080.js rename to tests/jerry/es5.1/regression-test-issue-1080.js diff --git a/tests/jerry/regression-test-issue-1546.js b/tests/jerry/es5.1/regression-test-issue-1546.js similarity index 100% rename from tests/jerry/regression-test-issue-1546.js rename to tests/jerry/es5.1/regression-test-issue-1546.js diff --git a/tests/jerry/regression-test-issue-1641.js b/tests/jerry/es5.1/regression-test-issue-1641.js similarity index 100% rename from tests/jerry/regression-test-issue-1641.js rename to tests/jerry/es5.1/regression-test-issue-1641.js diff --git a/tests/jerry/regression-test-issue-3151-function.js b/tests/jerry/es5.1/regression-test-issue-3151-function.js similarity index 100% rename from tests/jerry/regression-test-issue-3151-function.js rename to tests/jerry/es5.1/regression-test-issue-3151-function.js diff --git a/tests/jerry/es5.1/regression-test-issue-3637.js b/tests/jerry/es5.1/regression-test-issue-3637.js new file mode 100644 index 00000000..0306500a --- /dev/null +++ b/tests/jerry/es5.1/regression-test-issue-3637.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a = [1, 2, 3, 4]; +var b = a.slice(0, { valueOf: function(){ a.length = 0; return 100; } }); + +assert(b.length === 0); + +var c = [1, 2, 3, 4]; +c.prop = 4 +var d = c.slice(0, { valueOf: function(){ c.length = 0; return 100; } }); + +assert(d.length === 0); diff --git a/tests/jerry/regression-test-issue-787.js b/tests/jerry/es5.1/regression-test-issue-787.js similarity index 100% rename from tests/jerry/regression-test-issue-787.js rename to tests/jerry/es5.1/regression-test-issue-787.js diff --git a/tests/jerry/es5.1/string-prototype-split.js b/tests/jerry/es5.1/string-prototype-split.js new file mode 100644 index 00000000..27cc79cb --- /dev/null +++ b/tests/jerry/es5.1/string-prototype-split.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = "foo//bar/baz//foo"; +res = str.split("a", Infinity); +assert (res.length === 0); + +res = str.split(/\/\//, -1); +assert (res.length === 3); +assert (res[0] === "foo"); +assert (res[1] === "bar/baz"); +assert (res[2] === "foo"); diff --git a/tests/jerry/es5.1/string-regexp-methods.js b/tests/jerry/es5.1/string-regexp-methods.js new file mode 100644 index 00000000..6e6c2e17 --- /dev/null +++ b/tests/jerry/es5.1/string-regexp-methods.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Changing exec should not affect replace. +Object.getPrototypeOf(/x/).exec = function () { return 1234; } +assert (/y/.exec("y") === 1234); + +assert ("y".replace (/y/, "x") === "x"); +assert ("ay".search (/y/) === 1); diff --git a/tests/jerry/es5.1/try-catch.js b/tests/jerry/es5.1/try-catch.js new file mode 100644 index 00000000..bfd31081 --- /dev/null +++ b/tests/jerry/es5.1/try-catch.js @@ -0,0 +1,26 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f() { + try { + assert(e() == 6) + throw 8; + assert(false); + } catch (e) { + function e() { return 6 } + assert(e == 8); + } +} + +f(); diff --git a/tests/jerry/eval-with.js b/tests/jerry/eval-with.js new file mode 100644 index 00000000..59422217 --- /dev/null +++ b/tests/jerry/eval-with.js @@ -0,0 +1,53 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f() { + try { + a; + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } + + var o = { a:1 }; + + with (o) + { + eval("var a = 2") + } + + assert (o.a === 2); + assert (a === undefined); +} +f(); + +function g() { + try { + a; + assert (false); + } catch (e) { + assert (e instanceof ReferenceError); + } + + var o = { a:1 }; + + with (o) + { + eval("function a() { return 8; }") + } + + assert (o.a === 1); + assert (a() === 8); +} +g(); diff --git a/tests/jerry/eval.js b/tests/jerry/eval.js index 4d0c4b60..b5974b18 100644 --- a/tests/jerry/eval.js +++ b/tests/jerry/eval.js @@ -122,3 +122,40 @@ catch(e) code = 'eval("(function (){})")'; code = "eval ('" + code + "')"; eval (code); + +// Eval enclosed in brackets is still an eval. +var p1 = 0; + +function f3() { + var p1 = 5; + (eval)("assert(p1 === 5)"); +} +f3(); + +function f4() { + var p1 = 6; + ((eval))("assert(p1 === 6)"); +} +f4(); + +function f5() { + var p1 = 7; + (((((eval)))("assert(p1 === 7)"))); +} +f5(); + +function f6() { + var p1 = 8; + var e = eval; + + e("assert(p1 === 0)"); + (((((e)))("assert(p1 === 0)"))); +} +f6(); + +y = 1; +function f7() { + function x() { return y; } + eval("assert(x()() === 5); function y() { return 5 } assert(x()() === 5)"); +} +f7() diff --git a/tests/jerry/fail/module-032.js b/tests/jerry/fail/module-032.js new file mode 100644 index 00000000..c4256330 --- /dev/null +++ b/tests/jerry/fail/module-032.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let a; +import { a } from "../es2015/module-export-fail-test.js"; diff --git a/tests/jerry/fail/module-033.js b/tests/jerry/fail/module-033.js new file mode 100644 index 00000000..467b5640 --- /dev/null +++ b/tests/jerry/fail/module-033.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a; +import { a } from "../es2015/module-export-fail-test.js"; diff --git a/tests/jerry/fail/module-034.js b/tests/jerry/fail/module-034.js new file mode 100644 index 00000000..a0298c1c --- /dev/null +++ b/tests/jerry/fail/module-034.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { a } from "../es2015/module-export-fail-test.js"; +class a {}; diff --git a/tests/jerry/fail/module-035.js b/tests/jerry/fail/module-035.js new file mode 100644 index 00000000..411b6c62 --- /dev/null +++ b/tests/jerry/fail/module-035.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { a } from "../es2015/module-export-fail-test.js"; +function a() {} diff --git a/tests/jerry/regression-test-issue-1387.js b/tests/jerry/fail/regression-test-issue-1387.js similarity index 100% rename from tests/jerry/regression-test-issue-1387.js rename to tests/jerry/fail/regression-test-issue-1387.js diff --git a/tests/jerry/es2015/regression-test-issue-2819.js b/tests/jerry/fail/regression-test-issue-2819.js similarity index 100% rename from tests/jerry/es2015/regression-test-issue-2819.js rename to tests/jerry/fail/regression-test-issue-2819.js diff --git a/tests/jerry/fail/regresssion-test-issue-3121.js b/tests/jerry/fail/regression-test-issue-3121.js similarity index 100% rename from tests/jerry/fail/regresssion-test-issue-3121.js rename to tests/jerry/fail/regression-test-issue-3121.js diff --git a/tests/jerry/es2015/regression-test-issue-3123.js b/tests/jerry/fail/regression-test-issue-3123.js similarity index 100% rename from tests/jerry/es2015/regression-test-issue-3123.js rename to tests/jerry/fail/regression-test-issue-3123.js diff --git a/tests/jerry/fail/regresssion-test-issue-3145.js b/tests/jerry/fail/regression-test-issue-3145.js similarity index 100% rename from tests/jerry/fail/regresssion-test-issue-3145.js rename to tests/jerry/fail/regression-test-issue-3145.js diff --git a/tests/jerry/fail/regresssion-test-issue-3152.js b/tests/jerry/fail/regression-test-issue-3152.js similarity index 100% rename from tests/jerry/fail/regresssion-test-issue-3152.js rename to tests/jerry/fail/regression-test-issue-3152.js diff --git a/tests/jerry/fail/regression-test-issue-3253-1.js b/tests/jerry/fail/regression-test-issue-3253-1.js new file mode 100644 index 00000000..299cdb93 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3253-1.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a; +export { a diff --git a/tests/jerry/fail/regression-test-issue-3253-2.js b/tests/jerry/fail/regression-test-issue-3253-2.js new file mode 100644 index 00000000..2f8c563a --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3253-2.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var a, b; +export { a as b diff --git a/tests/jerry/fail/regression-test-issue-3275.js b/tests/jerry/fail/regression-test-issue-3275.js new file mode 100644 index 00000000..99f10326 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3275.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +for ( i in this ) class ${ } eval ( ) diff --git a/tests/jerry/fail/regression-test-issue-3276.js b/tests/jerry/fail/regression-test-issue-3276.js new file mode 100644 index 00000000..5c25208e --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3276.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +with ({ }) class ${ $( ) { $ } } diff --git a/tests/jerry/fail/regression-test-issue-3297.js b/tests/jerry/fail/regression-test-issue-3297.js new file mode 100644 index 00000000..cf3a84f7 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3297.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +"98765".replace(76, function ( ) { return $ }) diff --git a/tests/jerry/fail/regression-test-issue-3299.js b/tests/jerry/fail/regression-test-issue-3299.js new file mode 100644 index 00000000..98fa21b8 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3299.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f (a, b = $+ function ( ) { } ( ), $) { } +var $ = { $: function ($) { }} +f( ) + +function duplicatedArg ( a , b = d , c ) { + try { + var eval + var id_1 + if ( id_2 === eval ( ) ) { } + } finally { } +} + +duplicatedArg(1, 2) diff --git a/tests/jerry/fail/regression-test-issue-3300.js b/tests/jerry/fail/regression-test-issue-3300.js new file mode 100644 index 00000000..0ecfbfdf --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3300.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +y = 6 +function i ( a , b = ( y ) + 2 , c = typeof id_0 ) { + function x ( ) { } + eval ( "//Single Line Comments\u2029 var =;" ) + c === "undefined" + print ( y === 10 ) + ( id_2 === 11 ) +} +i ( ) diff --git a/tests/jerry/fail/regression-test-issue-3394.js b/tests/jerry/fail/regression-test-issue-3394.js new file mode 100644 index 00000000..ec65f25e --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3394.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +class Animal { } + +class Dog extends Animal { + static explain() { + super.explain(...[]) + } +} + +Dog.explain() diff --git a/tests/jerry/fail/regression-test-issue-3398.js b/tests/jerry/fail/regression-test-issue-3398.js new file mode 100644 index 00000000..367b1f4b --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3398.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function f($, [ + [b, [c] = [], {} = { + $: eval() + }] +] = [[]], c) {} +f() diff --git a/tests/jerry/fail/regression-test-issue-3410.js b/tests/jerry/fail/regression-test-issue-3410.js new file mode 100644 index 00000000..b41575e5 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3410.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +var a; +Promise.race([a]).then(function() { + [] = [] +}); +throw 0.1234; diff --git a/tests/jerry/fail/regression-test-issue-3554.js b/tests/jerry/fail/regression-test-issue-3554.js new file mode 100644 index 00000000..4f01e94a --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3554.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +(function(){try{}catch(e){function e diff --git a/tests/jerry/fail/regression-test-issue-3714.js b/tests/jerry/fail/regression-test-issue-3714.js new file mode 100644 index 00000000..8022eac8 --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3714.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function $() { + if ($) + function +} diff --git a/tests/jerry/fail/regression-test-issue-3735.js b/tests/jerry/fail/regression-test-issue-3735.js new file mode 100644 index 00000000..513df9cc --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3735.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function $({ $ $() {} diff --git a/tests/jerry/fail/regression-test-issue-3882.js b/tests/jerry/fail/regression-test-issue-3882.js new file mode 100644 index 00000000..1008888c --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-3882.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +for(let{[function(){}]:{}} = ()=>{} in []) ; diff --git a/tests/jerry/for-in.js b/tests/jerry/for-in.js index 84ef4e7f..c06b6c31 100644 --- a/tests/jerry/for-in.js +++ b/tests/jerry/for-in.js @@ -281,3 +281,11 @@ assert(count == 1 || 'base_prop2' in log || 'derived_prop1' in log || 'derived_prop2' in log)); + +try { + /* This form is a SyntaxError even in ES5.1. */ + eval("for (a = b in {}) ;"); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +} diff --git a/tests/jerry/func-decl.js b/tests/jerry/func-decl.js index 6be92e27..186fa785 100644 --- a/tests/jerry/func-decl.js +++ b/tests/jerry/func-decl.js @@ -16,7 +16,7 @@ function f() { return 'foo'; } assert ((function() { - if (1 === 0) { + if (1 === 1) { function f() { return 'bar'; } diff --git a/tests/jerry/function-construct.js b/tests/jerry/function-construct.js index d04935a6..5239429c 100644 --- a/tests/jerry/function-construct.js +++ b/tests/jerry/function-construct.js @@ -29,6 +29,10 @@ catch (e) assert (e instanceof ReferenceError); } +var singleArgFunction = new Function ('arg', 'return arg'); + +assert (singleArgFunction (5) === 5); + for (i = 1; i < 10; i ++) { var f = new Function ('a', 'b', 'var q = a; b++; function f (k) {return q + k + b++;}; return f;'); diff --git a/tests/jerry/function-external.js b/tests/jerry/function-external.js index d6eae392..b1cc8c31 100644 --- a/tests/jerry/function-external.js +++ b/tests/jerry/function-external.js @@ -12,15 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -try { - ({} instanceof assert); - assert(false); -} catch(e) { - assert(e instanceof TypeError); -} - -assert.prototype = {} - try { assert(!({} instanceof assert)); } catch(e) { diff --git a/tests/jerry/getter-setter-this-value.js b/tests/jerry/getter-setter-this-value.js index 217e9f07..a34e1aea 100644 --- a/tests/jerry/getter-setter-this-value.js +++ b/tests/jerry/getter-setter-this-value.js @@ -32,3 +32,19 @@ Object.defineProperty(Box.prototype, 'data', { assert(box.data === '='); box.data = '+'; assert(box.data === '+'); + +function test_access(value, proto) { + "use strict" + + Object.defineProperty(proto, 'test', { + get: function () { assert (this === value) }, + set: function () { assert (this === value) } + }); + + value.test; + value.test = undefined; +} + +test_access ("str", String.prototype); +test_access (1, Number.prototype); +test_access (true, Boolean.prototype); diff --git a/tests/jerry/keyword.js b/tests/jerry/keyword.js new file mode 100644 index 00000000..558d2533 --- /dev/null +++ b/tests/jerry/keyword.js @@ -0,0 +1,47 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_syntax_error(code) +{ + try { + eval(code) + assert(false) + } catch (e) { + assert(e instanceof SyntaxError) + } +} + +function check_strict_syntax_error(code) +{ + "use strict" + + try { + eval(code) + assert(false) + } catch (e) { + assert(e instanceof SyntaxError) + } +} + +check_syntax_error("d\\u006f {} while (false)") +check_syntax_error("\\u0076\\u0061\\u0072 var = 5") +check_syntax_error("wit\\u0068 ({}) {}") +check_syntax_error("\\u0066alse") +check_syntax_error("type\\006ff 3.14") +check_syntax_error("try {} fin\\u0061lly {}") +check_syntax_error("f\\u0075nction f() {}") +check_syntax_error("a instanc\\u0065of b") + +check_strict_syntax_error("\\u006c\\u0065\\u0074 _let = 5"); +check_strict_syntax_error("\\u0070rotecte\\u0064"); diff --git a/tests/jerry/large_literal.js b/tests/jerry/large_literal.js new file mode 100644 index 00000000..78bd3616 --- /dev/null +++ b/tests/jerry/large_literal.js @@ -0,0 +1,34 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var literal = "a" + +for (var i = 0; i < 25; i++) + literal += "\\u0061bcdefghij" + +assert(eval("var " + literal + " = 42; " + literal) === 42) + +literal = undefined + +var str = "" +var expected = "" + +for (var i = 0; i < 1000; i++) +{ + str += "123456789\\n" + expected += "123456789\n" +} + +assert(eval('"' + str + '"') === expected); + diff --git a/tests/jerry/math-functions-tonumber-rule.js b/tests/jerry/math-functions-tonumber-rule.js new file mode 100644 index 00000000..36f7524d --- /dev/null +++ b/tests/jerry/math-functions-tonumber-rule.js @@ -0,0 +1,33 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var str = ""; +var a = {valueOf: function() { str += "a"; return 1;}}; +var b = {valueOf: function() { str += "b"; return NaN;}}; +var c = {valueOf: function() { str += "c"; return 2;}}; + +Math.min (a, b, c); +assert (str === "abc"); + +str = ""; +Math.max (a, b, c); +assert (str === "abc"); + +str = ""; +Math.pow(b,a); +assert (str === "ba"); + +str = ""; +Math.atan2(b,a); +assert (str === "ba"); diff --git a/tests/jerry/math-round.js b/tests/jerry/math-round.js index 36f1fdb3..fe1aa9c0 100644 --- a/tests/jerry/math-round.js +++ b/tests/jerry/math-round.js @@ -35,3 +35,17 @@ assert (Math['round'](-0.7) === -1.0); assert (Math['round'](-1.2) === -1.0); assert (Math['round'](-1.7) === -2.0); assert (Math['round'](-1.5) === -1.0); + +assert (Math['round'](1) === 1); +assert (Math['round'](-1) === -1); + +for (var n = 1; n <= 53; n++) +{ + var x = Math.pow(2, n) + assert (Math['round'](x - 1) === x - 1); + assert (Math['round'](x) === x); + assert (Math['round'](x + 1) === x + 1); + assert (Math['round'](-x - 1) === -x - 1); + assert (Math['round'](-x) === -x); + assert (Math['round'](-x + 1) === -x + 1); +} diff --git a/tests/jerry/number-prototype-to-fixed.js b/tests/jerry/number-prototype-to-fixed.js index 67d5ed1b..637296cd 100644 --- a/tests/jerry/number-prototype-to-fixed.js +++ b/tests/jerry/number-prototype-to-fixed.js @@ -63,3 +63,35 @@ try { } catch (e) { assert(e instanceof RangeError) } + +assert ((0.5).toFixed(0) === "1"); +assert ((1.5).toFixed(0) === "2"); +assert ((12.5).toFixed(0) === "13"); +assert ((123.5).toFixed(0) === "124"); +assert ((1234.5).toFixed(0) === "1235"); +assert ((0.567).toFixed(0) === "1"); +assert ((1.567).toFixed(0) === "2"); +assert ((12.567).toFixed(0) === "13"); +assert ((123.567).toFixed(0) === "124"); +assert ((1234.567).toFixed(0) === "1235"); + +assert ((1.2567).toFixed(0) === "1"); +assert ((1.2567).toFixed(1) === "1.3"); +assert ((1.2567).toFixed(2) === "1.26"); +assert ((1.2567).toFixed(3) === "1.257"); +assert ((1.2567).toFixed(4) === "1.2567"); +assert ((1.2567).toFixed(5) === "1.25670"); + +assert ((12.3567).toFixed(0) === "12"); +assert ((12.3567).toFixed(1) === "12.4"); +assert ((12.3567).toFixed(2) === "12.36"); +assert ((12.3567).toFixed(3) === "12.357"); +assert ((12.3567).toFixed(4) === "12.3567"); +assert ((12.3567).toFixed(5) === "12.35670"); + +assert ((123.4567).toFixed(0) === "123"); +assert ((123.4567).toFixed(1) === "123.5"); +assert ((123.4567).toFixed(2) === "123.46"); +assert ((123.4567).toFixed(3) === "123.457"); +assert ((123.4567).toFixed(4) === "123.4567"); +assert ((123.4567).toFixed(5) === "123.45670"); diff --git a/tests/jerry/object-defineproperty.js b/tests/jerry/object-defineproperty.js index 6988f1ab..ed37dde8 100644 --- a/tests/jerry/object-defineproperty.js +++ b/tests/jerry/object-defineproperty.js @@ -68,3 +68,12 @@ try { } catch (err) { assert (err === 234); } + +try { + Object.defineProperty(42, "prop", { + set: undefined + }); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/object-get-own-property-names.js b/tests/jerry/object-get-own-property-names.js index f6dfb9fb..0cb4ac2c 100644 --- a/tests/jerry/object-get-own-property-names.js +++ b/tests/jerry/object-get-own-property-names.js @@ -62,11 +62,3 @@ assert (props.indexOf("prop") !== -1); assert (props.indexOf("method") !== -1); assert (props.length === 2); - -// Test non-object argument -try { - Object.getOwnPropertyNames("hello"); - assert (false); -} catch (e) { - assert (e instanceof TypeError); -} diff --git a/tests/jerry/object-is-extensible.js b/tests/jerry/object-is-extensible.js index f3e96b5e..5ecfd602 100644 --- a/tests/jerry/object-is-extensible.js +++ b/tests/jerry/object-is-extensible.js @@ -20,23 +20,6 @@ assert (Object.isExtensible(empty) === true); Object.preventExtensions(empty); assert(Object.isExtensible(empty) === false); -// Call on undefined should throw TypeError. -try -{ - Object.isExtensible(undefined); - assert (false); -} catch (e) { - assert (e instanceof TypeError); -} - -try -{ - Object.preventExtensions(undefined); - assert (false); -} catch (e) { - assert (e instanceof TypeError); -} - // Sealed objects are by definition non-extensible. var sealed = Object.seal({}); assert (Object.isExtensible(sealed) === false); diff --git a/tests/jerry/object-keys.js b/tests/jerry/object-keys.js index 4ebae687..e359233f 100644 --- a/tests/jerry/object-keys.js +++ b/tests/jerry/object-keys.js @@ -61,14 +61,6 @@ assert (props.indexOf("prop") !== -1); assert (props.indexOf("method") !== -1); assert (props.length === 2); -// Test non-object argument -try { - Object.keys("hello"); - assert (false); -} catch (e) { - assert (e instanceof TypeError); -} - var o = {}; Object.defineProperty(o, 'a', { diff --git a/tests/jerry/regexp-alternatives.js b/tests/jerry/regexp-alternatives.js index d084d459..379702c3 100644 --- a/tests/jerry/regexp-alternatives.js +++ b/tests/jerry/regexp-alternatives.js @@ -58,3 +58,6 @@ assert (r.exec("a") == "a"); r = new RegExp ("a|bb|c|d"); assert (r.exec("b") == undefined); + +r = new RegExp("(?:a|b)\\b|\\.\\w+", "g"); +assert (r.exec("name.lower()")[0] === ".lower") diff --git a/tests/jerry/regexp-backreference.js b/tests/jerry/regexp-backreference.js index 2551cd54..55b92f36 100644 --- a/tests/jerry/regexp-backreference.js +++ b/tests/jerry/regexp-backreference.js @@ -24,3 +24,6 @@ assert (r == undefined); r = new RegExp ("(a)*b\\1").exec("b"); assert (r[0] == "b"); assert (r[1] == undefined); + +assert (JSON.stringify (/[[]?(a)\1/.exec("aa")) === '["aa","a"]'); +assert (JSON.stringify (/\1{2,5}()\B/.exec("asd")) === '["",""]'); diff --git a/tests/jerry/regexp-backtrack.js b/tests/jerry/regexp-backtrack.js new file mode 100644 index 00000000..3099fe78 --- /dev/null +++ b/tests/jerry/regexp-backtrack.js @@ -0,0 +1,115 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (JSON.stringify (/(?:(a)*){3,}/.exec("aaaab")) === '["aaaa",null]'); +assert (JSON.stringify (/((a)*){3,}/.exec("aaaab")) === '["aaaa","",null]'); +assert (JSON.stringify (/((a)+){3,}/.exec("aaaab")) === '["aaaa","a","a"]'); +assert (JSON.stringify (/((.)*){3,}/.exec("abcd")) === '["abcd","",null]'); +assert (JSON.stringify (/((.)+){3,}/.exec("abcd")) === '["abcd","d","d"]'); + +assert (JSON.stringify (/((.){1,2}){1,2}/.exec("abc")) === '["abc","c","c"]'); +assert (JSON.stringify (/(?:(a)*?)asd/.exec("aaasd")) === '["aaasd","a"]'); +assert (JSON.stringify (/(?:(a)*)asd/.exec("aaasd")) === '["aaasd","a"]'); + +assert (JSON.stringify (/(.)*((a)*|(b)*)/.exec("ab")) === '["ab","b","",null,null]'); +assert (JSON.stringify (/(.)*((x)|(y))+/.exec("xy")) === '["xy","x","y",null,"y"]'); +assert (JSON.stringify (/(.)*((y)|(x))+/.exec("xy")) === '["xy","x","y","y",null]'); + +assert (JSON.stringify (/((?:a)*)/.exec("aaaad")) === '["aaaa","aaaa"]'); +assert (JSON.stringify (/((y)+|x)+/.exec("x")) === '["x","x",null]'); +assert (JSON.stringify (/((?:y)*|x)+/.exec("x")) === '["x","x"]'); +assert (JSON.stringify (/((y)*|x)+/.exec("x")) === '["x","x",null]'); +assert (JSON.stringify (/((y)*|x)*/.exec("x")) === '["x","x",null]'); +assert (JSON.stringify (/(?:(y)*|x)*/.exec("x")) === '["x",null]'); +assert (JSON.stringify (/(?:(y)*|(x))*/.exec("x")) === '["x",null,"x"]'); + +assert (JSON.stringify (/((?:a)*)asd/.exec("aaasd")) === '["aaasd","aa"]'); +assert (JSON.stringify (/((?:a)+)asd/.exec("aaasd")) === '["aaasd","aa"]'); +assert (JSON.stringify (/((?:a)*?)asd/.exec("aaasd")) === '["aaasd","aa"]'); +assert (JSON.stringify (/((?:a)+?)asd/.exec("aaasd")) === '["aaasd","aa"]'); + +assert (JSON.stringify (/((y)|(z)|(a))*/.exec("yazx")) === '["yaz","z",null,"z",null]'); +assert (JSON.stringify (/((y)|(z)|(.))*/.exec("yaz")) === '["yaz","z",null,"z",null]'); +assert (JSON.stringify (/((y)*|(z)*|(a)*)*/.exec("yazx")) === '["yaz","z",null,"z",null]') +assert (JSON.stringify (/((y)|(z)|(a))*/.exec("yazx")) === '["yaz","z",null,"z",null]') +assert (JSON.stringify (/(?:(y)|(z)|(a))*/.exec("yazx")) === '["yaz",null,"z",null]') +assert (JSON.stringify (/((y)|(z)|(a))+?/.exec("yazx")) === '["y","y","y",null,null]') +assert (JSON.stringify (/(?:(y)|(z)|(a))+?/.exec("yazx")) === '["y","y",null,null]') + +assert (JSON.stringify (/(?:(x|y)*|z)*/.exec("yz")) === '["yz",null]'); +assert (JSON.stringify (/((x|y)*|z)*/.exec("yz")) == '["yz","z",null]'); +assert (JSON.stringify (/(((x|y)*|(v|w)*|z)*)asd/.exec("xyzwvxzasd")) === '["xyzwvxzasd","xyzwvxz","z",null,null]'); + +assert (JSON.stringify (/((a)*){1,3}b/.exec("ab")) === '["ab","a","a"]') +assert (JSON.stringify (/((a)*){2,3}b/.exec("ab")) === '["ab","",null]') +assert (JSON.stringify (/((a)*){3,3}b/.exec("ab")) === '["ab","",null]') + +assert (JSON.stringify (/((a)*){3,}b/.exec("aaaab")) === '["aaaab","",null]'); +assert (JSON.stringify (/((a)*)*b/.exec("aaaab")) === '["aaaab","aaaa","a"]'); + +assert (JSON.stringify (/((bb?)*)*a/.exec("bbba")) === '["bbba","bbb","b"]'); +assert (JSON.stringify (/((b)*)*a/.exec("bbba")) === '["bbba","bbb","b"]'); + +assert (JSON.stringify (/(aa|a)a/.exec("aa")) === '["aa","a"]'); +assert (JSON.stringify (/(aa|a)?a/.exec("aa")) === '["aa","a"]'); +assert (JSON.stringify (/(aa|a)+?a/.exec("aa")) === '["aa","a"]'); +assert (JSON.stringify (/(?:aa|a)a/.exec("aa")) === '["aa"]'); +assert (JSON.stringify (/(?:aa|a)?a/.exec("aa")) === '["aa"]'); +assert (JSON.stringify (/(?:aa|a)+?a/.exec("aa")) === '["aa"]'); + +assert (JSON.stringify (/(aa|a)a/.exec("a")) === 'null'); +assert (JSON.stringify (/(aa|a)?a/.exec("a")) === '["a",null]'); +assert (JSON.stringify (/(aa|a)+?a/.exec("a")) === 'null'); +assert (JSON.stringify (/(?:aa|a)a/.exec("a")) === 'null'); +assert (JSON.stringify (/(?:aa|a)?a/.exec("a")) === '["a"]'); +assert (JSON.stringify (/(?:aa|a)+?a/.exec("a")) === 'null'); + +assert (JSON.stringify (/a+/.exec("aaasd")) === '["aaa"]'); +assert (JSON.stringify (/a+?/.exec("aaasd")) === '["a"]'); + +assert (JSON.stringify (/a+sd/.exec("aaasd")) === '["aaasd"]'); +assert (JSON.stringify (/a+?sd/.exec("aaasd")) === '["aaasd"]'); + +assert (JSON.stringify (/a{2}sd/.exec("aaasd")) === '["aasd"]'); +assert (JSON.stringify (/a{3}sd/.exec("aaasd")) === '["aaasd"]'); + +assert (JSON.stringify (/(?=a)/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?=a)+/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?=a)*/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?=(a))?/.exec("a")) === '["",null]'); +assert (JSON.stringify (/(?=(a))+?/.exec("a")) === '["","a"]'); +assert (JSON.stringify (/(?=(a))*?/.exec("a")) === '["",null]'); + +assert (JSON.stringify (/(?!a)/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?!a)+/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?!a)*/.exec("a")) === '[""]'); +assert (JSON.stringify (/(?!(a))?/.exec("a")) === '["",null]'); +assert (JSON.stringify (/(?!(a))+?/.exec("a")) === '["",null]'); +assert (JSON.stringify (/(?!(a))*?/.exec("a")) === '["",null]'); + +assert (JSON.stringify (/al(?=(ma))*ma/.exec("alma")) === '["alma",null]'); +assert (JSON.stringify (/al(?!(ma))*ma/.exec("alma")) === '["alma",null]'); +assert (JSON.stringify (/al(?=(ma))+ma/.exec("alma")) === '["alma","ma"]'); +assert (JSON.stringify (/al(?!(ma))+ma/.exec("alma")) === 'null'); + +assert (JSON.stringify (/(?=())x|/.exec("asd")) === '["",null]'); +assert (JSON.stringify (/(?!())x|/.exec("asd")) === '["",null]'); + +assert (JSON.stringify (/(().*)+.$/.exec("abcdefg")) === '["abcdefg","abcdef",""]'); +assert (JSON.stringify (/(().*)+?.$/.exec("abcdefg")) === '["abcdefg","abcdef",""]'); +assert (JSON.stringify (/(?:().*)+.$/.exec("abcdefg")) === '["abcdefg",""]'); +assert (JSON.stringify (/(?:().*)+?.$/.exec("abcdefg")) === '["abcdefg",""]'); + +assert (JSON.stringify(/((?=())|.)+^/.exec("a")) === '["","",""]'); +assert (JSON.stringify(/(?:(|\b\w+?){2})+$/.exec("aaaa")) === '["aaaa","aaaa"]'); diff --git a/tests/jerry/regexp-capture-groups.js b/tests/jerry/regexp-capture-groups.js index 801e062a..c3644d56 100644 --- a/tests/jerry/regexp-capture-groups.js +++ b/tests/jerry/regexp-capture-groups.js @@ -196,3 +196,12 @@ assert (r.exec("aa") == "aa,a"); r = new RegExp ("(a{0,1}?){0,1}a"); assert (r.exec("aa") == "aa,a"); + +r = new RegExp ("(|.)+"); +assert (JSON.stringify (r.exec("asdfgh")) === '["asdfgh","h"]'); + +assert (JSON.stringify (/([^\W](){8,}?){5}/.exec("asdfghijk")) === '["asdfg","g",""]'); +assert (JSON.stringify (/(()+?(.+)|){3,}./u.exec("asdfghi")) === '["asdfghi","",null,null]') +assert (JSON.stringify (/(()+?(.+)|){3,}?./u.exec("asdfghi")) === '["asdfghi","",null,null]') +assert (JSON.stringify (/(?:()+?(.+)|){3,}./u.exec("asdfghi")) === '["asdfghi",null,null]') +assert (JSON.stringify (/(?:()+?(.+)|){3,}?./u.exec("asdfghi")) === '["asdfghi",null,null]') diff --git a/tests/jerry/regexp-construct.js b/tests/jerry/regexp-construct.js index 4aa7c807..e33dbc8b 100644 --- a/tests/jerry/regexp-construct.js +++ b/tests/jerry/regexp-construct.js @@ -45,14 +45,6 @@ assert (r.ignoreCase == true); assert (r.multiline == true); var r2; -try { - r2 = RegExp (r,"gim"); - assert(false); -} -catch ( e ) -{ - assert (e instanceof TypeError); -} r2 = RegExp (r); assert (r2.source == "a"); @@ -84,8 +76,6 @@ assert (r.global == true); assert (r.ignoreCase == true); assert (r.multiline == true); -assert(Object.prototype.toString.call(RegExp.prototype) === '[object RegExp]'); - /* The 'undefined' argument for the RegExp constructor should not be converted to string, * and it should behave just like when there is no argument. */ @@ -138,25 +128,3 @@ assert (r.multiline == false); /* RegExp properties */ assert (RegExp.length === 2); -assert (RegExp.prototype.source === "(?:)"); -assert (RegExp.prototype.global === false); -assert (RegExp.prototype.ignoreCase === false); -assert (RegExp.prototype.multiline === false); - -RegExp.prototype.source = "a"; -RegExp.prototype.global = true; -RegExp.prototype.ignoreCase = true; -RegExp.prototype.multiline = true; -assert (RegExp.prototype.source === "(?:)"); -assert (RegExp.prototype.global === false); -assert (RegExp.prototype.ignoreCase === false); -assert (RegExp.prototype.multiline === false); - -delete RegExp.prototype.source; -delete RegExp.prototype.global; -delete RegExp.prototype.ignoreCase; -delete RegExp.prototype.multiline; -assert (RegExp.prototype.source === "(?:)"); -assert (RegExp.prototype.global === false); -assert (RegExp.prototype.ignoreCase === false); -assert (RegExp.prototype.multiline === false); diff --git a/tests/jerry/regexp-routines.js b/tests/jerry/regexp-routines.js index 00e328a2..33b533d9 100644 --- a/tests/jerry/regexp-routines.js +++ b/tests/jerry/regexp-routines.js @@ -39,15 +39,6 @@ catch (e) r = new RegExp ("a", "mig"); assert (r.toString () == "/a/gim"); -try { - r.toString.call({}, "a"); - assert (false) -} -catch (e) -{ - assert (e instanceof TypeError); -} - /* Test continous calls to the exec method to see how does the match * updates the lastIndex propertyand see if the match restarts. diff --git a/tests/jerry/regexp-simple-atom-and-iterations.js b/tests/jerry/regexp-simple-atom-and-iterations.js index c1f15da9..19cf7010 100644 --- a/tests/jerry/regexp-simple-atom-and-iterations.js +++ b/tests/jerry/regexp-simple-atom-and-iterations.js @@ -88,3 +88,6 @@ assert (r.exec ("\\c3") == "\\c3"); r = /\cIasd/; assert (r.exec ("\tasd") == "\tasd"); + +r = /.??$/; +assert (JSON.stringify (r.exec("asd")) === '["d"]'); diff --git a/tests/jerry/regexp-web-compatibility.js b/tests/jerry/regexp-web-compatibility.js new file mode 100644 index 00000000..ffe0a97d --- /dev/null +++ b/tests/jerry/regexp-web-compatibility.js @@ -0,0 +1,193 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function test_match(re, input, expected) +{ + var result = re.exec(input); + + if (expected === null) + { + assert (result === null); + return; + } + + assert (result !== null); + assert (result.length === expected.length); + + for (var idx = 0; idx < result.length; idx++) + { + assert (result[idx] === expected[idx]); + } +} + +test_match (new RegExp ("A{1,2}"), "B", null); +test_match (new RegExp ("A{1,2}"), "", null); +test_match (new RegExp ("A{1,2}"), "A", ["A"]); +test_match (new RegExp ("A{1,2}"), "AA", ["AA"]); +test_match (new RegExp ("A{1,2}"), "AAA", ["AA"]); + +test_match (new RegExp ("A{1,}"), "B", null); +test_match (new RegExp ("A{1,}"), "GA", ["A"]); +test_match (new RegExp ("A{1,}"), "FAAAW", ["AAA"]); +test_match (new RegExp ("A{1,}"), "FAdAAW", ["A"]); + +/* Test web compatiblity (ES2015 Annex B 1.4) */ + +test_match (new RegExp ("A{1,2"), "A", null); +test_match (new RegExp ("A{1,2"), "AA", null); +test_match (new RegExp ("A{1,2"), "A{1,2", ["A{1,2"]); +test_match (new RegExp ("A{1,2"), "AA{1,2", ["A{1,2"]); + +test_match (new RegExp ("A{1,"), "A", null); +test_match (new RegExp ("A{1,"), "AA", null); +test_match (new RegExp ("A{1,"), "A{1,", ["A{1,"]); +test_match (new RegExp ("A{1,"), "A{1,2", ["A{1,"]); +test_match (new RegExp ("A{1,"), "AA{1,2", ["A{1,"]); + +test_match (new RegExp ("A{1"), "A", null); +test_match (new RegExp ("A{1"), "AA", null); +test_match (new RegExp ("A{1"), "A{1,", ["A{1"]); +test_match (new RegExp ("A{1"), "A{1,2", ["A{1"]); +test_match (new RegExp ("A{1"), "AA{1,2", ["A{1"]); + +test_match (new RegExp ("A{"), "A", null); +test_match (new RegExp ("A{"), "AA", null); +test_match (new RegExp ("A{"), "A{,", ["A{"]); +test_match (new RegExp ("A{"), "A{1,", ["A{"]); +test_match (new RegExp ("A{"), "A{1,2", ["A{"]); +test_match (new RegExp ("A{"), "AA{1,2", ["A{"]); + +test_match (new RegExp ("{"), "", null); +test_match (new RegExp ("{"), "AA", null); +test_match (new RegExp ("{"), "{,", ["{"]); +test_match (new RegExp ("{"), "{1,", ["{"]); +test_match (new RegExp ("{"), "{1,2", ["{"]); +test_match (new RegExp ("{"), "A{1,2", ["{"]); + +test_match (new RegExp ("{{2,3}"), "", null); +test_match (new RegExp ("{{2,3}"), "AA", null); +test_match (new RegExp ("{{2,3}"), "{{,", ["{{"]); +test_match (new RegExp ("{{2,3}"), "{{{,", ["{{{"]); +test_match (new RegExp ("{{2,3}"), "{{{{,", ["{{{"]); + +test_match (new RegExp ("{{2,3"), "{{{{,", null); +test_match (new RegExp ("{{2,3"), "{{2,3,", ["{{2,3"]); + +test_match (/A{1,2/, "A", null); +test_match (/A{1,2/, "AA", null); +test_match (/A{1,2/, "A{1,2", ["A{1,2"]); +test_match (/A{1,2/, "AA{1,2", ["A{1,2"]); + +test_match (/A{1,/, "A", null); +test_match (/A{1,/, "AA", null); +test_match (/A{1,/, "A{1,", ["A{1,"]); +test_match (/A{1,/, "A{1,2", ["A{1,"]); +test_match (/A{1,/, "AA{1,2", ["A{1,"]); + +test_match (/A{1/, "A", null); +test_match (/A{1/, "AA", null); +test_match (/A{1/, "A{1,", ["A{1"]); +test_match (/A{1/, "A{1,2", ["A{1"]); +test_match (/A{1/, "AA{1,2", ["A{1"]); + +test_match (/A{/, "A", null); +test_match (/A{/, "AA", null); +test_match (/A{/, "A{,", ["A{"]); +test_match (/A{/, "A{1,", ["A{"]); +test_match (/A{/, "A{1,2", ["A{"]); +test_match (/A{/, "AA{1,2", ["A{"]); + +test_match (/{/, "", null); +test_match (/{/, "AA", null); +test_match (/{/, "{,", ["{"]); +test_match (/{/, "{1,", ["{"]); +test_match (/{/, "{1,2", ["{"]); +test_match (/{/, "A{1,2", ["{"]); + +test_match (/{{2,3}/, "", null); +test_match (/{{2,3}/, "AA", null); +test_match (/{{2,3}/, "{{,", ["{{"]); +test_match (/{{2,3}/, "{{{,", ["{{{"]); +test_match (/{{2,3}/, "{{{{,", ["{{{"]); + +test_match (/{{2,3/, "{{{{,", null); +test_match (/{{2,3/, "{{2,3,", ["{{2,3"]); + +try { + new RegExp ("["); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + eval ("/[/"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + new RegExp ("("); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + eval ("/(/"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +test_match (new RegExp("\s+{3,4"), "s+{3,4", null); +test_match (new RegExp("\s+{3,4"), "s{3,4", ["s{3,4"]); +test_match (new RegExp("\s+{3,4"), "ss{3,4", ["ss{3,4"]); +test_match (new RegExp("\\s+{3,4"), " {3,4", [" {3,4"]); +test_match (new RegExp("\\s+{3,4"), " d{3,4", null); + +test_match (/s+{3,4/, "s+{3,4", null); +test_match (/s+{3,4/, "s{3,4", ["s{3,4"]); +test_match (/s+{3,4/, "ss{3,4", ["ss{3,4"]); +test_match (/\s+{3,4/, " {3,4", [" {3,4"]); +test_match (/\s+{3,4/, " d{3,4", null); + +try { + new RegExp ("\s+{3,4}"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + eval ("/\\s+{3,4}/"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + new RegExp ("a{2,3}{2,3}"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} + +try { + eval ("/a{2,3}{2,3}/"); + assert (false); +} catch (ex) { + assert (ex instanceof SyntaxError); +} diff --git a/tests/jerry/regression-test-issue-1555.js b/tests/jerry/regression-test-issue-1555.js index 6e2db192..507d75f3 100644 --- a/tests/jerry/regression-test-issue-1555.js +++ b/tests/jerry/regression-test-issue-1555.js @@ -14,7 +14,7 @@ var src = "var a = 0; while(a) { switch(a) {"; /* The += operation has a longer opcode. */ -for (var i = 0; i < 3500; i++) +for (var i = 0; i < 3300; i++) src += "case " + i + ": a += a += a; break; "; src += "} }"; diff --git a/tests/jerry/regression-test-issue-2105.js b/tests/jerry/regression-test-issue-2105.js index 4cff41b2..184566e4 100644 --- a/tests/jerry/regression-test-issue-2105.js +++ b/tests/jerry/regression-test-issue-2105.js @@ -51,4 +51,4 @@ try { /* Check properties of a */ assert(Object.keys(a) == "one,two"); /* Check properties of global object */ -assert(Object.keys(this) == "assert,gc,print,a,fail,fail_two"); +assert(Object.keys(this) == "assert,gc,print,resourceName,a,fail,fail_two"); diff --git a/tests/jerry/regression-test-issue-2190.js b/tests/jerry/regression-test-issue-2190.js index ed229a20..a811572b 100644 --- a/tests/jerry/regression-test-issue-2190.js +++ b/tests/jerry/regression-test-issue-2190.js @@ -13,7 +13,7 @@ // limitations under the License. try { - /(?:(?=x)){1000}xyz/.exec('xyz'); + /(?:(?=x)){10000}xyz/.exec('xyz'); assert(false); } catch (e) { assert(e instanceof RangeError); diff --git a/tests/jerry/regression-test-issue-3229.js b/tests/jerry/regression-test-issue-3229.js new file mode 100644 index 00000000..50719181 --- /dev/null +++ b/tests/jerry/regression-test-issue-3229.js @@ -0,0 +1,33 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var NISLFuzzingFunc = function(e) { + Number(0).toString(e); +}; + +var NISLParameter4 = "Hello Jerry"; + +try { + NISLFuzzingFunc(NISLParameter4); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} +try { + Number.prototype.toString.call(-Infinity, "Unicorn invasion"); + assert(false); +} catch (e) { + assert(e instanceof RangeError); +} diff --git a/tests/jerry/regression-test-issue-3271.js b/tests/jerry/regression-test-issue-3271.js new file mode 100644 index 00000000..576ced8f --- /dev/null +++ b/tests/jerry/regression-test-issue-3271.js @@ -0,0 +1,42 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function bar(a) { + assert(a[0] === 10); + a.hasOwnProperty(0); + assert(a[0] === 10); +} + +function foo(a) { + assert(a === 20); + a = 10; + bar(arguments); +} + +function barStrict(a) { + "use strict" + assert(a[0] === 20); + a.hasOwnProperty(0); + assert(a[0] === 20); +} + +function fooStrict(a) { + "use strict" + assert(a === 20); + a = 10; + barStrict(arguments); +} + +foo(20); +fooStrict(20); diff --git a/tests/jerry/regression-test-issue-3313.js b/tests/jerry/regression-test-issue-3313.js new file mode 100644 index 00000000..dfb0fb29 --- /dev/null +++ b/tests/jerry/regression-test-issue-3313.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval("var" + "\u2029" + 'g\\u0065t: break get' ); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/regression-test-issue-3325.js b/tests/jerry/regression-test-issue-3325.js new file mode 100644 index 00000000..afc4e441 --- /dev/null +++ b/tests/jerry/regression-test-issue-3325.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var text = 'x'; +assert (text.charAt(0) === "x"); +assert (text.charAt(-0.1) === "x"); +assert (text.charAt(-0.5) === "x"); +assert (text.charAt(-0.9) === "x"); +assert (text.charAt(0.85) === "x"); + +assert (text.charAt(-0.5) !== ""); +assert (text.charAt(0.85) !== ""); diff --git a/tests/jerry/regression-test-issue-3397.js b/tests/jerry/regression-test-issue-3397.js new file mode 100644 index 00000000..6d8389ec --- /dev/null +++ b/tests/jerry/regression-test-issue-3397.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var $ + +$++ +[ ] diff --git a/tests/jerry/regression-test-issue-3467.js b/tests/jerry/regression-test-issue-3467.js new file mode 100644 index 00000000..f041b0a9 --- /dev/null +++ b/tests/jerry/regression-test-issue-3467.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(new Function("return")() === undefined); diff --git a/tests/jerry/regression-test-issue-3477.js b/tests/jerry/regression-test-issue-3477.js new file mode 100644 index 00000000..1f05570f --- /dev/null +++ b/tests/jerry/regression-test-issue-3477.js @@ -0,0 +1,28 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function _p(arg1, arg2) { + return arg1 ? arg1 : arg2; +} + +var _ref; +var constructor = _p(this, (_ref = Object.getPrototypeOf(function (){})).call({})); +assert(constructor === this); + +try { + _p(this, (_ref += Object.getPrototypeOf(function (){})).call({})); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/regression-test-issue-3523.js b/tests/jerry/regression-test-issue-3523.js new file mode 100644 index 00000000..537f6c2a --- /dev/null +++ b/tests/jerry/regression-test-issue-3523.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = { + sort: Array.prototype.sort, + $: 0 +} +assert(obj.sort() === obj); diff --git a/tests/jerry/regression-test-issue-3532.js b/tests/jerry/regression-test-issue-3532.js new file mode 100644 index 00000000..8b1b6028 --- /dev/null +++ b/tests/jerry/regression-test-issue-3532.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var reached = false; + +function dConstr () {} +dConstr.prototype = [, ] +for (var $ in new dConstr()) { + reached = true; +} + +assert(!reached); diff --git a/tests/jerry/regression-test-issue-3553.js b/tests/jerry/regression-test-issue-3553.js new file mode 100644 index 00000000..43e00fe2 --- /dev/null +++ b/tests/jerry/regression-test-issue-3553.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var src = "0?0:0+++++0"; + +try { + eval (src); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/regression-test-issue-3608.js b/tests/jerry/regression-test-issue-3608.js new file mode 100644 index 00000000..65ad62bf --- /dev/null +++ b/tests/jerry/regression-test-issue-3608.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var src = "function $() { return $ ? $ : $ * $++() } switch ($) {}"; + +try { + eval (src); + assert (false); +} catch (e) { + assert (e instanceof SyntaxError); +} diff --git a/tests/jerry/regression-test-issue-3648.js b/tests/jerry/regression-test-issue-3648.js new file mode 100644 index 00000000..243e60bf --- /dev/null +++ b/tests/jerry/regression-test-issue-3648.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var func = function () {}; +var boundFunc = func.bind(); +var externalFunc = print; +var builtinFunc = unescape; + +[func, boundFunc, externalFunc, builtinFunc].forEach(function (e) { + assert (Array.prototype.sort.call(e) === e); +}) + diff --git a/tests/jerry/regression-test-issue-3650.js b/tests/jerry/regression-test-issue-3650.js new file mode 100644 index 00000000..d191b735 --- /dev/null +++ b/tests/jerry/regression-test-issue-3650.js @@ -0,0 +1,17 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var u = 5; +assert ([this, u = u - 1].length === 2); +assert (u === 4); diff --git a/tests/jerry/regression-test-issue-3711.js b/tests/jerry/regression-test-issue-3711.js new file mode 100644 index 00000000..8a8b798c --- /dev/null +++ b/tests/jerry/regression-test-issue-3711.js @@ -0,0 +1,42 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function func() {} + +var bound = func.bind(); + +/* original test case from the issue report */ +if (function() { + return func.bind()(0, 0, 0, 0, 0, 0, 0) +}()); + +/* various versions of the issue report */ + +/* call the bound function with a lots of args */ +for (var idx = 0; idx < 50; idx++) { + var args = new Array(idx); + + bound.apply(undefined, args); + + delete args; +} + +/* bind the function with multiple args and invoke it */ +for (var idx = 0; idx < 25; idx++) { + var args = new Array(idx); + + func.bind.apply(func, args).apply(undefined, args); + + delete args; +} diff --git a/tests/jerry/regression-test-issue-3748-3749.js b/tests/jerry/regression-test-issue-3748-3749.js new file mode 100644 index 00000000..c6b06380 --- /dev/null +++ b/tests/jerry/regression-test-issue-3748-3749.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* try to trigger the gc a few times*/ +for (var i = 0; i < 2; i++) +{ + new RegExp(32.2, "g") +} diff --git a/tests/jerry/regression-test-issue-3761.js b/tests/jerry/regression-test-issue-3761.js new file mode 100644 index 00000000..c5a3507c --- /dev/null +++ b/tests/jerry/regression-test-issue-3761.js @@ -0,0 +1,16 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var result = parseFloat ("IE"); +assert (isNaN (result)); diff --git a/tests/jerry/regression-test-issue-3778.js b/tests/jerry/regression-test-issue-3778.js new file mode 100644 index 00000000..512eb0a1 --- /dev/null +++ b/tests/jerry/regression-test-issue-3778.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert (parseFloat (-0.00001) === -0.00001); diff --git a/tests/jerry/regression-test-issue-3779.js b/tests/jerry/regression-test-issue-3779.js new file mode 100644 index 00000000..c97db4b3 --- /dev/null +++ b/tests/jerry/regression-test-issue-3779.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var array = [1, 2, 3]; +var idx_50 = array.lastIndexOf(50, { + valueOf: function() { + // Trigger removing elements from fast array. + array.length = 0; + } +}) + +assert (idx_50 === -1); + +var idx_51 = array.lastIndexOf(51, { + valueOf: function() { + array.push(51) + return 10; + } +}) + +assert (idx_51 === -1); diff --git a/tests/jerry/regression-test-issue-3813.js b/tests/jerry/regression-test-issue-3813.js new file mode 100644 index 00000000..a26f48f9 --- /dev/null +++ b/tests/jerry/regression-test-issue-3813.js @@ -0,0 +1,23 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var o = Object("str"); +o.toString = function() { throw "toString error" }; + +try { + JSON.stringify(o); + assert(false); +} catch (e) { + assert(e === "toString error"); +} diff --git a/tests/jerry/regression-test-issue-3815.js b/tests/jerry/regression-test-issue-3815.js new file mode 100644 index 00000000..176ded9d --- /dev/null +++ b/tests/jerry/regression-test-issue-3815.js @@ -0,0 +1,22 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function a() {} + +try { + (a()) = a + assert (false); +} catch (e) { + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/regression-test-issue-3821.js b/tests/jerry/regression-test-issue-3821.js new file mode 100644 index 00000000..6fca983f --- /dev/null +++ b/tests/jerry/regression-test-issue-3821.js @@ -0,0 +1,35 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_syntax_error (script) +{ + try + { + eval (script); + assert (false); + } + catch (e) + { + assert (e instanceof SyntaxError); + } +} + +check_syntax_error ('function') +check_syntax_error ('function a') +check_syntax_error ('function a"') +check_syntax_error ('function a"b') +check_syntax_error ('function a("b') +check_syntax_error ('function a(b, "c') +check_syntax_error ('function a(b, c"d') +check_syntax_error ('function a(b, c)"d') diff --git a/tests/jerry/regression-test-issue-3878.js b/tests/jerry/regression-test-issue-3878.js new file mode 100644 index 00000000..21afd23f --- /dev/null +++ b/tests/jerry/regression-test-issue-3878.js @@ -0,0 +1,21 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var d = new Date(); + +var s = d.setHours(); +assert (typeof s === "number" && isNaN (s)); + +var g = d.getHours(); +assert (typeof g === "number" && isNaN (g)); diff --git a/tests/jerry/regression-test-issue-736.js b/tests/jerry/regression-test-issue-736.js index 9d31f736..887357c8 100644 --- a/tests/jerry/regression-test-issue-736.js +++ b/tests/jerry/regression-test-issue-736.js @@ -27,13 +27,7 @@ try { eval(code); assert(false); } catch(e) { - assert(e instanceof TypeError); -} - -try { - eval("var x = {}; x instanceof assert;"); - assert(false); -} catch(e) { - assert(e instanceof TypeError); + assert(e instanceof ReferenceError); } +assert (!eval("var x = {}; x instanceof assert;")); diff --git a/tests/jerry/strict2.js b/tests/jerry/strict2.js new file mode 100644 index 00000000..37e2a860 --- /dev/null +++ b/tests/jerry/strict2.js @@ -0,0 +1,82 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function check_syntax_error (script) +{ + try + { + eval (script); + assert (false); + } + catch (e) + { + assert (e instanceof SyntaxError); + } +} + +var + implements = 0, + private = 1, + public = 2, + interface = 3, + package = 4, + protected = 5, + let = 6, + yield = 7, + static = 8; + +check_syntax_error("'use strict'\nimplements") +check_syntax_error("'use strict'\n\\u0069mplements") +assert(eval("'use stric'\nimplements") === 0) +assert(eval("'use stric'\n\\u0069mplements") === 0) + +check_syntax_error("'use strict'\nprivate") +check_syntax_error("'use strict'\n\\u0070rivate") +assert(eval("'use stric'\nprivate") === 1) +assert(eval("'use stric'\n\\u0070rivate") === 1) + +check_syntax_error("'use strict'\npublic") +check_syntax_error("'use strict'\n\\u0070ublic") +assert(eval("'use stric'\npublic") === 2) +assert(eval("'use stric'\n\\u0070ublic") === 2) + +check_syntax_error("'use strict'\ninterface") +check_syntax_error("'use strict'\n\\u0069nterface") +assert(eval("'use stric'\ninterface") === 3) +assert(eval("'use stric'\n\\u0069nterface") === 3) + +check_syntax_error("'use strict'\npackage") +check_syntax_error("'use strict'\n\\u0070ackage") +assert(eval("'use stric'\npackage") === 4) +assert(eval("'use stric'\n\\u0070ackage") === 4) + +check_syntax_error("'use strict'\nprotected") +check_syntax_error("'use strict'\n\\u0070rotected") +assert(eval("'use stric'\nprotected") === 5) +assert(eval("'use stric'\n\\u0070rotected") === 5) + +check_syntax_error("'use strict'\nlet") +check_syntax_error("'use strict'\n\\u006cet") +assert(eval("'use stric'\nlet") === 6) +assert(eval("'use stric'\n\\u006cet") === 6) + +check_syntax_error("'use strict'\nyield") +check_syntax_error("'use strict'\n\\u0079ield") +assert(eval("'use stric'\nyield") === 7) +assert(eval("'use stric'\n\\u0079ield") === 7) + +check_syntax_error("'use strict'\nstatic") +check_syntax_error("'use strict'\n\\u0073tatic") +assert(eval("'use stric'\nstatic") === 8) +assert(eval("'use stric'\n\\u0073tatic") === 8) diff --git a/tests/jerry/string-prototype-charat.js b/tests/jerry/string-prototype-charat.js index 68daf68b..7c669842 100644 --- a/tests/jerry/string-prototype-charat.js +++ b/tests/jerry/string-prototype-charat.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.charAt, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.charAt, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.charAt, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-charcodeat.js b/tests/jerry/string-prototype-charcodeat.js index bfb68f63..35ff6ba3 100644 --- a/tests/jerry/string-prototype-charcodeat.js +++ b/tests/jerry/string-prototype-charcodeat.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.charCodeAt, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.charCodeAt, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.charCodeAt, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-concat.js b/tests/jerry/string-prototype-concat.js index c0019034..5d4fc07a 100644 --- a/tests/jerry/string-prototype-concat.js +++ b/tests/jerry/string-prototype-concat.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.concat, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.concat, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.concat, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-indexof.js b/tests/jerry/string-prototype-indexof.js index a0b55fb4..f7ee266a 100644 --- a/tests/jerry/string-prototype-indexof.js +++ b/tests/jerry/string-prototype-indexof.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.indexOf, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.indexOf, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.indexOf, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-lastindexof.js b/tests/jerry/string-prototype-lastindexof.js index ca90a782..5ff0f0bc 100644 --- a/tests/jerry/string-prototype-lastindexof.js +++ b/tests/jerry/string-prototype-lastindexof.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.lastIndexOf, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.lastIndexOf, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.lastIndexOf, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-match.js b/tests/jerry/string-prototype-match.js index c8a09996..5318d2a3 100644 --- a/tests/jerry/string-prototype-match.js +++ b/tests/jerry/string-prototype-match.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').enumerable === false); assert(Object.getOwnPropertyDescriptor(String.prototype.match, 'length').writable === false); diff --git a/tests/jerry/string-prototype-replace.js b/tests/jerry/string-prototype-replace.js index b8d3a044..872ac408 100644 --- a/tests/jerry/string-prototype-replace.js +++ b/tests/jerry/string-prototype-replace.js @@ -14,6 +14,8 @@ assert ("abcabc".replace("bc", ":") === "a:abc"); assert ("hello".replace("", ":") === ":hello"); +assert ("hello".replace("h", "") === "ello"); +assert ("".replace("", "h") === "h"); assert ("xabcxabcx".replace (/abc/g, "[$&][$`][$']") === "x[abc][x][xabcx]x[abc][xabcx][x]x"); assert ("abc".replace (/a(b)c|d()/, "[$1][$01][$2][$02][$99][$123][$012]") === "[b][b][][][$99][b23][b2]"); @@ -110,10 +112,23 @@ try { assert (e instanceof TypeError); } -// The real "exec" never returns with a number. -Object.getPrototypeOf(/x/).exec = function () { return 1234; } +try { + "str".replace ({toString: function () {throw "abrupt search toString"}}, ""); + assert (false); +} catch (e) { + assert (e === "abrupt search toString"); +} -assert (/y/.exec("y") === 1234); +try { + "str".replace ("str", {toString: function () {throw "abrupt search toString"}}); + assert (false); +} catch (e) { + assert (e === "abrupt search toString"); +} -// Changing exec should not affect replace. -assert ("y".replace (/y/, "x") === "x"); +try { + "str".replace ("str", function () {return {toString: function () {throw "abrupt replacer toString"}}}); + assert (false); +} catch (e) { + assert (e === "abrupt replacer toString"); +} diff --git a/tests/jerry/string-prototype-search.js b/tests/jerry/string-prototype-search.js index cf16c508..aa74d7d7 100644 --- a/tests/jerry/string-prototype-search.js +++ b/tests/jerry/string-prototype-search.js @@ -36,24 +36,5 @@ assert ("aaxbb".search (regexp) === 2); assert ("aabb".search (regexp) === -1); assert (regexp.lastIndex === "index"); -Object.defineProperty(regexp, "lastIndex", { - configurable : false, - enumerable : false, - value : "index2", - writable : false -}); - -assert ("axb".search (regexp) === 1); -assert ("aabb".search (regexp) === -1); -assert (regexp.lastIndex === "index2"); - assert ("##\ud801\udc00".search ("\ud801") === 2); assert ("##\ud801\udc00".search ("\udc00") === 3); - -// The real "exec" never returns with a number. -Object.getPrototypeOf(/x/).exec = function () { return "???"; } - -assert (/y/.exec("y") === "???"); - -// Changing exec should not affect search. -assert ("ay".search (/y/) === 1); diff --git a/tests/jerry/string-prototype-split.js b/tests/jerry/string-prototype-split.js index bef02ca0..f216c326 100644 --- a/tests/jerry/string-prototype-split.js +++ b/tests/jerry/string-prototype-split.js @@ -51,9 +51,6 @@ assert (res[0] === "foo//b"); res = str.split("a", NaN); assert (res.length === 0); -res = str.split("a", Infinity); -assert (res.length === 0); - res = str.split(["o"]) assert (res.length === 5); assert (res[0] === "f"); @@ -96,12 +93,6 @@ res = str.split(/\/\//, 1); assert (res.length === 1); assert (res[0] === "foo"); -res = str.split(/\/\//, -1); -assert (res.length === 3); -assert (res[0] === "foo"); -assert (res[1] === "bar/baz"); -assert (res[2] === "foo"); - str = "fo123o12bar"; res = str.split(12, undefined); assert (res.length === 3); diff --git a/tests/jerry/string-prototype-substr.js b/tests/jerry/string-prototype-substr.js index 40613b7f..1e4a662c 100644 --- a/tests/jerry/string-prototype-substr.js +++ b/tests/jerry/string-prototype-substr.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.substr, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.substr, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.substr, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-substring.js b/tests/jerry/string-prototype-substring.js index 51d03b1b..78bda200 100644 --- a/tests/jerry/string-prototype-substring.js +++ b/tests/jerry/string-prototype-substring.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.substring, 'length').enumerable === false); diff --git a/tests/jerry/string-prototype-trim.js b/tests/jerry/string-prototype-trim.js index abeb31c7..689d9d33 100644 --- a/tests/jerry/string-prototype-trim.js +++ b/tests/jerry/string-prototype-trim.js @@ -13,7 +13,17 @@ // limitations under the License. // check properties -assert(Object.getOwnPropertyDescriptor(String.prototype.trim, 'length').configurable === false); + +function length_configurable() +{ + function is_es51() { + return (typeof g === "function"); + { function g() {} } + } + return is_es51() ? false : true; +} + +assert(Object.getOwnPropertyDescriptor(String.prototype.trim, 'length').configurable === length_configurable()); assert(Object.getOwnPropertyDescriptor(String.prototype.trim, 'length').enumerable === false); @@ -75,3 +85,5 @@ assert("\u000A\u000D\u2028\u202911".trim() === "11"); assert("\u0009\u000B\u000C\u0020\u00A01\u0009\u000B\u000C\u0020\u00A0".trim() === "1"); assert("\u000A\u000D\u2028\u202911\u000A\u000D\u2028\u2029".trim() === "11"); + +assert ("\u200B".trim() === '\u200B') diff --git a/tests/jerry/try-eval.js b/tests/jerry/try-eval.js new file mode 100644 index 00000000..219bb44d --- /dev/null +++ b/tests/jerry/try-eval.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + e; + assert (false); +} catch (e) { + eval("var e"); +} +assert (e === undefined); + +function f() { + try { + throw 1; + assert (false); + } catch (e) { + eval("var e"); + } +} +f(); diff --git a/tests/jerry/unicode-format-control-characters.js b/tests/jerry/unicode-format-control-characters.js new file mode 100644 index 00000000..608430e2 --- /dev/null +++ b/tests/jerry/unicode-format-control-characters.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +// Only \u200C-Zero width non-joiner, and \u200D-Zero width joiner are allowed + +checkSyntax ("_\u200b\u200d"); +checkSyntax ("_\u200c\u200e"); + +var _\u200c\u200d = 5; + +assert (_\u200c\u200d === 5); diff --git a/tests/jerry/windows-line-ending.js b/tests/jerry/windows-line-ending.js index 02a652f3..bda4a165 100644 --- a/tests/jerry/windows-line-ending.js +++ b/tests/jerry/windows-line-ending.js @@ -1,22 +1,22 @@ -// Copyright JS Foundation and other contributors, http://js.foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This test file should use CR-LF styled line endings to test if everything is -// parsed correctly - - -var value = - 5; - -assert (value === 5); +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This test file should use CR-LF styled line endings to test if everything is +// parsed correctly + + +var value = + 5; + +assert (value === 5); diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml new file mode 100644 index 00000000..85befc67 --- /dev/null +++ b/tests/test262-es6-excludelist.xml @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<<<<<<< HEAD +<<<<<<< HEAD +======= + + + +>>>>>>> parent of 104001df (Implement function name support for script functions and classes (#3745)) +======= + +>>>>>>> parent of 3b4c2592 (Add support for builtin/builtin routine 'name' property (#3810)) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/unit-core/test-api-binary-operations-arithmetics.c b/tests/unit-core/test-api-binary-operations-arithmetics.c new file mode 100644 index 00000000..8401b51e --- /dev/null +++ b/tests/unit-core/test-api-binary-operations-arithmetics.c @@ -0,0 +1,290 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" + +#include "test-common.h" + +#define T(op, lhs, rhs, res) \ + { op, lhs, rhs, res } + +#define T_NAN(op, lhs, rhs) \ + { op, lhs, rhs } + +#define T_ERR(op, lsh, rhs) \ + T_NAN (op, lsh, rhs) + +#define T_ARI(lhs, rhs) \ + T_NAN (JERRY_BIN_OP_SUB, lhs, rhs), \ + T_NAN (JERRY_BIN_OP_MUL, lhs, rhs), \ + T_NAN (JERRY_BIN_OP_DIV, lhs, rhs), \ + T_NAN (JERRY_BIN_OP_REM, lhs, rhs) + +typedef struct +{ + jerry_binary_operation_t op; + jerry_value_t lhs; + jerry_value_t rhs; + jerry_value_t expected; +} test_entry_t; + +typedef struct +{ + jerry_binary_operation_t op; + jerry_value_t lhs; + jerry_value_t rhs; +} test_nan_entry_t; + +typedef test_nan_entry_t test_error_entry_t; + +int +main (void) +{ + TEST_INIT (); + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t obj1 = jerry_eval ((const jerry_char_t *) "o={x:1};o", 9, JERRY_PARSE_NO_OPTS); + jerry_value_t obj2 = jerry_eval ((const jerry_char_t *) "o={x:1};o", 9, JERRY_PARSE_NO_OPTS); + jerry_value_t err1 = jerry_create_error (JERRY_ERROR_SYNTAX, (const jerry_char_t *) "error"); + + test_nan_entry_t test_nans[] = + { + /* Testing addition (+) */ + T_NAN (JERRY_BIN_OP_ADD, jerry_create_number (3.1), jerry_create_undefined ()), + T_NAN (JERRY_BIN_OP_ADD, jerry_create_undefined (), jerry_create_undefined ()), + T_NAN (JERRY_BIN_OP_ADD, jerry_create_undefined (), jerry_create_null ()), + + /* Testing subtraction (-), multiplication (*), division (/), remainder (%) */ + T_ARI (jerry_create_number (3.1), jerry_create_undefined ()), + T_ARI (jerry_create_string ((const jerry_char_t *) "foo"), jerry_create_string ((const jerry_char_t *) "bar")), + T_ARI (jerry_create_string ((const jerry_char_t *) "foo"), jerry_create_undefined ()), + T_ARI (jerry_create_string ((const jerry_char_t *) "foo"), jerry_create_null ()), + T_ARI (jerry_create_string ((const jerry_char_t *) "foo"), jerry_create_number (5.0)), + T_ARI (jerry_create_undefined (), jerry_create_string ((const jerry_char_t *) "foo")), + T_ARI (jerry_create_null (), jerry_create_string ((const jerry_char_t *) "foo")), + T_ARI (jerry_create_number (5.0), jerry_create_string ((const jerry_char_t *) "foo")), + T_ARI (jerry_create_undefined (), jerry_create_undefined ()), + T_ARI (jerry_create_undefined (), jerry_create_null ()), + T_ARI (jerry_create_null (), jerry_create_undefined ()), + T_ARI (jerry_acquire_value (obj1), jerry_acquire_value (obj1)), + T_ARI (jerry_acquire_value (obj1), jerry_acquire_value (obj2)), + T_ARI (jerry_acquire_value (obj2), jerry_acquire_value (obj1)), + T_ARI (jerry_acquire_value (obj2), jerry_create_undefined ()), + T_ARI (jerry_acquire_value (obj1), jerry_create_string ((const jerry_char_t *) "foo")), + T_ARI (jerry_acquire_value (obj1), jerry_create_null ()), + T_ARI (jerry_acquire_value (obj1), jerry_create_boolean (true)), + T_ARI (jerry_acquire_value (obj1), jerry_create_boolean (false)), + T_ARI (jerry_acquire_value (obj1), jerry_create_number (5.0)), + + /* Testing division (/) */ + T_NAN (JERRY_BIN_OP_DIV, jerry_create_boolean (false), jerry_create_boolean (false)), + T_NAN (JERRY_BIN_OP_DIV, jerry_create_number (0.0), jerry_create_number (0.0)), + T_NAN (JERRY_BIN_OP_DIV, jerry_create_null (), jerry_create_null ()), + + /* Testing remainder (%) */ + T_NAN (JERRY_BIN_OP_REM, jerry_create_boolean (true), jerry_create_boolean (false)), + T_NAN (JERRY_BIN_OP_REM, jerry_create_boolean (false), jerry_create_boolean (false)), + T_NAN (JERRY_BIN_OP_REM, jerry_create_number (0.0), jerry_create_number (0.0)), + T_NAN (JERRY_BIN_OP_REM, jerry_create_null (), jerry_create_null ()), + }; + + for (uint32_t idx = 0; idx < sizeof (test_nans) / sizeof (test_nan_entry_t); idx++) + { + jerry_value_t result = jerry_binary_operation (test_nans[idx].op, test_nans[idx].lhs, test_nans[idx].rhs); + TEST_ASSERT (jerry_value_is_number (result)); + + double num = jerry_get_number_value (result); + + TEST_ASSERT (num != num); + + jerry_release_value (test_nans[idx].lhs); + jerry_release_value (test_nans[idx].rhs); + jerry_release_value (result); + } + + test_entry_t tests[] = + { + /* Testing addition (+) */ + T (JERRY_BIN_OP_ADD, jerry_create_number (5.0), jerry_create_number (5.0), jerry_create_number (10.0)), + T (JERRY_BIN_OP_ADD, jerry_create_number (3.1), jerry_create_number (10), jerry_create_number (13.1)), + T (JERRY_BIN_OP_ADD, jerry_create_number (3.1), jerry_create_boolean (true), jerry_create_number (4.1)), + T (JERRY_BIN_OP_ADD, + jerry_create_string ((const jerry_char_t *) "foo"), + jerry_create_string ((const jerry_char_t *) "bar"), + jerry_create_string ((const jerry_char_t *) "foobar")), + T (JERRY_BIN_OP_ADD, + jerry_create_string ((const jerry_char_t *) "foo"), + jerry_create_undefined (), + jerry_create_string ((const jerry_char_t *) "fooundefined")), + T (JERRY_BIN_OP_ADD, + jerry_create_string ((const jerry_char_t *) "foo"), + jerry_create_null (), + jerry_create_string ((const jerry_char_t *) "foonull")), + T (JERRY_BIN_OP_ADD, + jerry_create_string ((const jerry_char_t *) "foo"), + jerry_create_number (5.0), + jerry_create_string ((const jerry_char_t *) "foo5")), + + T (JERRY_BIN_OP_ADD, jerry_create_null (), jerry_create_null (), jerry_create_number (0.0)), + T (JERRY_BIN_OP_ADD, jerry_create_boolean (true), jerry_create_boolean (true), jerry_create_number (2.0)), + T (JERRY_BIN_OP_ADD, jerry_create_boolean (true), jerry_create_boolean (false), jerry_create_number (1.0)), + T (JERRY_BIN_OP_ADD, jerry_create_boolean (false), jerry_create_boolean (true), jerry_create_number (1.0)), + T (JERRY_BIN_OP_ADD, jerry_create_boolean (false), jerry_create_boolean (false), jerry_create_number (0.0)), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_acquire_value (obj1), + jerry_create_string ((const jerry_char_t *) "[object Object][object Object]")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_acquire_value (obj2), + jerry_create_string ((const jerry_char_t *) "[object Object][object Object]")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj2), + jerry_acquire_value (obj1), + jerry_create_string ((const jerry_char_t *) "[object Object][object Object]")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_null (), + jerry_create_string ((const jerry_char_t *) "[object Object]null")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_undefined (), + jerry_create_string ((const jerry_char_t *) "[object Object]undefined")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_boolean (true), + jerry_create_string ((const jerry_char_t *) "[object Object]true")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_boolean (false), + jerry_create_string ((const jerry_char_t *) "[object Object]false")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_number (5.0), + jerry_create_string ((const jerry_char_t *) "[object Object]5")), + T (JERRY_BIN_OP_ADD, + jerry_acquire_value (obj1), + jerry_create_string ((const jerry_char_t *) "foo"), + jerry_create_string ((const jerry_char_t *) "[object Object]foo")), + + /* Testing subtraction (-) */ + T (JERRY_BIN_OP_SUB, jerry_create_number (5.0), jerry_create_number (5.0), jerry_create_number (0.0)), + T (JERRY_BIN_OP_SUB, jerry_create_number (3.1), jerry_create_number (10), jerry_create_number (-6.9)), + T (JERRY_BIN_OP_SUB, jerry_create_number (3.1), jerry_create_boolean (true), jerry_create_number (2.1)), + T (JERRY_BIN_OP_SUB, jerry_create_boolean (true), jerry_create_boolean (true), jerry_create_number (0.0)), + T (JERRY_BIN_OP_SUB, jerry_create_boolean (true), jerry_create_boolean (false), jerry_create_number (1.0)), + T (JERRY_BIN_OP_SUB, jerry_create_boolean (false), jerry_create_boolean (true), jerry_create_number (-1.0)), + T (JERRY_BIN_OP_SUB, jerry_create_boolean (false), jerry_create_boolean (false), jerry_create_number (0.0)), + T (JERRY_BIN_OP_SUB, jerry_create_null (), jerry_create_null (), jerry_create_number (-0.0)), + + /* Testing multiplication (*) */ + T (JERRY_BIN_OP_MUL, jerry_create_number (5.0), jerry_create_number (5.0), jerry_create_number (25.0)), + T (JERRY_BIN_OP_MUL, jerry_create_number (3.1), jerry_create_number (10), jerry_create_number (31)), + T (JERRY_BIN_OP_MUL, jerry_create_number (3.1), jerry_create_boolean (true), jerry_create_number (3.1)), + T (JERRY_BIN_OP_MUL, jerry_create_boolean (true), jerry_create_boolean (true), jerry_create_number (1.0)), + T (JERRY_BIN_OP_MUL, jerry_create_boolean (true), jerry_create_boolean (false), jerry_create_number (0.0)), + T (JERRY_BIN_OP_MUL, jerry_create_boolean (false), jerry_create_boolean (true), jerry_create_number (0.0)), + T (JERRY_BIN_OP_MUL, jerry_create_boolean (false), jerry_create_boolean (false), jerry_create_number (0.0)), + T (JERRY_BIN_OP_MUL, jerry_create_null (), jerry_create_null (), jerry_create_number (0.0)), + + /* Testing division (/) */ + T (JERRY_BIN_OP_DIV, jerry_create_number (5.0), jerry_create_number (5.0), jerry_create_number (1.0)), + T (JERRY_BIN_OP_DIV, jerry_create_number (3.1), jerry_create_number (10), jerry_create_number (0.31)), + T (JERRY_BIN_OP_DIV, jerry_create_number (3.1), jerry_create_boolean (true), jerry_create_number (3.1)), + T (JERRY_BIN_OP_DIV, jerry_create_boolean (true), jerry_create_boolean (true), jerry_create_number (1.0)), + T (JERRY_BIN_OP_DIV, + jerry_create_boolean (true), + jerry_create_boolean (false), + jerry_create_number_infinity (false)), + T (JERRY_BIN_OP_DIV, jerry_create_boolean (false), jerry_create_boolean (true), jerry_create_number (0.0)), + + /* Testing remainder (%) */ + T (JERRY_BIN_OP_REM, jerry_create_number (5.0), jerry_create_number (5.0), jerry_create_number (0.0)), + T (JERRY_BIN_OP_REM, jerry_create_number (5.0), jerry_create_number (2.0), jerry_create_number (1.0)), + T (JERRY_BIN_OP_REM, jerry_create_number (3.1), jerry_create_number (10), jerry_create_number (3.1)), + T (JERRY_BIN_OP_REM, + jerry_create_number (3.1), + jerry_create_boolean (true), + jerry_create_number (0.10000000000000009)), + T (JERRY_BIN_OP_REM, jerry_create_boolean (true), jerry_create_boolean (true), jerry_create_number (0.0)), + T (JERRY_BIN_OP_REM, jerry_create_boolean (false), jerry_create_boolean (true), jerry_create_number (0.0)), + + }; + + for (uint32_t idx = 0; idx < sizeof (tests) / sizeof (test_entry_t); idx++) + { + jerry_value_t result = jerry_binary_operation (tests[idx].op, tests[idx].lhs, tests[idx].rhs); + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_value_t equals = jerry_binary_operation (JERRY_BIN_OP_STRICT_EQUAL, result, tests[idx].expected); + TEST_ASSERT (jerry_value_is_boolean (equals) && jerry_get_boolean_value (equals)); + jerry_release_value (equals); + + jerry_release_value (tests[idx].lhs); + jerry_release_value (tests[idx].rhs); + jerry_release_value (tests[idx].expected); + jerry_release_value (result); + } + + jerry_value_t obj3 = jerry_eval ((const jerry_char_t *) "o={valueOf:function(){throw 5}};o", 33, JERRY_PARSE_NO_OPTS); + + test_error_entry_t error_tests[] = + { + /* Testing addition (+) */ + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (err1), jerry_acquire_value (err1)), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (err1), jerry_create_undefined ()), + T_ERR (JERRY_BIN_OP_ADD, jerry_create_undefined (), jerry_acquire_value (err1)), + + /* Testing subtraction (-), multiplication (*), division (/), remainder (%) */ + T_ARI (jerry_acquire_value (err1), jerry_acquire_value (err1)), + T_ARI (jerry_acquire_value (err1), jerry_create_undefined ()), + T_ARI (jerry_create_undefined (), jerry_acquire_value (err1)), + + /* Testing addition (+) */ + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_create_undefined ()), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_create_null ()), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_create_boolean (true)), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_create_boolean (false)), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_acquire_value (obj2)), + T_ERR (JERRY_BIN_OP_ADD, jerry_acquire_value (obj3), jerry_create_string ((const jerry_char_t *) "foo")), + + /* Testing subtraction (-), multiplication (*), division (/), remainder (%) */ + T_ARI (jerry_acquire_value (obj3), jerry_create_undefined ()), + T_ARI (jerry_acquire_value (obj3), jerry_create_null ()), + T_ARI (jerry_acquire_value (obj3), jerry_create_boolean (true)), + T_ARI (jerry_acquire_value (obj3), jerry_create_boolean (false)), + T_ARI (jerry_acquire_value (obj3), jerry_acquire_value (obj2)), + T_ARI (jerry_acquire_value (obj3), jerry_create_string ((const jerry_char_t *) "foo")), + }; + + for (uint32_t idx = 0; idx < sizeof (error_tests) / sizeof (test_error_entry_t); idx++) + { + jerry_value_t result = jerry_binary_operation (tests[idx].op, error_tests[idx].lhs, error_tests[idx].rhs); + TEST_ASSERT (jerry_value_is_error (result)); + jerry_release_value (error_tests[idx].lhs); + jerry_release_value (error_tests[idx].rhs); + jerry_release_value (result); + } + + jerry_release_value (obj1); + jerry_release_value (obj2); + jerry_release_value (obj3); + jerry_release_value (err1); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-api-errortype.c b/tests/unit-core/test-api-errortype.c index 1c755a1d..305f5c31 100644 --- a/tests/unit-core/test-api-errortype.c +++ b/tests/unit-core/test-api-errortype.c @@ -62,5 +62,17 @@ main (void) jerry_release_value (test_values[idx]); } + char test_source[] = "\xF0\x9D\x84\x9E"; + + jerry_value_t result = jerry_parse (NULL, + 0, + (const jerry_char_t *) test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (jerry_value_is_error (result)); + TEST_ASSERT (jerry_get_error_type (result) == JERRY_ERROR_SYNTAX); + + jerry_release_value (result); + jerry_cleanup (); } /* main */ diff --git a/tests/unit-core/test-api-promise.c b/tests/unit-core/test-api-promise.c new file mode 100644 index 00000000..9dd247d0 --- /dev/null +++ b/tests/unit-core/test-api-promise.c @@ -0,0 +1,205 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +static void +test_promise_resolve_success (void) +{ + jerry_value_t my_promise = jerry_create_promise (); + + // A created promise has an undefined promise result by default and a pending state + { + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + TEST_ASSERT (jerry_value_is_undefined (promise_result)); + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_PENDING); + + jerry_release_value (promise_result); + } + + jerry_value_t resolve_value = jerry_create_object (); + { + jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one"); + jerry_value_t set_result = jerry_set_property (resolve_value, obj_key, jerry_create_number (3)); + TEST_ASSERT (jerry_value_is_boolean (set_result) && (jerry_get_boolean_value (set_result) == true)); + jerry_release_value (set_result); + jerry_release_value (obj_key); + } + + // A resolved promise should have the result of from the resolve call and a fulfilled state + { + jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, resolve_value, true); + + // Release "old" value of resolve. + jerry_release_value (resolve_value); + + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + { + TEST_ASSERT (jerry_value_is_object (promise_result)); + jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one"); + jerry_value_t get_result = jerry_get_property (promise_result, obj_key); + TEST_ASSERT (jerry_value_is_number (get_result)); + TEST_ASSERT (jerry_get_number_value (get_result) == 3.0); + + jerry_release_value (get_result); + jerry_release_value (obj_key); + } + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_FULFILLED); + + jerry_release_value (promise_result); + + jerry_release_value (resolve_result); + } + + // Resolvind a promise again does not change the result/state + { + jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, jerry_create_number (50), false); + + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + { + TEST_ASSERT (jerry_value_is_object (promise_result)); + jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one"); + jerry_value_t get_result = jerry_get_property (promise_result, obj_key); + TEST_ASSERT (jerry_value_is_number (get_result)); + TEST_ASSERT (jerry_get_number_value (get_result) == 3.0); + + jerry_release_value (get_result); + jerry_release_value (obj_key); + } + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_FULFILLED); + + jerry_release_value (promise_result); + + jerry_release_value (resolve_result); + } + + jerry_release_value (my_promise); +} /* test_promise_resolve_success */ + +static void +test_promise_resolve_fail (void) +{ + jerry_value_t my_promise = jerry_create_promise (); + + // A created promise has an undefined promise result by default and a pending state + { + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + TEST_ASSERT (jerry_value_is_undefined (promise_result)); + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_PENDING); + + jerry_release_value (promise_result); + } + + // A resolved promise should have the result of from the resolve call and a fulfilled state + { + jerry_value_t error_value = jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "resolve_fail"); + jerry_value_t error_obj = jerry_get_value_from_error (error_value, true); + jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, error_obj, false); + jerry_release_value (error_obj); + + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + // The error is not throw that's why it is only an error object. + TEST_ASSERT (jerry_value_is_object (promise_result)); + TEST_ASSERT (jerry_get_error_type (promise_result) == JERRY_ERROR_TYPE); + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_REJECTED); + + jerry_release_value (promise_result); + + jerry_release_value (resolve_result); + } + + // Resolvind a promise again does not change the result/state + { + jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, jerry_create_number (50), true); + + jerry_value_t promise_result = jerry_get_promise_result (my_promise); + TEST_ASSERT (jerry_value_is_object (promise_result)); + TEST_ASSERT (jerry_get_error_type (promise_result) == JERRY_ERROR_TYPE); + + jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise); + TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_REJECTED); + + jerry_release_value (promise_result); + + jerry_release_value (resolve_result); + } + + jerry_release_value (my_promise); +} /* test_promise_resolve_fail */ + +static void +test_promise_from_js (void) +{ + const jerry_char_t test_source[] = "(new Promise(function(rs, rj) { rs(30); })).then(function(v) { return v + 1; })"; + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t res = jerry_run (parsed_code_val); + TEST_ASSERT (jerry_value_is_promise (res)); + + TEST_ASSERT (jerry_get_promise_state (res) == JERRY_PROMISE_STATE_PENDING); + + jerry_value_t run_result = jerry_run_all_enqueued_jobs (); + TEST_ASSERT (jerry_value_is_undefined (run_result)); + jerry_release_value (run_result); + + TEST_ASSERT (jerry_get_promise_state (res) == JERRY_PROMISE_STATE_FULFILLED); + jerry_value_t promise_result = jerry_get_promise_result (res); + TEST_ASSERT (jerry_value_is_number (promise_result)); + TEST_ASSERT (jerry_get_number_value (promise_result) == 31.0); + + jerry_release_value (promise_result); + jerry_release_value (res); + jerry_release_value (parsed_code_val); +} /* test_promise_from_js */ + +int +main (void) +{ + if (!jerry_is_feature_enabled (JERRY_FEATURE_PROMISE)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Promise is disabled!\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + test_promise_resolve_fail (); + test_promise_resolve_success (); + + test_promise_from_js (); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-api-property.c b/tests/unit-core/test-api-property.c index c1f5de1f..b8b31ae5 100644 --- a/tests/unit-core/test-api-property.c +++ b/tests/unit-core/test-api-property.c @@ -64,10 +64,42 @@ main (void) TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter)); TEST_ASSERT (prop_desc.is_set_defined == false); TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter)); - jerry_release_value (prop_name); jerry_free_property_descriptor_fields (&prop_desc); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + /* Note: update this test when the internal method is implemented */ + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + is_ok = jerry_get_own_property_descriptor (proxy, prop_name, &prop_desc); + TEST_ASSERT (!is_ok); + jerry_release_value (proxy); + } + + jerry_release_value (prop_name); + + /* Test: define and get own property descriptor */ + prop_desc.is_enumerable = true; + prop_name = jerry_create_string ((const jerry_char_t *) "enumerable-property"); + res = jerry_define_own_property (global_obj_val, prop_name, &prop_desc); + TEST_ASSERT (!jerry_value_is_error (res)); + TEST_ASSERT (jerry_value_is_boolean (res)); + TEST_ASSERT (jerry_get_boolean_value (res)); + jerry_release_value (res); + jerry_free_property_descriptor_fields (&prop_desc); + is_ok = jerry_get_own_property_descriptor (global_obj_val, prop_name, &prop_desc); + TEST_ASSERT (is_ok); + TEST_ASSERT (prop_desc.is_writable == false); + TEST_ASSERT (prop_desc.is_enumerable == true); + TEST_ASSERT (prop_desc.is_configurable == false); + + jerry_release_value (prop_name); jerry_release_value (global_obj_val); + jerry_cleanup (); return 0; diff --git a/tests/unit-core/test-api-strings.c b/tests/unit-core/test-api-strings.c index 6e673567..2e8119d3 100644 --- a/tests/unit-core/test-api-strings.c +++ b/tests/unit-core/test-api-strings.c @@ -83,7 +83,7 @@ main (void) utf8_sz = jerry_get_utf8_string_size (args[0]); cesu8_sz = jerry_get_utf8_string_size (args[1]); - TEST_ASSERT (utf8_sz == cesu8_sz); + TEST_ASSERT (utf8_sz == cesu8_sz && utf8_sz > 0); JERRY_VLA (char, string_from_utf8_string, utf8_sz); JERRY_VLA (char, string_from_cesu8_string, cesu8_sz); diff --git a/tests/unit-core/test-api.c b/tests/unit-core/test-api.c index 86735229..290caf40 100644 --- a/tests/unit-core/test-api.c +++ b/tests/unit-core/test-api.c @@ -119,7 +119,6 @@ handler_construct_2_freecb (void *native_p) test_api_is_free_callback_was_called = true; } /* handler_construct_2_freecb */ - /** * The name of the jerry_object_native_info_t struct. */ @@ -271,8 +270,6 @@ foreach (const jerry_value_t name, /**< field name */ TEST_ASSERT (false); return false; - - } /* foreach */ static bool @@ -686,11 +683,35 @@ main (void) jerry_release_value (prim_val); /* Test: jerry_get_prototype */ + proto_val = jerry_get_prototype (jerry_create_undefined ()); + TEST_ASSERT (jerry_value_is_error (proto_val)); + jerry_value_t error = jerry_get_value_from_error (proto_val, true); + TEST_ASSERT (jerry_get_error_type (error) == JERRY_ERROR_TYPE); + jerry_release_value (error); + proto_val = jerry_get_prototype (obj_val); TEST_ASSERT (!jerry_value_is_error (proto_val)); TEST_ASSERT (jerry_value_is_object (proto_val)); + jerry_release_value (proto_val); jerry_release_value (obj_val); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + jerry_value_t obj_proto = jerry_eval ((jerry_char_t *) "Object.prototype", 16, JERRY_PARSE_NO_OPTS); + + jerry_release_value (target); + jerry_release_value (handler); + proto_val = jerry_get_prototype (proxy); + TEST_ASSERT (!jerry_value_is_error (proto_val)); + TEST_ASSERT (proto_val == obj_proto); + jerry_release_value (proto_val); + jerry_release_value (obj_proto); + jerry_release_value (proxy); + } + /* Test: jerry_set_prototype */ obj_val = jerry_create_object (); res = jerry_set_prototype (obj_val, jerry_create_null ()); @@ -698,7 +719,9 @@ main (void) TEST_ASSERT (jerry_value_is_boolean (res)); TEST_ASSERT (jerry_get_boolean_value (res)); - res = jerry_set_prototype (obj_val, jerry_create_object ()); + jerry_value_t new_proto = jerry_create_object (); + res = jerry_set_prototype (obj_val, new_proto); + jerry_release_value (new_proto); TEST_ASSERT (!jerry_value_is_error (res)); TEST_ASSERT (jerry_value_is_boolean (res)); TEST_ASSERT (jerry_get_boolean_value (res)); @@ -708,6 +731,25 @@ main (void) jerry_release_value (proto_val); jerry_release_value (obj_val); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + new_proto = jerry_eval ((jerry_char_t *) "Function.prototype", 18, JERRY_PARSE_NO_OPTS); + + res = jerry_set_prototype (proxy, new_proto); + TEST_ASSERT (!jerry_value_is_error (res)); + jerry_value_t target_proto = jerry_get_prototype (target); + TEST_ASSERT (target_proto == new_proto); + + jerry_release_value (target); + jerry_release_value (handler); + jerry_release_value (proxy); + jerry_release_value (new_proto); + jerry_release_value (target_proto); + } + /* Test: eval */ const jerry_char_t eval_code_src1[] = "(function () { return 123; })"; val_t = jerry_eval (eval_code_src1, sizeof (eval_code_src1) - 1, JERRY_PARSE_STRICT_MODE); @@ -805,6 +847,47 @@ main (void) jerry_cleanup (); } + /* Test parsing/executing scripts with lexically scoped global variables multiple times. */ + if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_init (JERRY_INIT_EMPTY); + const jerry_char_t scoped_src_p[] = "let a;"; + jerry_value_t parse_result = jerry_parse (NULL, + 0, + scoped_src_p, + sizeof (scoped_src_p) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + jerry_release_value (parse_result); + + parse_result = jerry_parse (NULL, + 0, + scoped_src_p, + sizeof (scoped_src_p) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + + jerry_value_t run_result = jerry_run (parse_result); + TEST_ASSERT (!jerry_value_is_error (run_result)); + jerry_release_value (run_result); + + /* Should be a syntax error due to redeclaration. */ + run_result = jerry_run (parse_result); + TEST_ASSERT (jerry_value_is_error (run_result)); + jerry_release_value (run_result); + jerry_release_value (parse_result); + + /* The variable should have no effect on parsing. */ + parse_result = jerry_parse (NULL, + 0, + scoped_src_p, + sizeof (scoped_src_p) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parse_result)); + jerry_release_value (parse_result); + jerry_cleanup (); + } + /* Test: parser error location */ if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)) { @@ -942,7 +1025,7 @@ main (void) TEST_ASSERT (jerry_get_boolean_value (has_prop_js)); jerry_release_value (has_prop_js); jerry_value_t parsed_data = jerry_get_property (parsed_json, key); - TEST_ASSERT (jerry_value_is_string (parsed_data)== true); + TEST_ASSERT (jerry_value_is_string (parsed_data) == true); jerry_size_t buff_size = jerry_get_string_size (parsed_data); JERRY_VLA (char, buff, buff_size + 1); jerry_string_to_char_buffer (parsed_data, (jerry_char_t *) buff, buff_size); diff --git a/tests/unit-core/test-arraybuffer.c b/tests/unit-core/test-arraybuffer.c index 46dffc23..b3735f0c 100644 --- a/tests/unit-core/test-arraybuffer.c +++ b/tests/unit-core/test-arraybuffer.c @@ -92,7 +92,7 @@ test_read_with_offset (uint8_t offset) /**< offset for buffer read. */ /* Try to copy more than the target buffer size. */ jerry_length_t copied = jerry_arraybuffer_read (arraybuffer, offset, buffer, 20); - TEST_ASSERT (copied == (jerry_length_t)(15 - offset)); + TEST_ASSERT (copied == (jerry_length_t) (15 - offset)); for (uint8_t i = 0; i < copied; i++) { @@ -132,7 +132,7 @@ static void test_write_with_offset (uint8_t offset) /**< offset for buffer write /* Intentionally copy more than the allowed space. */ jerry_length_t copied = jerry_arraybuffer_write (arraybuffer, offset, buffer, 20); - TEST_ASSERT (copied == (jerry_length_t)(15 - offset)); + TEST_ASSERT (copied == (jerry_length_t) (15 - offset)); const jerry_char_t eval_test_arraybuffer[] = TEST_STRING_LITERAL ( "for (var i = 0; i < offset; i++)" @@ -250,6 +250,23 @@ main (void) jerry_release_value (arraybuffer); } + /* Test zero length external ArrayBuffer */ + { + const uint32_t length = 0; + jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, NULL, NULL); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + uint8_t data[20]; + memset (data, 11, 20); + + jerry_length_t bytes_written = jerry_arraybuffer_write (arraybuffer, 0, data, 20); + TEST_ASSERT (bytes_written == 0); + + jerry_release_value (arraybuffer); + } + /* Test ArrayBuffer with buffer allocated externally */ { const uint32_t buffer_size = 15; @@ -287,6 +304,7 @@ main (void) /* Test ArrayBuffer external memory map/unmap */ { const uint32_t buffer_size = 20; + /* cppcheck-suppress variableScope */ JERRY_VLA (uint8_t, buffer_p, buffer_size); { jerry_value_t input_buffer = jerry_create_arraybuffer_external (buffer_size, buffer_p, NULL); @@ -322,7 +340,7 @@ main (void) double sum = 0; for (int i = 0; i < 20; i++) { - data[i] = (uint8_t)(i * 3); + data[i] = (uint8_t) (i * 3); sum += data[i]; } @@ -346,12 +364,49 @@ main (void) jerry_release_value (buffer); } - /* Test ArrayBuffer external with invalid arguments */ + /* Test ArrayBuffer detach */ { - jerry_value_t input_buffer = jerry_create_arraybuffer_external (0, NULL, NULL); - TEST_ASSERT (jerry_value_is_error (input_buffer)); - TEST_ASSERT (jerry_get_error_type (input_buffer) == JERRY_ERROR_RANGE); - jerry_release_value (input_buffer); + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer (length); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (!jerry_get_boolean_value (is_detachable)); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (jerry_value_is_error (res)); + + jerry_release_value (res); + jerry_release_value (arraybuffer); + } + + /* Test external ArrayBuffer detach */ + { + uint8_t buf[1]; + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, buf, NULL); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (res)); + + is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (!jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_release_value (res); + jerry_release_value (arraybuffer); } jerry_cleanup (); diff --git a/tests/unit-core/test-common.h b/tests/unit-core/test-common.h index 24c115a6..aaa942d2 100644 --- a/tests/unit-core/test-common.h +++ b/tests/unit-core/test-common.h @@ -49,7 +49,8 @@ #define TEST_INIT() \ do \ { \ - srand ((unsigned) jerry_port_get_current_time ()); \ + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; \ + srand (now.u); \ } while (0) /** diff --git a/tests/unit-core/test-container.c b/tests/unit-core/test-container.c new file mode 100644 index 00000000..031f2b42 --- /dev/null +++ b/tests/unit-core/test-container.c @@ -0,0 +1,86 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "test-common.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + if (!jerry_is_feature_enabled (JERRY_FEATURE_MAP) + || !jerry_is_feature_enabled (JERRY_FEATURE_SET) + || !jerry_is_feature_enabled (JERRY_FEATURE_WEAKMAP) + || !jerry_is_feature_enabled (JERRY_FEATURE_WEAKSET)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Containers are disabled!\n"); + jerry_cleanup (); + return 0; + } + + jerry_value_t instance_check; + jerry_value_t global = jerry_get_global_object (); + jerry_value_t map_str = jerry_create_string ((jerry_char_t *) "Map"); + jerry_value_t set_str = jerry_create_string ((jerry_char_t *) "Set"); + jerry_value_t weakmap_str = jerry_create_string ((jerry_char_t *) "WeakMap"); + jerry_value_t weakset_str = jerry_create_string ((jerry_char_t *) "WeakSet"); + jerry_value_t global_map = jerry_get_property (global, map_str); + jerry_value_t global_set = jerry_get_property (global, set_str); + jerry_value_t global_weakmap = jerry_get_property (global, weakmap_str); + jerry_value_t global_weakset = jerry_get_property (global, weakset_str); + + jerry_release_value (global); + + jerry_release_value (map_str); + jerry_release_value (set_str); + jerry_release_value (weakmap_str); + jerry_release_value (weakset_str); + + jerry_value_t empty_map = jerry_create_container (JERRY_CONTAINER_TYPE_MAP, NULL, 0); + TEST_ASSERT (jerry_get_container_type (empty_map) == JERRY_CONTAINER_TYPE_MAP); + instance_check = jerry_binary_operation (JERRY_BIN_OP_INSTANCEOF, empty_map, global_map); + TEST_ASSERT (jerry_get_boolean_value (instance_check)); + jerry_release_value (instance_check); + jerry_release_value (global_map); + jerry_release_value (empty_map); + + jerry_value_t empty_set = jerry_create_container (JERRY_CONTAINER_TYPE_SET, NULL, 0); + TEST_ASSERT (jerry_get_container_type (empty_set) == JERRY_CONTAINER_TYPE_SET); + instance_check = jerry_binary_operation (JERRY_BIN_OP_INSTANCEOF, empty_set, global_set); + TEST_ASSERT (jerry_get_boolean_value (instance_check)); + jerry_release_value (instance_check); + jerry_release_value (global_set); + jerry_release_value (empty_set); + + jerry_value_t empty_weakmap = jerry_create_container (JERRY_CONTAINER_TYPE_WEAKMAP, NULL, 0); + TEST_ASSERT (jerry_get_container_type (empty_weakmap) == JERRY_CONTAINER_TYPE_WEAKMAP); + instance_check = jerry_binary_operation (JERRY_BIN_OP_INSTANCEOF, empty_weakmap, global_weakmap); + TEST_ASSERT (jerry_get_boolean_value (instance_check)); + jerry_release_value (instance_check); + jerry_release_value (global_weakmap); + jerry_release_value (empty_weakmap); + + jerry_value_t empty_weakset = jerry_create_container (JERRY_CONTAINER_TYPE_WEAKSET, NULL, 0); + TEST_ASSERT (jerry_get_container_type (empty_weakset) == JERRY_CONTAINER_TYPE_WEAKSET); + instance_check = jerry_binary_operation (JERRY_BIN_OP_INSTANCEOF, empty_weakset, global_weakset); + TEST_ASSERT (jerry_get_boolean_value (instance_check)); + jerry_release_value (instance_check); + jerry_release_value (global_weakset); + jerry_release_value (empty_weakset); + + jerry_cleanup (); + return 0; +} /* main */ diff --git a/tests/unit-core/test-context-data.c b/tests/unit-core/test-context-data.c index 15221168..d2ef7c57 100644 --- a/tests/unit-core/test-context-data.c +++ b/tests/unit-core/test-context-data.c @@ -113,7 +113,6 @@ test_context_data4_new (void *user_data_p) TEST_ASSERT (user_data_p == NULL); } /* test_context_data4_new */ - static void test_context_data4_free (void *user_data_p) { @@ -138,7 +137,6 @@ static const jerry_context_data_manager_t manager4 = .bytes_needed = 0 }; - int main (void) { diff --git a/tests/unit-core/test-internal-properties.c b/tests/unit-core/test-internal-properties.c new file mode 100644 index 00000000..c9a5ec9b --- /dev/null +++ b/tests/unit-core/test-internal-properties.c @@ -0,0 +1,240 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t object = jerry_create_object (); + + jerry_value_t prop_name_1 = jerry_create_string ((const jerry_char_t *) "foo"); + jerry_value_t prop_name_2 = jerry_create_string ((const jerry_char_t *) "non_hidden_prop"); + jerry_value_t prop_name_3; + + if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_value_t prop_name_3_desc = jerry_create_string ((const jerry_char_t *) "bar"); + prop_name_3 = jerry_create_symbol (prop_name_3_desc); + jerry_release_value (prop_name_3_desc); + } + else + { + prop_name_3 = jerry_create_string ((const jerry_char_t *) "non_hidden_string_prop"); + } + + jerry_value_t internal_prop_name_1 = jerry_create_string ((const jerry_char_t *) "hidden_foo"); + jerry_value_t internal_prop_name_2 = jerry_create_string ((const jerry_char_t *) "hidden_prop"); + jerry_value_t internal_prop_name_3; + + if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_value_t internal_prop_name_3_desc = jerry_create_string ((const jerry_char_t *) "bar"); + internal_prop_name_3 = jerry_create_symbol (internal_prop_name_3_desc); + jerry_release_value (internal_prop_name_3_desc); + } + else + { + internal_prop_name_3 = jerry_create_string ((const jerry_char_t *) "hidden_string_prop"); + } + + jerry_value_t prop_value_1 = jerry_create_number (5.5); + jerry_value_t prop_value_2 = jerry_create_number (6.5); + jerry_value_t prop_value_3 = jerry_create_number (7.5); + + jerry_value_t internal_prop_value_1 = jerry_create_number (8.5); + jerry_value_t internal_prop_value_2 = jerry_create_number (9.5); + jerry_value_t internal_prop_value_3 = jerry_create_number (10.5); + + /* Test the normal [[Set]] method */ + bool set_result_1 = jerry_set_property (object, prop_name_1, prop_value_1); + bool set_result_2 = jerry_set_property (object, prop_name_2, prop_value_2); + bool set_result_3 = jerry_set_property (object, prop_name_3, prop_value_3); + + TEST_ASSERT (set_result_1); + TEST_ASSERT (set_result_2); + TEST_ASSERT (set_result_3); + + /* Test the internal [[Set]] method */ + bool set_internal_result_1 = jerry_set_internal_property (object, internal_prop_name_1, internal_prop_value_1); + bool set_internal_result_2 = jerry_set_internal_property (object, internal_prop_name_2, internal_prop_value_2); + bool set_internal_result_3 = jerry_set_internal_property (object, internal_prop_name_3, internal_prop_value_3); + + TEST_ASSERT (set_internal_result_1); + TEST_ASSERT (set_internal_result_2); + TEST_ASSERT (set_internal_result_3); + + /* Test the normal [[Has]] method. */ + jerry_value_t has_result_1 = jerry_has_property (object, prop_name_1); + jerry_value_t has_result_2 = jerry_has_property (object, prop_name_2); + jerry_value_t has_result_3 = jerry_has_property (object, prop_name_3); + jerry_value_t has_result_4 = jerry_has_property (object, internal_prop_name_1); + jerry_value_t has_result_5 = jerry_has_property (object, internal_prop_name_2); + jerry_value_t has_result_6 = jerry_has_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_boolean (has_result_1) && jerry_get_boolean_value (has_result_1)); + TEST_ASSERT (jerry_value_is_boolean (has_result_2) && jerry_get_boolean_value (has_result_2)); + TEST_ASSERT (jerry_value_is_boolean (has_result_3) && jerry_get_boolean_value (has_result_3)); + TEST_ASSERT (jerry_value_is_boolean (has_result_4) && !jerry_get_boolean_value (has_result_4)); + TEST_ASSERT (jerry_value_is_boolean (has_result_5) && !jerry_get_boolean_value (has_result_5)); + TEST_ASSERT (jerry_value_is_boolean (has_result_6) && !jerry_get_boolean_value (has_result_6)); + + jerry_release_value (has_result_1); + jerry_release_value (has_result_2); + jerry_release_value (has_result_3); + jerry_release_value (has_result_4); + jerry_release_value (has_result_5); + jerry_release_value (has_result_6); + + /* Test the internal [[Has]] method. */ + bool has_internal_result_1 = jerry_has_internal_property (object, prop_name_1); + bool has_internal_result_2 = jerry_has_internal_property (object, prop_name_2); + bool has_internal_result_3 = jerry_has_internal_property (object, prop_name_3); + bool has_internal_result_4 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_internal_result_5 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_internal_result_6 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (!has_internal_result_1); + TEST_ASSERT (!has_internal_result_2); + TEST_ASSERT (!has_internal_result_3); + TEST_ASSERT (has_internal_result_4); + TEST_ASSERT (has_internal_result_5); + TEST_ASSERT (has_internal_result_6); + + /* Test the normal [[Get]] method. */ + jerry_value_t get_result_1 = jerry_get_property (object, prop_name_1); + jerry_value_t get_result_2 = jerry_get_property (object, prop_name_2); + jerry_value_t get_result_3 = jerry_get_property (object, prop_name_3); + jerry_value_t get_result_4 = jerry_get_property (object, internal_prop_name_1); + jerry_value_t get_result_5 = jerry_get_property (object, internal_prop_name_2); + jerry_value_t get_result_6 = jerry_get_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_number (get_result_1) && jerry_get_number_value (get_result_1) == 5.5); + TEST_ASSERT (jerry_value_is_number (get_result_2) && jerry_get_number_value (get_result_2) == 6.5); + TEST_ASSERT (jerry_value_is_number (get_result_3) && jerry_get_number_value (get_result_3) == 7.5); + TEST_ASSERT (jerry_value_is_undefined (get_result_4)); + TEST_ASSERT (jerry_value_is_undefined (get_result_5)); + TEST_ASSERT (jerry_value_is_undefined (get_result_6)); + + jerry_release_value (get_result_1); + jerry_release_value (get_result_2); + jerry_release_value (get_result_3); + jerry_release_value (get_result_4); + jerry_release_value (get_result_5); + jerry_release_value (get_result_6); + + /* Test the internal [[Get]] method. */ + jerry_value_t get_internal_result_1 = jerry_get_internal_property (object, prop_name_1); + jerry_value_t get_internal_result_2 = jerry_get_internal_property (object, prop_name_2); + jerry_value_t get_internal_result_3 = jerry_get_internal_property (object, prop_name_3); + jerry_value_t get_internal_result_4 = jerry_get_internal_property (object, internal_prop_name_1); + jerry_value_t get_internal_result_5 = jerry_get_internal_property (object, internal_prop_name_2); + jerry_value_t get_internal_result_6 = jerry_get_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_1)); + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_2)); + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_3)); + TEST_ASSERT (jerry_value_is_number (get_internal_result_4) && jerry_get_number_value (get_internal_result_4) == 8.5); + TEST_ASSERT (jerry_value_is_number (get_internal_result_5) && jerry_get_number_value (get_internal_result_5) == 9.5); + TEST_ASSERT (jerry_value_is_number (get_internal_result_6) && jerry_get_number_value (get_internal_result_6) == 10.5); + + jerry_release_value (get_internal_result_1); + jerry_release_value (get_internal_result_2); + jerry_release_value (get_internal_result_3); + jerry_release_value (get_internal_result_4); + jerry_release_value (get_internal_result_5); + jerry_release_value (get_internal_result_6); + + /* Test the normal [[Delete]] method. */ + bool delete_result_1 = jerry_delete_property (object, prop_name_1); + bool delete_result_2 = jerry_delete_property (object, prop_name_2); + bool delete_result_3 = jerry_delete_property (object, prop_name_3); + bool delete_result_4 = jerry_delete_property (object, internal_prop_name_1); + bool delete_result_5 = jerry_delete_property (object, internal_prop_name_2); + bool delete_result_6 = jerry_delete_property (object, internal_prop_name_3); + + TEST_ASSERT (delete_result_1); + TEST_ASSERT (delete_result_2); + TEST_ASSERT (delete_result_3); + TEST_ASSERT (delete_result_4); + TEST_ASSERT (delete_result_5); + TEST_ASSERT (delete_result_6); + + jerry_value_t has_after_delete_result_1 = jerry_has_property (object, prop_name_1); + jerry_value_t has_after_delete_result_2 = jerry_has_property (object, prop_name_2); + jerry_value_t has_after_delete_result_3 = jerry_has_property (object, prop_name_3); + bool has_after_delete_result_4 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_after_delete_result_5 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_after_delete_result_6 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_1) + && !jerry_get_boolean_value (has_after_delete_result_1)); + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_2) + && !jerry_get_boolean_value (has_after_delete_result_2)); + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_3) + && !jerry_get_boolean_value (has_after_delete_result_3)); + TEST_ASSERT (has_after_delete_result_4); + TEST_ASSERT (has_after_delete_result_5); + TEST_ASSERT (has_after_delete_result_6); + + jerry_release_value (has_after_delete_result_1); + jerry_release_value (has_after_delete_result_2); + jerry_release_value (has_after_delete_result_3); + + /* Test the internal [[Delete]] method. */ + bool delete_internal_result_4 = jerry_delete_internal_property (object, internal_prop_name_1); + bool delete_internal_result_5 = jerry_delete_internal_property (object, internal_prop_name_2); + bool delete_internal_result_6 = jerry_delete_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (delete_internal_result_4); + TEST_ASSERT (delete_internal_result_5); + TEST_ASSERT (delete_internal_result_6); + + bool has_after_internal_delete_result_1 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_after_internal_delete_result_2 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_after_internal_delete_result_3 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (!has_after_internal_delete_result_1); + TEST_ASSERT (!has_after_internal_delete_result_2); + TEST_ASSERT (!has_after_internal_delete_result_3); + + /* Cleanup */ + jerry_release_value (prop_value_3); + jerry_release_value (prop_value_2); + jerry_release_value (prop_value_1); + + jerry_release_value (prop_name_3); + jerry_release_value (prop_name_2); + jerry_release_value (prop_name_1); + + jerry_release_value (internal_prop_value_3); + jerry_release_value (internal_prop_value_2); + jerry_release_value (internal_prop_value_1); + + jerry_release_value (internal_prop_name_3); + jerry_release_value (internal_prop_name_2); + jerry_release_value (internal_prop_name_1); + + jerry_release_value (object); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-lit-char-helpers.c b/tests/unit-core/test-lit-char-helpers.c index c203e5c3..7374a7e1 100644 --- a/tests/unit-core/test-lit-char-helpers.c +++ b/tests/unit-core/test-lit-char-helpers.c @@ -21,6 +21,39 @@ #include "test-common.h" +static lit_code_point_t +lexer_hex_to_character (const uint8_t *source_p) /**< current source position */ +{ + lit_code_point_t result = 0; + + do + { + uint32_t byte = *source_p++; + + result <<= 4; + + if (byte >= LIT_CHAR_0 && byte <= LIT_CHAR_9) + { + result += byte - LIT_CHAR_0; + } + else + { + byte = LEXER_TO_ASCII_LOWERCASE (byte); + if (byte >= LIT_CHAR_LOWERCASE_A && byte <= LIT_CHAR_LOWERCASE_F) + { + result += byte - (LIT_CHAR_LOWERCASE_A - 10); + } + else + { + return UINT32_MAX; + } + } + } + while (*source_p); + + return result; +} /* lexer_hex_to_character */ + int main (void) { @@ -29,50 +62,59 @@ main (void) jmem_init (); ecma_init (); - const uint8_t _1_byte_long1[] = "\\u007F"; - const uint8_t _1_byte_long2[] = "\\u0000"; - const uint8_t _1_byte_long3[] = "\\u0065"; + const uint8_t _1_byte_long1[] = "007F"; + const uint8_t _1_byte_long2[] = "0000"; + const uint8_t _1_byte_long3[] = "0065"; - const uint8_t _2_byte_long1[] = "\\u008F"; - const uint8_t _2_byte_long2[] = "\\u00FF"; - const uint8_t _2_byte_long3[] = "\\u07FF"; + const uint8_t _2_byte_long1[] = "008F"; + const uint8_t _2_byte_long2[] = "00FF"; + const uint8_t _2_byte_long3[] = "07FF"; - const uint8_t _3_byte_long1[] = "\\u08FF"; - const uint8_t _3_byte_long2[] = "\\u0FFF"; - const uint8_t _3_byte_long3[] = "\\uFFFF"; + const uint8_t _3_byte_long1[] = "08FF"; + const uint8_t _3_byte_long2[] = "0FFF"; + const uint8_t _3_byte_long3[] = "FFFF"; + + const uint8_t _6_byte_long1[] = "10000"; + const uint8_t _6_byte_long2[] = "10FFFF"; size_t length; /* Test 1-byte-long unicode sequences. */ - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _1_byte_long1 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_1_byte_long1)); TEST_ASSERT (length == 1); - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _1_byte_long2 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_1_byte_long2)); TEST_ASSERT (length == 1); - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _1_byte_long3 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_1_byte_long3)); TEST_ASSERT (length == 1); /* Test 2-byte-long unicode sequences. */ - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _2_byte_long1 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_2_byte_long1)); TEST_ASSERT (length == 2); - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _2_byte_long2 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_2_byte_long2)); TEST_ASSERT (length == 2); - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _2_byte_long3 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_2_byte_long3)); TEST_ASSERT (length == 2); /* Test 3-byte-long unicode sequences. */ - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _3_byte_long1 + 2, 4)); - TEST_ASSERT (length != 2); - - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _3_byte_long2 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_3_byte_long1)); TEST_ASSERT (length == 3); - length = lit_char_get_utf8_length (lexer_hex_to_character (0, _3_byte_long3 + 2, 4)); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_3_byte_long2)); TEST_ASSERT (length == 3); + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_3_byte_long3)); + TEST_ASSERT (length == 3); + + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_6_byte_long1)); + TEST_ASSERT (length == 6); + + length = lit_code_point_get_cesu8_length (lexer_hex_to_character (_6_byte_long2)); + TEST_ASSERT (length == 6); + ecma_finalize (); jmem_finalize (); diff --git a/tests/unit-core/test-mem-stats.c b/tests/unit-core/test-mem-stats.c index 322eb27c..2a29ae6e 100644 --- a/tests/unit-core/test-mem-stats.c +++ b/tests/unit-core/test-mem-stats.c @@ -16,7 +16,6 @@ #include "jerryscript.h" #include "test-common.h" - int main (void) { if (!jerry_is_feature_enabled (JERRY_FEATURE_MEM_STATS)) diff --git a/tests/unit-core/test-native-callback-nested.c b/tests/unit-core/test-native-callback-nested.c new file mode 100644 index 00000000..0d5b067d --- /dev/null +++ b/tests/unit-core/test-native-callback-nested.c @@ -0,0 +1,68 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +static void native_cb2 (void) +{ + jerry_value_t array = jerry_create_array (100); + jerry_release_value (array); +} /* native_cb2 */ + +static const jerry_object_native_info_t native_info2 = +{ + .free_cb = (jerry_object_native_free_callback_t) native_cb2 +}; + +static void native_cb (void) +{ + jerry_value_t array = jerry_create_array (100); + + jerry_set_object_native_pointer (array, NULL, &native_info2); + + jerry_release_value (array); +} /* native_cb */ + +static const jerry_object_native_info_t native_info = +{ + .free_cb = (jerry_object_native_free_callback_t) native_cb +}; + +static void * +context_alloc_fn (size_t size, void *cb_data) +{ + (void) cb_data; + return malloc (size); +} /* context_alloc_fn */ + +int +main (void) +{ + jerry_context_t *ctx_p = jerry_create_context (1024, context_alloc_fn, NULL); + jerry_port_default_set_current_context (ctx_p); + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t obj = jerry_create_object (); + + jerry_set_object_native_pointer (obj, NULL, &native_info); + jerry_release_value (obj); + + jerry_cleanup (); + free (ctx_p); + return 0; +} /* main */ diff --git a/tests/unit-core/test-native-instanceof.c b/tests/unit-core/test-native-instanceof.c new file mode 100644 index 00000000..7954c510 --- /dev/null +++ b/tests/unit-core/test-native-instanceof.c @@ -0,0 +1,86 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "test-common.h" + +static const char instanceof_source[] = "var x = function(o, c) {return (o instanceof c);}; x"; + +static jerry_value_t +external_function (const jerry_value_t function_obj, + const jerry_value_t this_arg, + const jerry_value_t args_p[], + const jerry_size_t args_count) +{ + (void) function_obj; + (void) this_arg; + (void) args_p; + (void) args_count; + + return jerry_create_undefined (); +} /* external_function */ + +static void +test_instanceof (jerry_value_t instanceof, + jerry_value_t constructor) +{ + jerry_value_t instance = jerry_construct_object (constructor, NULL, 0); + jerry_value_t args[2] = + { + instance, constructor + }; + + jerry_value_t undefined = jerry_create_undefined (); + jerry_value_t result = jerry_call_function (instanceof, undefined, args, 2); + jerry_release_value (undefined); + + TEST_ASSERT (!jerry_value_is_error (result)); + TEST_ASSERT (jerry_value_is_boolean (result)); + + TEST_ASSERT (jerry_get_boolean_value (result)); + + jerry_release_value (instance); + jerry_release_value (result); +} /* test_instanceof */ + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t instanceof = jerry_eval ((jerry_char_t *) instanceof_source, sizeof (instanceof_source) - 1, true); + + /* Test for a native-backed function. */ + jerry_value_t constructor = jerry_create_external_function (external_function); + + test_instanceof (instanceof, constructor); + jerry_release_value (constructor); + + /* Test for a JS constructor. */ + jerry_value_t global = jerry_get_global_object (); + jerry_value_t object_name = jerry_create_string ((jerry_char_t *) "Object"); + constructor = jerry_get_property (global, object_name); + jerry_release_value (object_name); + jerry_release_value (global); + + test_instanceof (instanceof, constructor); + jerry_release_value (constructor); + + jerry_release_value (instanceof); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-newtarget.c b/tests/unit-core/test-newtarget.c new file mode 100644 index 00000000..606991d2 --- /dev/null +++ b/tests/unit-core/test-newtarget.c @@ -0,0 +1,213 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +/** + * Register a JavaScript function in the global object. + */ +static jerry_value_t +register_js_function (const char *name_p, /**< name of the function */ + jerry_external_handler_t handler_p) /**< function callback */ +{ + jerry_value_t global_obj_val = jerry_get_global_object (); + + jerry_value_t function_val = jerry_create_external_function (handler_p); + jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) name_p); + jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val); + + jerry_release_value (function_name_val); + jerry_release_value (global_obj_val); + + jerry_release_value (result_val); + + return function_val; +} /* register_js_function */ + +enum +{ + TEST_ID_SIMPLE_CONSTRUCT = 1, + TEST_ID_SIMPLE_CALL = 2, + TEST_ID_CONSTRUCT_AND_CALL_SUB = 3, +}; + +static jerry_value_t +construct_handler (const jerry_value_t func_obj_val, /**< function object */ + const jerry_value_t this_val, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + JERRY_UNUSED (func_obj_val); + JERRY_UNUSED (this_val); + JERRY_UNUSED (args_p); + + if (args_cnt != 1 || !jerry_value_is_number (args_p[0])) + { + TEST_ASSERT (0 && "Invalid arguments for demo method"); + } + + int test_id = (int) jerry_get_number_value (args_p[0]); + + switch (test_id) + { + case TEST_ID_SIMPLE_CONSTRUCT: + { + /* Method was called with "new": new.target should be equal to the function object. */ + jerry_value_t target = jerry_get_new_target (); + TEST_ASSERT (!jerry_value_is_undefined (target)); + TEST_ASSERT (target == func_obj_val); + jerry_release_value (target); + break; + } + case TEST_ID_SIMPLE_CALL: + { + /* Method was called directly without "new": new.target should be equal undefined. */ + jerry_value_t target = jerry_get_new_target (); + TEST_ASSERT (jerry_value_is_undefined (target)); + TEST_ASSERT (target != func_obj_val); + jerry_release_value (target); + break; + } + case TEST_ID_CONSTRUCT_AND_CALL_SUB: + { + /* Method was called with "new": new.target should be equal to the function object. */ + jerry_value_t target = jerry_get_new_target (); + TEST_ASSERT (!jerry_value_is_undefined (target)); + TEST_ASSERT (target == func_obj_val); + jerry_release_value (target); + + /* Calling a function should hide the old "new.target". */ + jerry_value_t sub_arg = jerry_create_number (TEST_ID_SIMPLE_CALL); + jerry_value_t func_call_result = jerry_call_function (func_obj_val, this_val, &sub_arg, 1); + TEST_ASSERT (!jerry_value_is_error (func_call_result)); + TEST_ASSERT (jerry_value_is_undefined (func_call_result)); + break; + } + + default: + { + TEST_ASSERT (0 && "Incorrect test ID"); + break; + } + } + + return jerry_create_undefined (); +} /* construct_handler */ + +int +main (void) +{ + /* Test JERRY_FEATURE_SYMBOL feature as it is a must-have in ES2015 */ + if (!jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Skipping test, ES2015 support is disabled.\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t demo_func = register_js_function ("Demo", construct_handler); + + { + jerry_value_t test_arg = jerry_create_number (TEST_ID_SIMPLE_CONSTRUCT); + jerry_value_t constructed = jerry_construct_object (demo_func, &test_arg, 1); + TEST_ASSERT (!jerry_value_is_error (constructed)); + TEST_ASSERT (jerry_value_is_object (constructed)); + jerry_release_value (test_arg); + jerry_release_value (constructed); + } + + { + jerry_value_t test_arg = jerry_create_number (TEST_ID_SIMPLE_CALL); + jerry_value_t this_arg = jerry_create_undefined (); + jerry_value_t constructed = jerry_call_function (demo_func, this_arg, &test_arg, 1); + TEST_ASSERT (jerry_value_is_undefined (constructed)); + jerry_release_value (constructed); + jerry_release_value (constructed); + jerry_release_value (test_arg); + } + + { + jerry_value_t test_arg = jerry_create_number (TEST_ID_CONSTRUCT_AND_CALL_SUB); + jerry_value_t constructed = jerry_construct_object (demo_func, &test_arg, 1); + TEST_ASSERT (!jerry_value_is_error (constructed)); + TEST_ASSERT (jerry_value_is_object (constructed)); + jerry_release_value (test_arg); + jerry_release_value (constructed); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ("new Demo (1)"); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t res = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (res)); + + jerry_release_value (res); + jerry_release_value (parsed_code_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ("Demo (2)"); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t res = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (res)); + + jerry_release_value (res); + jerry_release_value (parsed_code_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( + "function base(arg) { new Demo (arg); };" + "base (1);" + "new base(1);" + "new base(3);" + ); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t res = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (res)); + + jerry_release_value (res); + jerry_release_value (parsed_code_val); + } + + jerry_release_value (demo_func); + jerry_cleanup (); + return 0; +} /* main */ diff --git a/tests/unit-core/test-objects-foreach.c b/tests/unit-core/test-objects-foreach.c index c291a294..cce1949e 100644 --- a/tests/unit-core/test-objects-foreach.c +++ b/tests/unit-core/test-objects-foreach.c @@ -16,6 +16,122 @@ #include "jerryscript.h" #include "test-common.h" +static bool +count_objects (jerry_value_t object, void *user_arg) +{ + (void) object; + TEST_ASSERT (user_arg != NULL); + + int *counter = (int *) user_arg; + + (*counter)++; + return true; +} /* count_objects */ + +static void +test_container (void) +{ + jerry_value_t global = jerry_get_global_object (); + jerry_value_t map_str = jerry_create_string ((const jerry_char_t *) "Map"); + jerry_value_t map_result = jerry_get_property (global, map_str); + jerry_type_t type = jerry_value_get_type (map_result); + + jerry_release_value (map_result); + jerry_release_value (map_str); + jerry_release_value (global); + + /* If there is no Map function this is not an es2015 profile build, skip this test case. */ + if (type != JERRY_TYPE_FUNCTION) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Container based test is disabled!\n"); + return; + } + + { + /* Create a "DEMO" array which will be used for the Map below. */ + const char array_str[] = "var DEMO = [[1, 2], [3, 4]]; DEMO"; + jerry_value_t array = jerry_eval ((const jerry_char_t *) array_str, sizeof (array_str) - 1, 0); + TEST_ASSERT (jerry_value_is_object (array)); + TEST_ASSERT (!jerry_value_is_error (array)); + jerry_release_value (array); + } + + const char eval_str[] = "new Map (DEMO)"; + { + /* Make sure that the Map and it's prototype object/function is initialized. */ + jerry_value_t result = jerry_eval ((const jerry_char_t *) eval_str, sizeof (eval_str) - 1, 0); + TEST_ASSERT (jerry_value_is_object (result)); + TEST_ASSERT (!jerry_value_is_error (result)); + jerry_release_value (result); + } + + /* Do a bit of cleaning to clear up old objects. */ + jerry_gc (JERRY_GC_PRESSURE_LOW); + + /* Get the number of iterable objects. */ + int start_count = 0; + jerry_objects_foreach (count_objects, &start_count); + + /* Create another map. */ + jerry_value_t result = jerry_eval ((const jerry_char_t *) eval_str, sizeof (eval_str) - 1, 0); + + /* Remove any old/unused objects. */ + jerry_gc (JERRY_GC_PRESSURE_LOW); + + /* Get the current number of objects. */ + int end_count = 0; + jerry_objects_foreach (count_objects, &end_count); + + /* As only one Map was created the number of available iterable objects should be incremented only by one. */ + TEST_ASSERT (end_count > start_count); + TEST_ASSERT ((end_count - start_count) == 1); + + jerry_release_value (result); +} /* test_container */ + +static void +test_internal_prop (void) +{ + /* Make sure that the object is initialized in the engine. */ + { + jerry_value_t object = jerry_create_object (); + jerry_release_value (object); + } + + /* Get the number of iterable objects. */ + int before_object_count = 0; + jerry_objects_foreach (count_objects, &before_object_count); + + jerry_value_t object = jerry_create_object (); + + /* After creating the object, the number of objects is incremented by one. */ + int after_object_count = 0; + { + jerry_objects_foreach (count_objects, &after_object_count); + + TEST_ASSERT (after_object_count > before_object_count); + TEST_ASSERT ((after_object_count - before_object_count) == 1); + } + + jerry_value_t internal_prop_name = jerry_create_string ((const jerry_char_t *) "hidden_foo"); + jerry_value_t internal_prop_object = jerry_create_object (); + bool internal_result = jerry_set_internal_property (object, internal_prop_name, internal_prop_object); + TEST_ASSERT (internal_result == true); + jerry_release_value (internal_prop_name); + jerry_release_value (internal_prop_object); + + /* After adding an internal property object, the number of object is incremented by one. */ + { + int after_internal_count = 0; + jerry_objects_foreach (count_objects, &after_internal_count); + + TEST_ASSERT (after_internal_count > after_object_count); + TEST_ASSERT ((after_internal_count - after_object_count) == 1); + } + + jerry_release_value (object); +} /* test_internal_prop */ + static int test_data = 1; static void free_test_data (void *data_p) @@ -133,5 +249,11 @@ main (void) jerry_release_value (property_name); jerry_release_value (undefined); jerry_release_value (strict_equal); + + test_container (); + test_internal_prop (); + jerry_cleanup (); + + return 0; } /* main */ diff --git a/tests/unit-core/test-promise.c b/tests/unit-core/test-promise.c index bd37fc40..2103efea 100644 --- a/tests/unit-core/test-promise.c +++ b/tests/unit-core/test-promise.c @@ -18,7 +18,6 @@ #include "jerryscript-port-default.h" #include "test-common.h" - static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( "var p1 = create_promise1();" "var p2 = create_promise2();" diff --git a/tests/unit-core/test-proxy.c b/tests/unit-core/test-proxy.c new file mode 100644 index 00000000..2bd382cf --- /dev/null +++ b/tests/unit-core/test-proxy.c @@ -0,0 +1,250 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "jerryscript.h" + +#include "test-common.h" + +/** Test in Proxy on C side. Equivalent test code in JS: + +var demo = 0.0; + +var target = {}; +var handler = { + get: function (target, name, recv) { + assert (typeof (target) === 'object'); + assert (name === 'value'); + assert (typeof (recv) === 'object'); + return demo++; + } + + set: function (target, name, value, recv) { + assert (typeof (target) === 'object'); + assert (name === 'value'); + assert (typeof (recv) === 'object'); + demo = 55; + return demo; + } +}; + +var pdemo = new Proxy(target, handler); + +assert (pdemo.value === 1.0); +assert (pdemo.value === 1.0); +assert (pdemo.value === 2.0); + +pdemo.value = 55; + +assert (pdemo.value === 56); + +pdemo.value = 12; + +assert (pdemo.value === 13); + */ + +static int demo_value = 0; + +static jerry_value_t +handler_get (const jerry_value_t function_obj, /**< function object */ + const jerry_value_t this_val, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_count) /**< number of function arguments */ +{ + JERRY_UNUSED (function_obj); + JERRY_UNUSED (this_val); + + TEST_ASSERT (args_count == 3); + TEST_ASSERT (jerry_value_is_object (args_p[0])); /* target */ + TEST_ASSERT (jerry_value_is_string (args_p[1])); /* P */ + TEST_ASSERT (jerry_value_is_object (args_p[2])); /* receiver */ + + const char expected[] = "value"; + char buffer[10]; + jerry_size_t copied = jerry_string_to_char_buffer (args_p[1], (jerry_char_t *) buffer, 10); + + TEST_ASSERT (copied == 5); + TEST_ASSERT (strncmp (expected, buffer, 5) == 0); + + demo_value++; + + return jerry_create_number (demo_value); +} /* handler_get */ + +static jerry_value_t +handler_set (const jerry_value_t function_obj, /**< function object */ + const jerry_value_t this_val, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_count) /**< number of function arguments */ +{ + JERRY_UNUSED (function_obj); + JERRY_UNUSED (this_val); + JERRY_UNUSED (args_p); + JERRY_UNUSED (args_count); + + TEST_ASSERT (args_count == 4); + TEST_ASSERT (jerry_value_is_object (args_p[0])); /* target */ + TEST_ASSERT (jerry_value_is_string (args_p[1])); /* P */ + TEST_ASSERT (jerry_value_is_number (args_p[2])); /* V */ + TEST_ASSERT (jerry_value_is_object (args_p[3])); /* receiver */ + + const char expected[] = "value"; + char buffer[10]; + jerry_size_t copied = jerry_string_to_char_buffer (args_p[1], (jerry_char_t *) buffer, 10); + + TEST_ASSERT (copied == 5); + TEST_ASSERT (strncmp (expected, buffer, 5) == 0); + + TEST_ASSERT (jerry_value_is_number (args_p[2])); + demo_value = (int) jerry_get_number_value (args_p[2]); + + return jerry_create_number (demo_value); +} /* handler_set */ + +static void +set_property (jerry_value_t target, /**< target object */ + const char *name_p, /**< name of the property */ + jerry_value_t value) /**< value of the property */ +{ + jerry_value_t name_val = jerry_create_string ((const jerry_char_t *) name_p); + jerry_value_t result_val = jerry_set_property (target, name_val, value); + + TEST_ASSERT (jerry_value_is_boolean (result_val)); + TEST_ASSERT (jerry_get_boolean_value (result_val)); + jerry_release_value (name_val); +} /* set_property */ + +static jerry_value_t +get_property (jerry_value_t target, /**< target object */ + const char *name_p) /**< name of the property */ +{ + jerry_value_t name_val = jerry_create_string ((const jerry_char_t *) name_p); + jerry_value_t result_val = jerry_get_property (target, name_val); + + TEST_ASSERT (!jerry_value_is_error (result_val)); + jerry_release_value (name_val); + return result_val; +} /* get_property */ + +static void +set_function (jerry_value_t target, /**< target object */ + const char *name_p, /**< name of the function */ + jerry_external_handler_t handler_p) /**< function callback */ +{ + jerry_value_t function_val = jerry_create_external_function (handler_p); + set_property (target, name_p, function_val); + jerry_release_value (function_val); +} /* set_function */ + +int +main (void) +{ + TEST_INIT (); + + if (!jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + printf ("Skipping test, Proxy not enabled\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t handler = jerry_create_object (); + { + set_function (handler, "get", handler_get); + set_function (handler, "set", handler_set); + } + + jerry_value_t target = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + { + jerry_value_t global = jerry_get_global_object (); + set_property (global, "pdemo", proxy); + jerry_release_value (global); + } + + const jerry_char_t get_value_src[] = TEST_STRING_LITERAL ("pdemo.value"); + jerry_value_t parsed_get_code_val = jerry_parse (NULL, + 0, + get_value_src, + sizeof (get_value_src) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_get_code_val)); + + { + jerry_value_t res = jerry_run (parsed_get_code_val); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 1.0); + jerry_release_value (res); + } + + { + jerry_value_t res = get_property (proxy, "value"); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 2.0); + jerry_release_value (res); + } + + { + jerry_value_t res = jerry_run (parsed_get_code_val); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 3.0); + jerry_release_value (res); + } + + const jerry_char_t set_value_src[] = TEST_STRING_LITERAL ("pdemo.value = 55"); + jerry_value_t parsed_set_code_val = jerry_parse (NULL, + 0, + set_value_src, + sizeof (set_value_src) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_set_code_val)); + + { + jerry_value_t res = jerry_run (parsed_set_code_val); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 55); + jerry_release_value (res); + } + + { + jerry_value_t res = jerry_run (parsed_get_code_val); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 56); + jerry_release_value (res); + } + + { + jerry_value_t new_value = jerry_create_number (12); + set_property (proxy, "value", new_value); + jerry_release_value (new_value); + } + + { + jerry_value_t res = get_property (proxy, "value"); + TEST_ASSERT (jerry_value_is_number (res)); + TEST_ASSERT (jerry_get_number_value (res) == 13.0); + jerry_release_value (res); + } + + jerry_release_value (parsed_set_code_val); + jerry_release_value (parsed_get_code_val); + jerry_release_value (proxy); + jerry_release_value (target); + jerry_release_value (handler); + + jerry_cleanup (); + return 0; +} /* main */ diff --git a/tests/unit-core/test-regression-3588.c b/tests/unit-core/test-regression-3588.c new file mode 100644 index 00000000..57598051 --- /dev/null +++ b/tests/unit-core/test-regression-3588.c @@ -0,0 +1,107 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +/** + * Empty constructor + */ +static jerry_value_t +construct_handler (const jerry_value_t func_obj_val, /**< function object */ + const jerry_value_t this_val, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + JERRY_UNUSED (func_obj_val); + JERRY_UNUSED (this_val); + + TEST_ASSERT (args_cnt == 1); + TEST_ASSERT (jerry_get_number_value (args_p[0]) == 1.0); + + return jerry_create_undefined (); +} /* construct_handler */ + +int +main (void) +{ + /* Test JERRY_FEATURE_SYMBOL feature as it is a must-have in ES2015 */ + if (!jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Skipping test, ES2015 support is disabled.\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + { + jerry_value_t global_obj_val = jerry_get_global_object (); + + jerry_value_t function_val = jerry_create_external_function (construct_handler); + jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) "Demo"); + jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val); + TEST_ASSERT (!jerry_value_is_error (result_val)); + TEST_ASSERT (jerry_get_boolean_value (result_val) == true); + jerry_release_value (result_val); + jerry_release_value (function_name_val); + jerry_release_value (global_obj_val); + jerry_release_value (function_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( + "class Sub1 extends Demo { constructor () { super (1); } };" + "new Sub1 ()" + ); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t result = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_release_value (result); + jerry_release_value (parsed_code_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( + "class Sub2 extends Demo { };" + "new Sub2 (1)" + ); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t result = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_release_value (result); + jerry_release_value (parsed_code_val); + } + + jerry_cleanup (); + return 0; +} /* main */ diff --git a/tests/unit-core/test-resource-name.c b/tests/unit-core/test-resource-name.c new file mode 100644 index 00000000..449900e3 --- /dev/null +++ b/tests/unit-core/test-resource-name.c @@ -0,0 +1,126 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "jerryscript.h" +#include "test-common.h" + +static jerry_value_t +resource_name_handler (const jerry_value_t function_obj, /**< function object */ + const jerry_value_t this_val, /**< this value */ + const jerry_value_t args_p[], /**< argument list */ + const jerry_length_t args_count) /**< argument count */ +{ + (void) function_obj; + (void) this_val; + + jerry_value_t undefined_value = jerry_create_undefined (); + jerry_value_t resource_name = jerry_get_resource_name (args_count > 0 ? args_p[0] : undefined_value); + jerry_release_value (undefined_value); + + return resource_name; +} /* resource_name_handler */ + +int +main (void) +{ + TEST_INIT (); + + if (!jerry_is_feature_enabled (JERRY_FEATURE_LINE_INFO)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Line info support is disabled!\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global = jerry_get_global_object (); + + /* Register the "resourceName" method. */ + { + jerry_value_t func = jerry_create_external_function (resource_name_handler); + jerry_value_t name = jerry_create_string ((const jerry_char_t *) "resourceName"); + jerry_value_t result = jerry_set_property (global, name, func); + jerry_release_value (result); + jerry_release_value (name); + jerry_release_value (func); + } + + jerry_release_value (global); + + const char *source_1 = ("function f1 () {\n" + " if (resourceName() !== 'demo1.js') return false; \n" + " if (resourceName(f1) !== 'demo1.js') return false; \n" + " if (resourceName(5) !== '') return false; \n" + " return f1; \n" + "} \n" + "f1();"); + const char *resource_1 = "demo1.js"; + + jerry_value_t program = jerry_parse ((const jerry_char_t *) resource_1, + strlen (resource_1), + (const jerry_char_t *) source_1, + strlen (source_1), + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (program)); + + jerry_value_t run_result = jerry_run (program); + TEST_ASSERT (!jerry_value_is_error (run_result)); + TEST_ASSERT (jerry_value_is_object (run_result)); + + jerry_value_t resource_value = jerry_get_resource_name (run_result); + jerry_value_t resource1_name_value = jerry_create_string ((const jerry_char_t *) resource_1); + TEST_ASSERT (jerry_binary_operation (JERRY_BIN_OP_STRICT_EQUAL, resource_value, resource1_name_value)); + jerry_release_value (resource1_name_value); + jerry_release_value (resource_value); + + jerry_release_value (run_result); + jerry_release_value (program); + + const char *source_2 = ("function f2 () { \n" + " if (resourceName() !== 'demo2.js') return false; \n" + " if (resourceName(f2) !== 'demo2.js') return false; \n" + " if (resourceName(f1) !== 'demo1.js') return false; \n" + " if (resourceName(Object.prototype) !== '') return false; \n" + " if (resourceName(Function) !== '') return false; \n" + " return f2; \n" + "} \n" + "f2(); \n"); + const char *resource_2 = "demo2.js"; + + program = jerry_parse ((const jerry_char_t *) resource_2, + strlen (resource_2), + (const jerry_char_t *) source_2, + strlen (source_2), + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (program)); + + run_result = jerry_run (program); + TEST_ASSERT (!jerry_value_is_error (run_result)); + TEST_ASSERT (jerry_value_is_object (run_result)); + + resource_value = jerry_get_resource_name (run_result); + jerry_value_t resource2_name_value = jerry_create_string ((const jerry_char_t *) resource_2); + TEST_ASSERT (jerry_binary_operation (JERRY_BIN_OP_STRICT_EQUAL, resource_value, resource2_name_value)); + jerry_release_value (resource2_name_value); + jerry_release_value (resource_value); + + jerry_release_value (run_result); + jerry_release_value (program); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 46c143cf..8c1a39ed 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -223,19 +223,38 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x18, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, - 0x28, 0x00, 0xB8, 0x46, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x2C, 0x00, 0xC9, 0x53, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E, - 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74 + 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74, }; + + if (sizeof (expected_data) != snapshot_size || memcmp (expected_data, snapshot_buffer, sizeof (expected_data))) + { + printf ("Snapshot data has been changed, please update tests/unit-core/test-snapshot.c.\n"); + printf ("-------------------------------------------------------------------------------\n"); + printf (" const uint8_t expected_data[] =\n"); + printf (" {"); + for (unsigned int i = 0; i < snapshot_size; i++) + { + if ((i % 8) == 0) + { + printf ("\n "); + } + printf (" 0x%02X,", ((uint8_t *) snapshot_buffer)[i]); + } + printf ("\n };\n"); + printf ("-------------------------------------------------------------------------------\n"); + } + TEST_ASSERT (sizeof (expected_data) == snapshot_size); TEST_ASSERT (0 == memcmp (expected_data, snapshot_buffer, sizeof (expected_data))); @@ -381,7 +400,7 @@ main (void) static jerry_char_t literal_buffer_c[LITERAL_BUFFER_SIZE]; static uint32_t literal_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; - static const jerry_char_t code_for_c_format[] = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };"; + static const jerry_char_t code_for_c_format[] = "var object = { aa:'fo\" o\\n \\\\', Bb:'max', aaa:'xzy0' };"; jerry_value_t generate_result; generate_result = jerry_generate_snapshot (NULL, @@ -392,35 +411,40 @@ main (void) literal_snapshot_buffer, SNAPSHOT_BUFFER_SIZE); - TEST_ASSERT (!jerry_value_is_error (generate_result) - && jerry_value_is_number (generate_result)); + TEST_ASSERT (!jerry_value_is_error (generate_result)); + TEST_ASSERT (jerry_value_is_number (generate_result)); size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); jerry_release_value (generate_result); - TEST_ASSERT (snapshot_size == 120); + + /* In ES2015 we emit extra bytecode instructions to check global variable redeclaration. */ + const size_t expected_size = (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) ? 132 : 124; + TEST_ASSERT (snapshot_size == expected_size); const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer, snapshot_size, literal_buffer_c, LITERAL_BUFFER_SIZE, true); - TEST_ASSERT (lit_c_buf_sz == 200); + TEST_ASSERT (lit_c_buf_sz == 239); static const char *expected_c_format = ( - "jerry_length_t literal_count = 4;\n\n" - "jerry_char_t *literals[4] =\n" + "jerry_length_t literal_count = 5;\n\n" + "jerry_char_t *literals[5] =\n" "{\n" " \"Bb\",\n" " \"aa\",\n" " \"aaa\",\n" - " \"xzy0\"\n" + " \"xzy0\",\n" + " \"fo\\\" o\\x0A \\\\\"\n" "};\n\n" - "jerry_length_t literal_sizes[4] =\n" + "jerry_length_t literal_sizes[5] =\n" "{\n" " 2 /* Bb */,\n" " 2 /* aa */,\n" " 3 /* aaa */,\n" - " 4 /* xzy0 */\n" + " 4 /* xzy0 */,\n" + " 8 /* fo\" o\n \\ */\n" "};\n" ); @@ -433,9 +457,10 @@ main (void) literal_buffer_list, LITERAL_BUFFER_SIZE, false); - - TEST_ASSERT (lit_list_buf_sz == 30); - TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "2 Bb\n2 aa\n3 aaa\n4 fo o\n4 xzy0\n", lit_list_buf_sz)); + TEST_ASSERT (lit_list_buf_sz == 34); + TEST_ASSERT (!strncmp ((char *) literal_buffer_list, + "2 Bb\n2 aa\n3 aaa\n4 xzy0\n8 fo\" o\n \\\n", + lit_list_buf_sz)); jerry_cleanup (); } diff --git a/tests/unit-core/test-stringbuilder.c b/tests/unit-core/test-stringbuilder.c index d993fbda..7aa4eab3 100644 --- a/tests/unit-core/test-stringbuilder.c +++ b/tests/unit-core/test-stringbuilder.c @@ -155,7 +155,6 @@ main (void) } ecma_string_t *result_p = ecma_stringbuilder_finalize (&builder); - ecma_string_t *expected_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); for (size_t i = 0; i < count; i++) { diff --git a/tests/unit-core/test-strings.c b/tests/unit-core/test-strings.c index a3b8b6b0..7896d7a0 100644 --- a/tests/unit-core/test-strings.c +++ b/tests/unit-core/test-strings.c @@ -131,7 +131,7 @@ main (void) while (curr_p < end_p) { - code_units[code_units_count] = lit_utf8_peek_next (curr_p); + code_units[code_units_count] = lit_cesu8_peek_next (curr_p); saved_positions[code_units_count] = curr_p; code_units_count++; calculated_length++; @@ -147,7 +147,7 @@ main (void) { ecma_length_t index = (ecma_length_t) rand () % code_units_count; curr_p = saved_positions[index]; - TEST_ASSERT (lit_utf8_peek_next (curr_p) == code_units[index]); + TEST_ASSERT (lit_cesu8_peek_next (curr_p) == code_units[index]); } } @@ -156,7 +156,7 @@ main (void) { TEST_ASSERT (code_units_count > 0); calculated_length--; - TEST_ASSERT (code_units[calculated_length] == lit_utf8_peek_prev (curr_p)); + TEST_ASSERT (code_units[calculated_length] == lit_cesu8_peek_prev (curr_p)); lit_utf8_decr (&curr_p); } @@ -164,7 +164,7 @@ main (void) while (curr_p < end_p) { - ecma_char_t code_unit = lit_utf8_read_next (&curr_p); + ecma_char_t code_unit = lit_cesu8_read_next (&curr_p); TEST_ASSERT (code_unit == code_units[calculated_length]); calculated_length++; } @@ -175,7 +175,7 @@ main (void) { TEST_ASSERT (code_units_count > 0); calculated_length--; - TEST_ASSERT (code_units[calculated_length] == lit_utf8_read_prev (&curr_p)); + TEST_ASSERT (code_units[calculated_length] == lit_cesu8_read_prev (&curr_p)); } TEST_ASSERT (calculated_length == 0); diff --git a/tests/unit-core/test-to-integer.c b/tests/unit-core/test-to-integer.c index 191e0d53..e606b2c1 100644 --- a/tests/unit-core/test-to-integer.c +++ b/tests/unit-core/test-to-integer.c @@ -51,7 +51,7 @@ main (void) result = ecma_op_to_integer (error, &num); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); TEST_ASSERT (ECMA_IS_VALUE_ERROR (result)); @@ -130,5 +130,3 @@ main (void) return 0; } /* main */ - - diff --git a/tests/unit-core/test-to-length.c b/tests/unit-core/test-to-length.c index 4c6c2976..af967991 100644 --- a/tests/unit-core/test-to-length.c +++ b/tests/unit-core/test-to-length.c @@ -51,7 +51,7 @@ main (void) result = ecma_op_to_length (error_throw, &num); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); TEST_ASSERT (ECMA_IS_VALUE_ERROR (result)); diff --git a/tests/unit-core/test-typedarray.c b/tests/unit-core/test-typedarray.c index 1459d038..2b34eb51 100644 --- a/tests/unit-core/test-typedarray.c +++ b/tests/unit-core/test-typedarray.c @@ -155,7 +155,7 @@ test_typedarray_queries (test_entry_t test_entries[]) /**< test cases */ */ static void test_buffer_value (uint64_t value, /**< value to test for */ - const uint8_t *buffer, /**< buffer to read value from */ + const void *buffer, /**< buffer to read value from */ uint32_t start_offset, /**< start offset of the value */ jerry_typedarray_type_t typedarray_type, /**< type of TypedArray */ uint32_t bytes_per_element) /**< bytes per element for the given type */ @@ -400,6 +400,81 @@ static void test_property_by_index (test_entry_t test_entries[]) } } /* test_property_by_index */ +static void +test_detached_arraybuffer (void) +{ + static jerry_typedarray_type_t types[] = + { + JERRY_TYPEDARRAY_UINT8, + JERRY_TYPEDARRAY_UINT8CLAMPED, + JERRY_TYPEDARRAY_INT8, + JERRY_TYPEDARRAY_UINT16, + JERRY_TYPEDARRAY_INT16, + JERRY_TYPEDARRAY_UINT32, + JERRY_TYPEDARRAY_INT32, + JERRY_TYPEDARRAY_FLOAT32, + JERRY_TYPEDARRAY_FLOAT64, + }; + + /* Creating an TypedArray for a detached array buffer with a given length/offset is invalid */ + { + uint8_t buf[1]; + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, buf, NULL); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (res)); + jerry_release_value (res); + + for (size_t idx = 0; idx < (sizeof (types) / sizeof (types[0])); idx++) + { + jerry_value_t typedarray = jerry_create_typedarray_for_arraybuffer_sz (types[idx], arraybuffer, 0, 4); + TEST_ASSERT (jerry_value_is_error (typedarray)); + TEST_ASSERT (jerry_get_error_type (typedarray) == JERRY_ERROR_TYPE); + jerry_release_value (typedarray); + } + + jerry_release_value (arraybuffer); + } + + /* Creating an TypedArray for a detached array buffer without length/offset is valid */ + { + uint8_t buf[1]; + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, buf, NULL); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (res)); + jerry_release_value (res); + + for (size_t idx = 0; idx < (sizeof (types) / sizeof (types[0])); idx++) + { + jerry_value_t typedarray = jerry_create_typedarray_for_arraybuffer (types[idx], arraybuffer); + TEST_ASSERT (jerry_value_is_error (typedarray)); + TEST_ASSERT (jerry_get_error_type (typedarray) == JERRY_ERROR_TYPE); + jerry_release_value (typedarray); + } + + jerry_release_value (arraybuffer); + } +} /* test_detached_arraybuffer */ + int main (void) { @@ -443,11 +518,11 @@ main (void) /* Test TypedArray operations in js */ { const uint32_t element_count = 14; - uint8_t expected_value = 42; jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_UINT8, element_count); { + uint8_t expected_value = 42; JERRY_VLA (uint8_t, expected_data, element_count); memset (expected_data, expected_value, element_count); @@ -571,6 +646,8 @@ main (void) } } + test_detached_arraybuffer (); + jerry_cleanup (); return 0; diff --git a/tests/unit-core/test-unicode.c b/tests/unit-core/test-unicode.c new file mode 100644 index 00000000..0e6a25a1 --- /dev/null +++ b/tests/unit-core/test-unicode.c @@ -0,0 +1,61 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "test-common.h" + +static bool +test_syntax_error (char *script_p) /**< script */ +{ + jerry_value_t parse_result = jerry_parse (NULL, + 0, + (const jerry_char_t *) script_p, + strlen (script_p), + JERRY_PARSE_NO_OPTS); + + bool result = false; + + if (jerry_value_is_error (parse_result)) + { + result = true; + TEST_ASSERT (jerry_get_error_type (parse_result) == JERRY_ERROR_SYNTAX); + } + + jerry_release_value (parse_result); + return result; +} /* test_syntax_error */ + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + if (!test_syntax_error ("\\u{61}")) + { + TEST_ASSERT (!test_syntax_error ("\xF0\x90\xB2\x80: break \\u{10C80}")); + /* The \u surrogate pairs are ignored. The \u{hex} form must be used. */ + TEST_ASSERT (test_syntax_error ("\xF0\x90\xB2\x80: break \\ud803\\udc80")); + /* The utf8 code point and the cesu8 surrogate pair must match. */ + TEST_ASSERT (!test_syntax_error ("\xF0\x90\xB2\x80: break \xed\xa0\x83\xed\xb2\x80")); + + TEST_ASSERT (!test_syntax_error ("$\xF0\x90\xB2\x80$: break $\\u{10C80}$")); + TEST_ASSERT (test_syntax_error ("$\xF0\x90\xB2\x80$: break $\\ud803\\udc80$")); + TEST_ASSERT (!test_syntax_error ("$\xF0\x90\xB2\x80$: break $\xed\xa0\x83\xed\xb2\x80$")); + } + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-ext/test-ext-arg.c b/tests/unit-ext/test-ext-arg.c index 0aabdbd6..2b0d18e0 100644 --- a/tests/unit-ext/test-ext-arg.c +++ b/tests/unit-ext/test-ext-arg.c @@ -401,7 +401,6 @@ test_validator_prop2_handler (const jerry_value_t func_obj_val, /**< function ob jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping)); - TEST_ASSERT (!jerry_value_is_error (is_ok)); if (validator_prop_count == 1) @@ -622,7 +621,6 @@ test_validator_array1_handler (const jerry_value_t func_obj_val, /**< function o jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping)); - TEST_ASSERT (!jerry_value_is_error (is_ok)); if (validator_array_count == 0) @@ -730,7 +728,7 @@ jerry_arg_to_double_or_bool_t (jerryx_arg_js_iterator_t *js_arg_iter_p, * the stack more times than there are actual stack values to ensure * that the restore function doesn't produce an error. */ double_or_bool_t *destination = c_arg_p->dest; - uintptr_t *extra_info = (uintptr_t *)(c_arg_p->extra_info); + uintptr_t *extra_info = (uintptr_t *) (c_arg_p->extra_info); jerryx_arg_t conversion_function; jerry_value_t conversion_result; jerry_value_t restore_result; diff --git a/tests/unit-ext/test-ext-method-register.c b/tests/unit-ext/test-ext-method-register.c index 30e886f7..8f6daafa 100644 --- a/tests/unit-ext/test-ext-method-register.c +++ b/tests/unit-ext/test-ext-method-register.c @@ -185,7 +185,6 @@ test_error_setvalue (void) jerry_cleanup (); } /* test_error_setvalue */ - /** * Test registration error with jerryx_set_properties. * diff --git a/tests/unit-libm/test-libm.inc.h b/tests/unit-libm/test-libm.inc.h index 00f2070d..7cb03c0c 100644 --- a/tests/unit-libm/test-libm.inc.h +++ b/tests/unit-libm/test-libm.inc.h @@ -167,6 +167,87 @@ check_double ("atan2 (0.7, -1.0)", atan2 (0.7, -1.0), 2.53086668920058466270E+00 check_double ("atan2 (-0.7, -1.0)", atan2 (-0.7, -1.0), -2.53086668920058466270E+00); check_double ("atan2 (0.4, 0.0003)", atan2 (0.4, 0.0003), 1.57004632693552159672E+00); check_double ("atan2 (1.4, -0.93)", atan2 (1.4, -0.93), 2.15714876682378431383E+00); +check_double ("acosh (0.0)", acosh (0.0), -NAN); +check_double ("acosh (-0.0)", acosh (-0.0), -NAN); +check_double ("acosh (1.0)", acosh (1.0), 0.00000000000000000000E+00); +check_double ("acosh (-1.0)", acosh (-1.0), -NAN); +check_double ("acosh (INFINITY)", acosh (INFINITY), INF); +check_double ("acosh (-INFINITY)", acosh (-INFINITY), -NAN); +check_double ("acosh (NAN)", acosh (NAN), NAN); +check_double ("acosh (7.08e+02)", acosh (7.08e+02), 7.25559077551410425144E+00); +check_double ("acosh (7.10e+02)", acosh (7.10e+02), 7.25841165466159132791E+00); +check_double ("acosh (-7.40e+02)", acosh (-7.40e+02), -NAN); +check_double ("acosh (-7.50e+02)", acosh (-7.50e+02), -NAN); +check_double ("acosh (0.34)", acosh (0.34), -NAN); +check_double ("acosh (-0.34)", acosh (-0.34), -NAN); +check_double ("acosh (0.35)", acosh (0.35), -NAN); +check_double ("acosh (-0.35)", acosh (-0.35), -NAN); +check_double ("acosh (1.03)", acosh (1.03), 2.44340698822827606662E-01); +check_double ("acosh (-1.03)", acosh (-1.03), -NAN); +check_double ("acosh (1.04)", acosh (1.04), 2.81908289054146887764E-01); +check_double ("acosh (-1.04)", acosh (-1.04), -NAN); +check_double ("acosh (3.72e-09)", acosh (3.72e-09), -NAN); +check_double ("acosh (-3.72e-09)", acosh (-3.72e-09), -NAN); +check_double ("acosh (3.73e-09)", acosh (3.73e-09), -NAN); +check_double ("acosh (-3.73e-09)", acosh (-3.73e-09), -NAN); +check_double ("acosh (2.0)", acosh (2.0), 1.31695789692481679545E+00); +check_double ("acosh (3.0)", acosh (3.0), 1.76274717403908609548E+00); +check_double ("acosh (0.7)", acosh (0.7), -NAN); +check_double ("acosh (38.0)", acosh (38.0), 4.33056016511402308566E+00); +check_double ("asinh (0.0)", asinh (0.0), 0.00000000000000000000E+00); +check_double ("asinh (-0.0)", asinh (-0.0), -0.00000000000000000000E+00); +check_double ("asinh (1.0)", asinh (1.0), 8.81373587019543047738E-01); +check_double ("asinh (-1.0)", asinh (-1.0), -8.81373587019543047738E-01); +check_double ("asinh (INFINITY)", asinh (INFINITY), INF); +check_double ("asinh (-INFINITY)", asinh (-INFINITY), -INF); +check_double ("asinh (NAN)", asinh (NAN), NAN); +check_double ("asinh (7.08e+02)", asinh (7.08e+02), 7.25559177299247970439E+00); +check_double ("asinh (7.10e+02)", asinh (7.10e+02), 7.25841264652828410675E+00); +check_double ("asinh (-7.40e+02)", asinh (-7.40e+02), -7.29979782329546722508E+00); +check_double ("asinh (-7.50e+02)", asinh (-7.50e+02), -7.31322083153444957304E+00); +check_double ("asinh (0.34)", asinh (0.34), 3.33768351645882199730E-01); +check_double ("asinh (-0.34)", asinh (-0.34), -3.33768351645882199730E-01); +check_double ("asinh (0.35)", asinh (0.35), 3.43221555085943930141E-01); +check_double ("asinh (-0.35)", asinh (-0.35), -3.43221555085943930141E-01); +check_double ("asinh (1.03)", asinh (1.03), 9.02428495530461671770E-01); +check_double ("asinh (-1.03)", asinh (-1.03), -9.02428495530461671770E-01); +check_double ("asinh (1.04)", asinh (1.04), 9.09376928017844976537E-01); +check_double ("asinh (-1.04)", asinh (-1.04), -9.09376928017844976537E-01); +check_double ("asinh (3.72e-09)", asinh (3.72e-09), 3.71999999999999997526E-09); +check_double ("asinh (-3.72e-09)", asinh (-3.72e-09), -3.71999999999999997526E-09); +check_double ("asinh (3.73e-09)", asinh (3.73e-09), 3.73000000000000014752E-09); +check_double ("asinh (-3.73e-09)", asinh (-3.73e-09), -3.73000000000000014752E-09); +check_double ("asinh (2.0)", asinh (2.0), 1.44363547517881030124E+00); +check_double ("asinh (3.0)", asinh (3.0), 1.81844645923206682525E+00); +check_double ("asinh (0.7)", asinh (0.7), 6.52666566082355736889E-01); +check_double ("asinh (38.0)", asinh (38.0), 4.33090642553643068169E+00); +check_double ("atanh (0.0)", atanh (0.0), 0.00000000000000000000E+00); +check_double ("atanh (-0.0)", atanh (-0.0), -0.00000000000000000000E+00); +check_double ("atanh (1.0)", atanh (1.0), INF); +check_double ("atanh (-1.0)", atanh (-1.0), -INF); +check_double ("atanh (INFINITY)", atanh (INFINITY), -NAN); +check_double ("atanh (-INFINITY)", atanh (-INFINITY), -NAN); +check_double ("atanh (NAN)", atanh (NAN), NAN); +check_double ("atanh (7.08e+02)", atanh (7.08e+02), -NAN); +check_double ("atanh (7.10e+02)", atanh (7.10e+02), -NAN); +check_double ("atanh (-7.40e+02)", atanh (-7.40e+02), -NAN); +check_double ("atanh (-7.50e+02)", atanh (-7.50e+02), -NAN); +check_double ("atanh (0.34)", atanh (0.34), 3.54092528962242913959E-01); +check_double ("atanh (-0.34)", atanh (-0.34), -3.54092528962242913959E-01); +check_double ("atanh (0.35)", atanh (0.35), 3.65443754271396137323E-01); +check_double ("atanh (-0.35)", atanh (-0.35), -3.65443754271396137323E-01); +check_double ("atanh (1.03)", atanh (1.03), -NAN); +check_double ("atanh (-1.03)", atanh (-1.03), -NAN); +check_double ("atanh (1.04)", atanh (1.04), -NAN); +check_double ("atanh (-1.04)", atanh (-1.04), -NAN); +check_double ("atanh (3.72e-09)", atanh (3.72e-09), 3.71999999999999997526E-09); +check_double ("atanh (-3.72e-09)", atanh (-3.72e-09), -3.71999999999999997526E-09); +check_double ("atanh (3.73e-09)", atanh (3.73e-09), 3.73000000000000014752E-09); +check_double ("atanh (-3.73e-09)", atanh (-3.73e-09), -3.73000000000000014752E-09); +check_double ("atanh (2.0)", atanh (2.0), -NAN); +check_double ("atanh (3.0)", atanh (3.0), -NAN); +check_double ("atanh (0.7)", atanh (0.7), 8.67300527694053080552E-01); +check_double ("atanh (38.0)", atanh (38.0), -NAN); check_double ("ceil (0.0)", ceil (0.0), 0.00000000000000000000E+00); check_double ("ceil (-0.0)", ceil (-0.0), -0.00000000000000000000E+00); check_double ("ceil (INFINITY)", ceil (INFINITY), INF); @@ -205,6 +286,33 @@ check_double ("exp (2.0)", exp (2.0), 7.38905609893065040694E+00); check_double ("exp (3.0)", exp (3.0), 2.00855369231876679237E+01); check_double ("exp (0.7)", exp (0.7), 2.01375270747047663278E+00); check_double ("exp (38.0)", exp (38.0), 3.18559317571137560000E+16); +check_double ("expm1 (0.0)", expm1 (0.0), 0.00000000000000000000E+00); +check_double ("expm1 (-0.0)", expm1 (-0.0), -0.00000000000000000000E+00); +check_double ("expm1 (1.0)", expm1 (1.0), 1.71828182845904531284E+00); +check_double ("expm1 (-1.0)", expm1 (-1.0), -6.32120558828557665976E-01); +check_double ("expm1 (INFINITY)", expm1 (INFINITY), INF); +check_double ("expm1 (-INFINITY)", expm1 (-INFINITY), -1.00000000000000000000E+00); +check_double ("expm1 (NAN)", expm1 (NAN), NAN); +check_double ("expm1 (7.08e+02)", expm1 (7.08e+02), 3.02338314427605515848E+307); +check_double ("expm1 (7.10e+02)", expm1 (7.10e+02), INF); +check_double ("expm1 (-7.40e+02)", expm1 (-7.40e+02), -1.00000000000000000000E+00); +check_double ("expm1 (-7.50e+02)", expm1 (-7.50e+02), -1.00000000000000000000E+00); +check_double ("expm1 (0.34)", expm1 (0.34), 4.04947590563593806667E-01); +check_double ("expm1 (-0.34)", expm1 (-0.34), -2.88229677237390291555E-01); +check_double ("expm1 (0.35)", expm1 (0.35), 4.19067548593257233058E-01); +check_double ("expm1 (-0.35)", expm1 (-0.35), -2.95311910281286560398E-01); +check_double ("expm1 (1.03)", expm1 (1.03), 1.80106583469907910455E+00); +check_double ("expm1 (-1.03)", expm1 (-1.03), -6.42993039430852619809E-01); +check_double ("expm1 (1.04)", expm1 (1.04), 1.82921701435155958926E+00); +check_double ("expm1 (-1.04)", expm1 (-1.04), -6.46545318041219840843E-01); +check_double ("expm1 (3.72e-09)", expm1 (3.72e-09), 3.72000000691919994955E-09); +check_double ("expm1 (-3.72e-09)", expm1 (-3.72e-09), -3.71999999308080000097E-09); +check_double ("expm1 (3.73e-09)", expm1 (3.73e-09), 3.73000000695645013275E-09); +check_double ("expm1 (-3.73e-09)", expm1 (-3.73e-09), -3.72999999304355016230E-09); +check_double ("expm1 (2.0)", expm1 (2.0), 6.38905609893065040694E+00); +check_double ("expm1 (3.0)", expm1 (3.0), 1.90855369231876679237E+01); +check_double ("expm1 (0.7)", expm1 (0.7), 1.01375270747047641073E+00); +check_double ("expm1 (38.0)", expm1 (38.0), 3.18559317571137560000E+16); check_double ("fabs (0.0)", fabs (0.0), 0.00000000000000000000E+00); check_double ("fabs (-0.0)", fabs (-0.0), 0.00000000000000000000E+00); check_double ("fabs (1.0)", fabs (1.0), 1.00000000000000000000E+00); @@ -322,6 +430,63 @@ check_double ("log (0.18)", log (0.18), -1.71479842809192661868E+00); check_double ("log (1999.0)", log (1999.0), 7.60040233450039970364E+00); check_double ("log (2000.0)", log (2000.0), 7.60090245954208221235E+00); check_double ("log (2001.0)", log (2001.0), 7.60140233458373337783E+00); +check_double ("log1p (0.0)", log1p (0.0), 0.00000000000000000000E+00); +check_double ("log1p (-0.0)", log1p (-0.0), -0.00000000000000000000E+00); +check_double ("log1p (1.0)", log1p (1.0), 6.93147180559945286227E-01); +check_double ("log1p (-1.0)", log1p (-1.0), -INF); +check_double ("log1p (INFINITY)", log1p (INFINITY), INF); +check_double ("log1p (-INFINITY)", log1p (-INFINITY), -NAN); +check_double ("log1p (NAN)", log1p (NAN), NAN); +check_double ("log1p (M_E)", log1p (M_E), 1.31326168751822280889E+00); +check_double ("log1p (1.0 / M_E)", log1p (1.0 / M_E), 3.13261687518222864401E-01); +check_double ("log1p (2)", log1p (2), 1.09861228866810978211E+00); +check_double ("log1p (10)", log1p (10), 2.39789527279837066942E+00); +check_double ("log1p (0.7)", log1p (0.7), 5.30628251062170375185E-01); +check_double ("log1p (2.22e-308)", log1p (2.22e-308), 2.22000000000000013467E-308); +check_double ("log1p (2.23e-308)", log1p (2.23e-308), 2.23000000000000010412E-308); +check_double ("log1p (0.17)", log1p (0.17), 1.57003748809664750441E-01); +check_double ("log1p (0.18)", log1p (0.18), 1.65514438477573383457E-01); +check_double ("log1p (1999.0)", log1p (1999.0), 7.60090245954208221235E+00); +check_double ("log1p (2000.0)", log1p (2000.0), 7.60140233458373337783E+00); +check_double ("log1p (2001.0)", log1p (2001.0), 7.60190195987516581511E+00); +check_double ("log2 (0.0)", log2 (0.0), -INF); +check_double ("log2 (-0.0)", log2 (-0.0), -INF); +check_double ("log2 (1.0)", log2 (1.0), 0.00000000000000000000E+00); +check_double ("log2 (-1.0)", log2 (-1.0), NAN); +check_double ("log2 (INFINITY)", log2 (INFINITY), INF); +check_double ("log2 (-INFINITY)", log2 (-INFINITY), NAN); +check_double ("log2 (NAN)", log2 (NAN), NAN); +check_double ("log2 (M_E)", log2 (M_E), 1.44269504088896338700E+00); +check_double ("log2 (1.0 / M_E)", log2 (1.0 / M_E), -1.44269504088896338700E+00); +check_double ("log2 (2)", log2 (2), 1.00000000000000000000E+00); +check_double ("log2 (10)", log2 (10), 3.32192809488736218171E+00); +check_double ("log2 (0.7)", log2 (0.7), -5.14573172829758340718E-01); +check_double ("log2 (2.22e-308)", log2 (2.22e-308), -1.02200329354873224474E+03); +check_double ("log2 (2.23e-308)", log2 (2.23e-308), -1.02199680951516199912E+03); +check_double ("log2 (0.17)", log2 (0.17), -2.55639334852438526724E+00); +check_double ("log2 (0.18)", log2 (0.18), -2.47393118833241221211E+00); +check_double ("log2 (1999.0)", log2 (1999.0), 1.09650627567446274924E+01); +check_double ("log2 (2000.0)", log2 (2000.0), 1.09657842846620869892E+01); +check_double ("log2 (2001.0)", log2 (2001.0), 1.09665054519057409976E+01); +check_double ("log10 (0.0)", log10 (0.0), -INF); +check_double ("log10 (-0.0)", log10 (-0.0), -INF); +check_double ("log10 (1.0)", log10 (1.0), 0.00000000000000000000E+00); +check_double ("log10 (-1.0)", log10 (-1.0), NAN); +check_double ("log10 (INFINITY)", log10 (INFINITY), INF); +check_double ("log10 (-INFINITY)", log10 (-INFINITY), NAN); +check_double ("log10 (NAN)", log10 (NAN), NAN); +check_double ("log10 (M_E)", log10 (M_E), 4.34294481903251816668E-01); +check_double ("log10 (1.0 / M_E)", log10 (1.0 / M_E), -4.34294481903251816668E-01); +check_double ("log10 (2)", log10 (2), 3.01029995663981198017E-01); +check_double ("log10 (10)", log10 (10), 1.00000000000000000000E+00); +check_double ("log10 (0.7)", log10 (0.7), -1.54901959985743187254E-01); +check_double ("log10 (2.22e-308)", log10 (2.22e-308), -3.07653647025549389582E+02); +check_double ("log10 (2.23e-308)", log10 (2.23e-308), -3.07651695136951843779E+02); +check_double ("log10 (0.17)", log10 (0.17), -7.69551078621726003526E-01); +check_double ("log10 (0.18)", log10 (0.18), -7.44727494896693986703E-01); +check_double ("log10 (1999.0)", log10 (1999.0), 3.30081279411811712166E+00); +check_double ("log10 (2000.0)", log10 (2000.0), 3.30102999566398125353E+00); +check_double ("log10 (2001.0)", log10 (2001.0), 3.30124708863621130206E+00); check_double ("pow (0.0, 0.0)", pow (0.0, 0.0), 1.00000000000000000000E+00); check_double ("pow (0.0, -0.0)", pow (0.0, -0.0), 1.00000000000000000000E+00); check_double ("pow (-0.0, 0.0)", pow (-0.0, 0.0), 1.00000000000000000000E+00); @@ -447,6 +612,29 @@ check_double ("sqrt (4)", sqrt (4), 2.00000000000000000000E+00); check_double ("sqrt (0.25)", sqrt (0.25), 5.00000000000000000000E-01); check_double ("sqrt (6642.25)", sqrt (6642.25), 8.15000000000000000000E+01); check_double ("sqrt (15239.9025)", sqrt (15239.9025), 1.23450000000000002842E+02); +check_double ("cbrt (0.0)", cbrt (0.0), 0.00000000000000000000E+00); +check_double ("cbrt (-0.0)", cbrt (-0.0), -0.00000000000000000000E+00); +check_double ("cbrt (1.0)", cbrt (1.0), 1.00000000000000000000E+00); +check_double ("cbrt (-1.0)", cbrt (-1.0), -1.00000000000000000000E+00); +check_double ("cbrt (INFINITY)", cbrt (INFINITY), INF); +check_double ("cbrt (-INFINITY)", cbrt (-INFINITY), -INF); +check_double ("cbrt (NAN)", cbrt (NAN), NAN); +check_double ("cbrt (0.7)", cbrt (0.7), 8.87904001742600645919E-01); +check_double ("cbrt (2)", cbrt (2), 1.25992104989487319067E+00); +check_double ("cbrt (10)", cbrt (10), 2.15443469003188381450E+00); +check_double ("cbrt (2.22e-308)", cbrt (2.22e-308), 2.81050475771047639693E-103); +check_double ("cbrt (2.23e-308)", cbrt (2.23e-308), 2.81471841433133404618E-103); +check_double ("cbrt (3.72e-09)", cbrt (3.72e-09), 1.54946217899915657419E-03); +check_double ("cbrt (7.37e+19)", cbrt (7.37e+19), 4.19265534205965511501E+06); +check_double ("cbrt (2209)", cbrt (2209), 1.30236256766892157799E+01); +check_double ("cbrt (4)", cbrt (4), 1.58740105196819958344E+00); +check_double ("cbrt (0.25)", cbrt (0.25), 6.29960524947436595333E-01); +check_double ("cbrt (6642.25)", cbrt (6642.25), 1.87977155063238647870E+01); +check_double ("cbrt (15239.9025)", cbrt (15239.9025), 2.47929038511971775449E+01); +check_double ("cbrt (3)", cbrt (3), 1.44224957030740830177E+00); +check_double ("cbrt (9)", cbrt (9), 2.08008382305190409056E+00); +check_double ("cbrt (-17.87)", cbrt (-17.87), -2.61441695192974155049E+00); +check_double ("cbrt (-8941)", cbrt (-8941), -2.07552848589356599973E+01); check_double ("sin (0.0)", sin (0.0), 0.00000000000000000000E+00); check_double ("sin (-0.0)", sin (-0.0), -0.00000000000000000000E+00); check_double ("sin (1.0)", sin (1.0), 8.41470984807896504876E-01); @@ -580,3 +768,144 @@ check_double ("tan (6.0)", tan (6.0), -2.91006191384749146600E-01); check_double ("tan (-6.0)", tan (-6.0), 2.91006191384749146600E-01); check_double ("tan (7.0)", tan (7.0), 8.71447982724318781500E-01); check_double ("tan (-7.0)", tan (-7.0), -8.71447982724318781500E-01); +check_double ("cosh (0.0)", cosh (0.0), 1.00000000000000000000E+00); +check_double ("cosh (-0.0)", cosh (-0.0), 1.00000000000000000000E+00); +check_double ("cosh (1.0)", cosh (1.0), 1.54308063481524371241E+00); +check_double ("cosh (-1.0)", cosh (-1.0), 1.54308063481524371241E+00); +check_double ("cosh (INFINITY)", cosh (INFINITY), INF); +check_double ("cosh (-INFINITY)", cosh (-INFINITY), INF); +check_double ("cosh (NAN)", cosh (NAN), NAN); +check_double ("cosh (M_PI)", cosh (M_PI), 1.15919532755215186626E+01); +check_double ("cosh (-M_PI)", cosh (-M_PI), 1.15919532755215186626E+01); +check_double ("cosh (2.0 * M_PI)", cosh (2.0 * M_PI), 2.67746761483748173305E+02); +check_double ("cosh (-2.0 * M_PI)", cosh (-2.0 * M_PI), 2.67746761483748173305E+02); +check_double ("cosh (M_PI / 2.0)", cosh (M_PI / 2.0), 2.50917847865805665464E+00); +check_double ("cosh (-M_PI / 2.0)", cosh (-M_PI / 2.0), 2.50917847865805665464E+00); +check_double ("cosh (M_PI / 3.0)", cosh (M_PI / 3.0), 1.60028685770238610075E+00); +check_double ("cosh (-M_PI / 3.0)", cosh (-M_PI / 3.0), 1.60028685770238610075E+00); +check_double ("cosh (M_PI / 4.0)", cosh (M_PI / 4.0), 1.32460908925200571140E+00); +check_double ("cosh (-M_PI / 4.0)", cosh (-M_PI / 4.0), 1.32460908925200571140E+00); +check_double ("cosh (M_PI / 6.0)", cosh (M_PI / 6.0), 1.14023832107642886236E+00); +check_double ("cosh (-M_PI / 6.0)", cosh (-M_PI / 6.0), 1.14023832107642886236E+00); +check_double ("cosh (M_PI * 2.0 / 3.0)", cosh (M_PI * 2.0 / 3.0), 4.12183605386995388642E+00); +check_double ("cosh (-M_PI * 2.0 / 3.0)", cosh (-M_PI * 2.0 / 3.0), 4.12183605386995388642E+00); +check_double ("cosh (M_PI * 5.0 / 6.0)", cosh (M_PI * 5.0 / 6.0), 6.89057236497588299073E+00); +check_double ("cosh (-M_PI * 5.0 / 6.0)", cosh (-M_PI * 5.0 / 6.0), 6.89057236497588299073E+00); +check_double ("cosh (6.9e-18)", cosh (6.9e-18), 1.00000000000000000000E+00); +check_double ("cosh (-6.9e-18)", cosh (-6.9e-18), 1.00000000000000000000E+00); +check_double ("cosh (7.0e-18)", cosh (7.0e-18), 1.00000000000000000000E+00); +check_double ("cosh (-7.0e-18)", cosh (-7.0e-18), 1.00000000000000000000E+00); +check_double ("cosh (7.4e-9)", cosh (7.4e-9), 1.00000000000000000000E+00); +check_double ("cosh (-7.4e-9)", cosh (-7.4e-9), 1.00000000000000000000E+00); +check_double ("cosh (7.5e-9)", cosh (7.5e-9), 1.00000000000000000000E+00); +check_double ("cosh (-7.5e-9)", cosh (-7.5e-9), 1.00000000000000000000E+00); +check_double ("cosh (0.2)", cosh (0.2), 1.02006675561907589334E+00); +check_double ("cosh (-0.2)", cosh (-0.2), 1.02006675561907589334E+00); +check_double ("cosh (0.4)", cosh (0.4), 1.08107237183845472650E+00); +check_double ("cosh (-0.4)", cosh (-0.4), 1.08107237183845472650E+00); +check_double ("cosh (0.7)", cosh (0.7), 1.25516900563094302434E+00); +check_double ("cosh (-0.7)", cosh (-0.7), 1.25516900563094302434E+00); +check_double ("cosh (0.8)", cosh (0.8), 1.33743494630484471841E+00); +check_double ("cosh (-0.8)", cosh (-0.8), 1.33743494630484471841E+00); +check_double ("cosh (3.0)", cosh (3.0), 1.00676619957777653269E+01); +check_double ("cosh (-3.0)", cosh (-3.0), 1.00676619957777653269E+01); +check_double ("cosh (4.0)", cosh (4.0), 2.73082328360164865444E+01); +check_double ("cosh (-4.0)", cosh (-4.0), 2.73082328360164865444E+01); +check_double ("cosh (6.0)", cosh (6.0), 2.01715636122455890700E+02); +check_double ("cosh (-6.0)", cosh (-6.0), 2.01715636122455890700E+02); +check_double ("cosh (7.0)", cosh (7.0), 5.48317035155212124664E+02); +check_double ("cosh (-7.0)", cosh (-7.0), 5.48317035155212124664E+02); +check_double ("sinh (0.0)", sinh (0.0), 0.00000000000000000000E+00); +check_double ("sinh (-0.0)", sinh (-0.0), -0.00000000000000000000E+00); +check_double ("sinh (1.0)", sinh (1.0), 1.17520119364380137839E+00); +check_double ("sinh (-1.0)", sinh (-1.0), -1.17520119364380137839E+00); +check_double ("sinh (INFINITY)", sinh (INFINITY), INF); +check_double ("sinh (-INFINITY)", sinh (-INFINITY), -INF); +check_double ("sinh (NAN)", sinh (NAN), NAN); +check_double ("sinh (M_PI)", sinh (M_PI), 1.15487393572577463630E+01); +check_double ("sinh (-M_PI)", sinh (-M_PI), -1.15487393572577463630E+01); +check_double ("sinh (2.0 * M_PI)", sinh (2.0 * M_PI), 2.67744894041016436859E+02); +check_double ("sinh (-2.0 * M_PI)", sinh (-2.0 * M_PI), -2.67744894041016436859E+02); +check_double ("sinh (M_PI / 2.0)", sinh (M_PI / 2.0), 2.30129890230729472478E+00); +check_double ("sinh (-M_PI / 2.0)", sinh (-M_PI / 2.0), -2.30129890230729472478E+00); +check_double ("sinh (M_PI / 3.0)", sinh (M_PI / 3.0), 1.24936705052397512006E+00); +check_double ("sinh (-M_PI / 3.0)", sinh (-M_PI / 3.0), -1.24936705052397512006E+00); +check_double ("sinh (M_PI / 4.0)", sinh (M_PI / 4.0), 8.68670961486009529651E-01); +check_double ("sinh (-M_PI / 4.0)", sinh (-M_PI / 4.0), -8.68670961486009529651E-01); +check_double ("sinh (M_PI / 6.0)", sinh (M_PI / 6.0), 5.47853473888039732564E-01); +check_double ("sinh (-M_PI / 6.0)", sinh (-M_PI / 6.0), -5.47853473888039732564E-01); +check_double ("sinh (M_PI * 2.0 / 3.0)", sinh (M_PI * 2.0 / 3.0), 3.99869134279982052504E+00); +check_double ("sinh (-M_PI * 2.0 / 3.0)", sinh (-M_PI * 2.0 / 3.0), -3.99869134279982052504E+00); +check_double ("sinh (M_PI * 5.0 / 6.0)", sinh (M_PI * 5.0 / 6.0), 6.81762330412654371514E+00); +check_double ("sinh (-M_PI * 5.0 / 6.0)", sinh (-M_PI * 5.0 / 6.0), -6.81762330412654371514E+00); +check_double ("sinh (6.9e-18)", sinh (6.9e-18), 6.90000000000000026253E-18); +check_double ("sinh (-6.9e-18)", sinh (-6.9e-18), -6.90000000000000026253E-18); +check_double ("sinh (7.0e-18)", sinh (7.0e-18), 6.99999999999999973042E-18); +check_double ("sinh (-7.0e-18)", sinh (-7.0e-18), -6.99999999999999973042E-18); +check_double ("sinh (7.4e-9)", sinh (7.4e-9), 7.40000000000000008865E-09); +check_double ("sinh (-7.4e-9)", sinh (-7.4e-9), -7.40000000000000008865E-09); +check_double ("sinh (7.5e-9)", sinh (7.5e-9), 7.49999999999999932974E-09); +check_double ("sinh (-7.5e-9)", sinh (-7.5e-9), -7.49999999999999932974E-09); +check_double ("sinh (0.2)", sinh (0.2), 2.01336002541093989082E-01); +check_double ("sinh (-0.2)", sinh (-0.2), -2.01336002541093989082E-01); +check_double ("sinh (0.4)", sinh (0.4), 4.10752325802815509981E-01); +check_double ("sinh (-0.4)", sinh (-0.4), -4.10752325802815509981E-01); +check_double ("sinh (0.7)", sinh (0.7), 7.58583701839533497413E-01); +check_double ("sinh (-0.7)", sinh (-0.7), -7.58583701839533497413E-01); +check_double ("sinh (0.8)", sinh (0.8), 8.88105982187623044233E-01); +check_double ("sinh (-0.8)", sinh (-0.8), -8.88105982187623044233E-01); +check_double ("sinh (3.0)", sinh (3.0), 1.00178749274099025968E+01); +check_double ("sinh (-3.0)", sinh (-3.0), -1.00178749274099025968E+01); +check_double ("sinh (4.0)", sinh (4.0), 2.72899171971277532123E+01); +check_double ("sinh (-4.0)", sinh (-4.0), -2.72899171971277532123E+01); +check_double ("sinh (6.0)", sinh (6.0), 2.01713157370279219549E+02); +check_double ("sinh (-6.0)", sinh (-6.0), -2.01713157370279219549E+02); +check_double ("sinh (7.0)", sinh (7.0), 5.48316123273246489589E+02); +check_double ("sinh (-7.0)", sinh (-7.0), -5.48316123273246489589E+02); +check_double ("tanh (0.0)", tanh (0.0), 0.00000000000000000000E+00); +check_double ("tanh (-0.0)", tanh (-0.0), -0.00000000000000000000E+00); +check_double ("tanh (1.0)", tanh (1.0), 7.61594155955764851029E-01); +check_double ("tanh (-1.0)", tanh (-1.0), -7.61594155955764851029E-01); +check_double ("tanh (INFINITY)", tanh (INFINITY), 1.00000000000000000000E+00); +check_double ("tanh (-INFINITY)", tanh (-INFINITY), -1.00000000000000000000E+00); +check_double ("tanh (NAN)", tanh (NAN), NAN); +check_double ("tanh (M_PI)", tanh (M_PI), 9.96272076220749980280E-01); +check_double ("tanh (-M_PI)", tanh (-M_PI), -9.96272076220749980280E-01); +check_double ("tanh (2.0 * M_PI)", tanh (2.0 * M_PI), 9.99993025339610652757E-01); +check_double ("tanh (-2.0 * M_PI)", tanh (-2.0 * M_PI), -9.99993025339610652757E-01); +check_double ("tanh (M_PI / 2.0)", tanh (M_PI / 2.0), 9.17152335667274387632E-01); +check_double ("tanh (-M_PI / 2.0)", tanh (-M_PI / 2.0), -9.17152335667274387632E-01); +check_double ("tanh (M_PI / 3.0)", tanh (M_PI / 3.0), 7.80714435359267655556E-01); +check_double ("tanh (-M_PI / 3.0)", tanh (-M_PI / 3.0), -7.80714435359267655556E-01); +check_double ("tanh (M_PI / 4.0)", tanh (M_PI / 4.0), 6.55794202632672407205E-01); +check_double ("tanh (-M_PI / 4.0)", tanh (-M_PI / 4.0), -6.55794202632672407205E-01); +check_double ("tanh (M_PI / 6.0)", tanh (M_PI / 6.0), 4.80472778156451563181E-01); +check_double ("tanh (-M_PI / 6.0)", tanh (-M_PI / 6.0), -4.80472778156451563181E-01); +check_double ("tanh (M_PI * 2.0 / 3.0)", tanh (M_PI * 2.0 / 3.0), 9.70123821165930766419E-01); +check_double ("tanh (-M_PI * 2.0 / 3.0)", tanh (-M_PI * 2.0 / 3.0), -9.70123821165930766419E-01); +check_double ("tanh (M_PI * 5.0 / 6.0)", tanh (M_PI * 5.0 / 6.0), 9.89413207352682011475E-01); +check_double ("tanh (-M_PI * 5.0 / 6.0)", tanh (-M_PI * 5.0 / 6.0), -9.89413207352682011475E-01); +check_double ("tanh (6.9e-18)", tanh (6.9e-18), 6.90000000000000026253E-18); +check_double ("tanh (-6.9e-18)", tanh (-6.9e-18), -6.90000000000000026253E-18); +check_double ("tanh (7.0e-18)", tanh (7.0e-18), 6.99999999999999973042E-18); +check_double ("tanh (-7.0e-18)", tanh (-7.0e-18), -6.99999999999999973042E-18); +check_double ("tanh (7.4e-9)", tanh (7.4e-9), 7.40000000000000008865E-09); +check_double ("tanh (-7.4e-9)", tanh (-7.4e-9), -7.40000000000000008865E-09); +check_double ("tanh (7.5e-9)", tanh (7.5e-9), 7.49999999999999932974E-09); +check_double ("tanh (-7.5e-9)", tanh (-7.5e-9), -7.49999999999999932974E-09); +check_double ("tanh (0.2)", tanh (0.2), 1.97375320224904005073E-01); +check_double ("tanh (-0.2)", tanh (-0.2), -1.97375320224904005073E-01); +check_double ("tanh (0.4)", tanh (0.4), 3.79948962255224897966E-01); +check_double ("tanh (-0.4)", tanh (-0.4), -3.79948962255224897966E-01); +check_double ("tanh (0.7)", tanh (0.7), 6.04367777117163496037E-01); +check_double ("tanh (-0.7)", tanh (-0.7), -6.04367777117163496037E-01); +check_double ("tanh (0.8)", tanh (0.8), 6.64036770267849019156E-01); +check_double ("tanh (-0.8)", tanh (-0.8), -6.64036770267849019156E-01); +check_double ("tanh (3.0)", tanh (3.0), 9.95054753686730464324E-01); +check_double ("tanh (-3.0)", tanh (-3.0), -9.95054753686730464324E-01); +check_double ("tanh (4.0)", tanh (4.0), 9.99329299739067034025E-01); +check_double ("tanh (-4.0)", tanh (-4.0), -9.99329299739067034025E-01); +check_double ("tanh (6.0)", tanh (6.0), 9.99987711650795585427E-01); +check_double ("tanh (-6.0)", tanh (-6.0), -9.99987711650795585427E-01); +check_double ("tanh (7.0)", tanh (7.0), 9.99998336943944687860E-01); +check_double ("tanh (-7.0)", tanh (-7.0), -9.99998336943944687860E-01); diff --git a/tools/apt-get-install-deps.sh b/tools/apt-get-install-deps.sh index 7df3ebc1..f4f39640 100755 --- a/tools/apt-get-install-deps.sh +++ b/tools/apt-get-install-deps.sh @@ -14,8 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -sudo apt-get update -q -sudo apt-get install -q -y \ +if [ "$(whoami)" != "root" ]; then + SUDO=sudo +fi + +${SUDO} apt-get update -q +${SUDO} apt-get install -q -y \ make cmake \ gcc gcc-multilib \ doxygen \ diff --git a/tools/apt-get-install-qemu-arm.sh b/tools/apt-get-install-qemu-arm.sh index 7658ccd6..b38373bb 100755 --- a/tools/apt-get-install-qemu-arm.sh +++ b/tools/apt-get-install-qemu-arm.sh @@ -14,7 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -sudo apt-get update -q -sudo apt-get install -q -y \ +if [ "$(whoami)" != "root" ]; then + SUDO=sudo +fi + +${SUDO} apt-get update -q +${SUDO} apt-get install -q -y \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross \ qemu-user-static diff --git a/tools/babel/README.md b/tools/babel/README.md index 4b1b15b1..aebac397 100644 --- a/tools/babel/README.md +++ b/tools/babel/README.md @@ -62,13 +62,4 @@ Place the files/directories you want transpiled to the babel folder and run `$ npm run transpile [name of input file/directory] [(OPTIONAL)name of output file/directory]` -If you want to use the same name, then only give the name once. - -#### Missing features/Polyfill [](#missing-features) -Some features aren't implemented yet and found no babel plug-in for them. - -* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) -* [Array.prototype.fill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) -* [String.prototype.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) - -In the case you encounter those, use the polyfill found on the linked sites. Also, **be aware** there could be more. \ No newline at end of file +If you want to use the same name, then only give the name once. \ No newline at end of file diff --git a/tools/build.py b/tools/build.py index 52c2bc8f..e30f00e4 100755 --- a/tools/build.py +++ b/tools/build.py @@ -128,6 +128,8 @@ def get_arguments(): help='memory usage limit to trigger garbage collection (in bytes)') coregrp.add_argument('--stack-limit', metavar='SIZE', type=int, help='maximum stack usage (in kilobytes)') + coregrp.add_argument('--gc-mark-limit', metavar='SIZE', type=int, + help='maximum depth of recursion during GC mark phase') coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper, help=devhelp('enable memory statistics (%(choices)s)')) coregrp.add_argument('--mem-stress-test', metavar='X', choices=['ON', 'OFF'], type=str.upper, @@ -215,6 +217,9 @@ def generate_build_options(arguments): build_options_append('JERRY_VALGRIND', arguments.valgrind) build_options_append('JERRY_VM_EXEC_STOP', arguments.vm_exec_stop) + if arguments.gc_mark_limit is not None: + build_options.append('-D%s=%s' % ('JERRY_GC_MARK_LIMIT', arguments.gc_mark_limit)) + # jerry-main options build_options_append('ENABLE_LINK_MAP', arguments.link_map) diff --git a/tools/check-cppcheck.sh b/tools/check-cppcheck.sh index 8da40d50..2f95d1ba 100755 --- a/tools/check-cppcheck.sh +++ b/tools/check-cppcheck.sh @@ -40,6 +40,7 @@ cppcheck -j$CPPCHECK_JOBS --force \ --enable=warning,style,performance,portability,information \ --template="{file}:{line}: {severity}({id}): {message}" \ --error-exitcode=1 \ + --inline-suppr \ --exitcode-suppressions=tools/cppcheck/suppressions-list \ --suppressions-list=tools/cppcheck/suppressions-list \ "${INCLUDE_DIRS[@]}" \ diff --git a/tools/cppcheck/suppressions-list b/tools/cppcheck/suppressions-list index ea48aec2..d2277a83 100644 --- a/tools/cppcheck/suppressions-list +++ b/tools/cppcheck/suppressions-list @@ -1,4 +1,9 @@ wrongmathcall:tests/unit-libm/test-libm.inc.h variableScope:jerry-libm/*.c invalidPointerCast:jerry-libm/*.c -commaSeparatedReturn:* + +ConfigurationNotChecked:jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +ConfigurationNotChecked:jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-defines.inc.h +ConfigurationNotChecked:jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.inc.h +ConfigurationNotChecked:jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h +ConfigurationNotChecked:jerry-core/ecma/builtin-objects/ecma-builtin-helpers-macro-undefs.inc.h diff --git a/tools/gen-magic-strings.py b/tools/gen-magic-strings.py index 504023f2..06e774aa 100755 --- a/tools/gen-magic-strings.py +++ b/tools/gen-magic-strings.py @@ -221,8 +221,6 @@ def generate_header(gen_file): def generate_magic_string_defs(gen_file, defs): - print(file=gen_file) # empty line separator - last_guards = set([()]) for str_ref, str_value, guards in defs: if last_guards != guards: diff --git a/tools/gen-unicode.py b/tools/gen-unicode.py index 34f8ace9..47624df8 100755 --- a/tools/gen-unicode.py +++ b/tools/gen-unicode.py @@ -137,6 +137,14 @@ class UnicodeCategorizer(object): if zero_width_space not in separators: bisect.insort(separators, int(zero_width_space)) + # https://www.ecma-international.org/ecma-262/5.1/#sec-7.1 format-control characters + non_letters = self._categories['non_letters'] + zero_width_non_joiner = 0x200C + zero_width_joiner = 0x200D + + bisect.insort(non_letters, int(zero_width_non_joiner)) + bisect.insort(non_letters, int(zero_width_joiner)) + return self._categories['letters'], self._categories['non_letters'], self._categories['separators'] @@ -780,7 +788,7 @@ def main(): The input files (UnicodeData.txt, SpecialCasing.txt) must be retrieved from http://www.unicode.org/Public//ucd/. - The last known good version is 9.0.0. + The last known good version is 13.0.0. ''') parser.add_argument('--unicode-data', metavar='FILE', action='store', required=True, diff --git a/tools/pylint/pylintrc b/tools/pylint/pylintrc index e07b6b80..8a436182 100644 --- a/tools/pylint/pylintrc +++ b/tools/pylint/pylintrc @@ -303,7 +303,7 @@ ignore-imports=no [DESIGN] # Maximum number of arguments for function / method -max-args=5 +max-args=6 # Argument names that match this expression will be ignored. Default to name # with leading underscore diff --git a/tools/run-tests.py b/tools/run-tests.py index e37899aa..637f7195 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -38,6 +38,7 @@ OPTIONS_PROFILE_MIN = ['--profile=minimal'] OPTIONS_PROFILE_ES51 = [] # NOTE: same as ['--profile=es5.1'] OPTIONS_PROFILE_ES2015 = ['--profile=es2015-subset'] OPTIONS_STACK_LIMIT = ['--stack-limit=96'] +OPTIONS_GC_MARK_LIMIT = ['--gc-mark-limit=16'] OPTIONS_DEBUG = ['--debug'] OPTIONS_SNAPSHOT = ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'] OPTIONS_UNITTESTS = ['--unittests=on', '--jerry-cmdline=off', '--error-messages=on', @@ -75,22 +76,23 @@ JERRY_UNITTESTS_OPTIONS = [ # Test options for jerry-tests JERRY_TESTS_OPTIONS = [ Options('jerry_tests-es2015_subset-debug', - OPTIONS_COMMON + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1-snapshot', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_STACK_LIMIT, + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT, ['--snapshot']), Options('jerry_tests-es5.1-debug', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1-debug-snapshot', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT, - ['--snapshot']), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + + OPTIONS_GC_MARK_LIMIT, ['--snapshot']), Options('jerry_tests-es5.1-debug-cpointer_32bit', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + ['--cpointer-32bit=on', '--mem-heap=1024']), Options('jerry_tests-es5.1-debug-external_context', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + ['--external-context=on']), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + + ['--external-context=on']), ] # Test options for jerry-test-suite @@ -122,6 +124,11 @@ TEST262_TEST_SUITE_OPTIONS = [ Options('test262_tests-debug', OPTIONS_DEBUG) ] +# Test options for test262-es2015 +TEST262_ES2015_TEST_SUITE_OPTIONS = [ + Options('test262_tests_es2015', OPTIONS_PROFILE_ES2015 + ['--line-info=on', '--error-messages=on']), +] + # Test options for jerry-debugger DEBUGGER_TEST_OPTIONS = [ Options('jerry_debugger_tests', @@ -169,8 +176,12 @@ JERRY_BUILDOPTIONS = [ ['--jerry-cmdline-snapshot=on']), Options('buildoption_test-recursion_limit', OPTIONS_STACK_LIMIT), + Options('buildoption_test-gc-mark_limit', + OPTIONS_GC_MARK_LIMIT), Options('buildoption_test-single-source', ['--cmake-param=-DENABLE_ALL_IN_ONE_SOURCE=ON']), + Options('buildoption_test-jerry-debugger', + ['--jerry-debugger=on']), ] def get_arguments(): @@ -207,7 +218,9 @@ def get_arguments(): parser.add_argument('--jerry-test-suite', action='store_true', help='Run jerry-test-suite') parser.add_argument('--test262', action='store_true', - help='Run test262') + help='Run test262 - ES5.1') + parser.add_argument('--test262-es2015', action='store_true', + help='Run test262 - ES2015') parser.add_argument('--unittests', action='store_true', help='Run unittests (including doctests)') parser.add_argument('--buildoption-test', action='store_true', @@ -280,6 +293,7 @@ def create_binary(job, options): subprocess.check_output(build_cmd) ret = 0 except subprocess.CalledProcessError as err: + print(err.output) ret = err.returncode BINARY_CACHE[binary_key] = (ret, build_dir_path) @@ -294,7 +308,7 @@ def hash_binary(bin_path): hasher = hashlib.sha1() with open(bin_path, 'rb') as bin_file: buf = bin_file.read(blocksize) - while len(buf) > 0: + while buf: hasher.update(buf) buf = bin_file.read(blocksize) return hasher.hexdigest() @@ -323,7 +337,8 @@ def iterate_test_runner_jobs(jobs, options): else: tested_hashes[bin_hash] = build_dir_path - test_cmd = [settings.TEST_RUNNER_SCRIPT, bin_path] + test_cmd = get_platform_cmd_prefix() + test_cmd.extend([settings.TEST_RUNNER_SCRIPT, '--engine', bin_path]) yield job, ret_build, test_cmd @@ -373,6 +388,7 @@ def run_jerry_tests(options): if ret_build: break + test_cmd.append('--test-dir') test_cmd.append(settings.JERRY_TESTS_DIR) if options.quiet: @@ -381,9 +397,9 @@ def run_jerry_tests(options): skip_list = [] if '--profile=es2015-subset' in job.build_args: - skip_list.append(r"es5.1\/") + skip_list.append(os.path.join('es5.1', '')) else: - skip_list.append(r"es2015\/") + skip_list.append(os.path.join('es2015', '')) if options.skip_list: skip_list.append(options.skip_list) @@ -404,18 +420,27 @@ def run_jerry_test_suite(options): if ret_build: break + skip_list = [] + if '--profile=minimal' in job.build_args: + test_cmd.append('--test-list') test_cmd.append(settings.JERRY_TEST_SUITE_MINIMAL_LIST) - elif '--profile=es2015-subset' in job.build_args: - test_cmd.append(settings.JERRY_TEST_SUITE_DIR) else: - test_cmd.append(settings.JERRY_TEST_SUITE_ES51_LIST) + test_cmd.append('--test-dir') + test_cmd.append(settings.JERRY_TEST_SUITE_DIR) + if '--profile=es2015-subset' in job.build_args: + skip_list.append(os.path.join('es5.1', '')) + else: + skip_list.append(os.path.join('es2015', '')) if options.quiet: test_cmd.append("-q") if options.skip_list: - test_cmd.append("--skip-list=" + options.skip_list) + skip_list.append(options.skip_list) + + if skip_list: + test_cmd.append("--skip-list=" + ",".join(skip_list)) if job.test_args: test_cmd.extend(job.test_args) @@ -426,7 +451,14 @@ def run_jerry_test_suite(options): def run_test262_test_suite(options): ret_build = ret_test = 0 - for job in TEST262_TEST_SUITE_OPTIONS: + + jobs = [] + if options.test262: + jobs.extend(TEST262_TEST_SUITE_OPTIONS) + if options.test262_es2015: + jobs.extend(TEST262_ES2015_TEST_SUITE_OPTIONS) + + for job in jobs: ret_build, build_dir_path = create_binary(job, options) if ret_build: print("\n%sBuild failed%s\n" % (TERM_RED, TERM_NORMAL)) @@ -434,10 +466,15 @@ def run_test262_test_suite(options): test_cmd = get_platform_cmd_prefix() + [ settings.TEST262_RUNNER_SCRIPT, - get_binary_path(build_dir_path), - settings.TEST262_TEST_SUITE_DIR + '--engine', get_binary_path(build_dir_path), + '--test-dir', settings.TEST262_TEST_SUITE_DIR ] + if '--profile=es2015-subset' in job.build_args: + test_cmd.append('--es2015') + else: + test_cmd.append('--es51') + if job.test_args: test_cmd.extend(job.test_args) @@ -502,7 +539,7 @@ def main(options): Check(options.jerry_debugger, run_jerry_debugger_tests, options), Check(options.jerry_tests, run_jerry_tests, options), Check(options.jerry_test_suite, run_jerry_test_suite, options), - Check(options.test262, run_test262_test_suite, options), + Check(options.test262 or options.test262_es2015, run_test262_test_suite, options), Check(options.unittests, run_unittests, options), Check(options.buildoption_test, run_buildoption_test, options), ] diff --git a/tools/runners/run-test-suite-test262.py b/tools/runners/run-test-suite-test262.py index 059562df..1d3131fc 100755 --- a/tools/runners/run-test-suite-test262.py +++ b/tools/runners/run-test-suite-test262.py @@ -15,12 +15,13 @@ # limitations under the License. from __future__ import print_function +import argparse import os import shutil -import signal import subprocess import sys +import util def get_platform_cmd_prefix(): if sys.platform == 'win32': @@ -28,47 +29,92 @@ def get_platform_cmd_prefix(): return ['python2'] # The official test262.py isn't python3 compatible, but has python shebang. -def set_timezone(timezone): - assert sys.platform == 'win32', "set_timezone is Windows only function" - subprocess.call(get_platform_cmd_prefix() + ['tzutil', '/s', timezone]) +def get_arguments(): + execution_runtime = os.environ.get('RUNTIME', '') + parser = argparse.ArgumentParser() + parser.add_argument('--runtime', metavar='FILE', default=execution_runtime, + help='Execution runtime (e.g. qemu)') + parser.add_argument('--engine', metavar='FILE', required=True, + help='JerryScript binary to run tests with') + parser.add_argument('--test-dir', metavar='DIR', required=True, + help='Directory contains test262 test suite') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--es51', action='store_true', + help='Run test262 ES5.1 version') + group.add_argument('--es2015', action='store_true', + help='Run test262 ES2015 version') + + args = parser.parse_args() + + if args.es2015: + args.test_dir = os.path.join(args.test_dir, 'es2015') + else: + args.test_dir = os.path.join(args.test_dir, 'es51') + + return args -def set_timezone_and_exit(timezone): - set_timezone(timezone) - sys.exit(1) +def prepare_test262_test_suite(args): + if os.path.isdir(os.path.join(args.test_dir, '.git')): + return 0 + return_code = subprocess.call(['git', 'clone', '--no-checkout', + 'https://github.com/tc39/test262.git', args.test_dir]) + if return_code: + print('Cloning test262 repository failed.') + return return_code -def run_test262_tests(runtime, engine, path_to_test262): - if not os.path.isdir(os.path.join(path_to_test262, '.git')): - return_code = subprocess.call(['git', 'clone', 'https://github.com/tc39/test262.git', - '-b', 'es5-tests', path_to_test262]) + if args.es2015: + git_hash = 'fd44cd73dfbce0b515a2474b7cd505d6176a9eb5' + else: + git_hash = 'es5-tests' + + return_code = subprocess.call(['git', 'checkout', git_hash], cwd=args.test_dir) + if return_code: + print('Cloning test262 repository failed - invalid git revision.') + return return_code + + if args.es2015: + shutil.copyfile(os.path.join('tests', 'test262-es6-excludelist.xml'), + os.path.join(args.test_dir, 'excludelist.xml')) + + return_code = subprocess.call(['git', 'apply', os.path.join('..', '..', 'test262-es6.patch')], + cwd=args.test_dir) if return_code: - print('Cloning test262 repository failed.') + print('Applying test262-es6.patch failed') return return_code - path_to_remove = os.path.join(path_to_test262, 'test', 'suite', 'bestPractice') - if os.path.isdir(path_to_remove): - shutil.rmtree(path_to_remove) + else: + path_to_remove = os.path.join(args.test_dir, 'test', 'suite', 'bestPractice') + if os.path.isdir(path_to_remove): + shutil.rmtree(path_to_remove) - path_to_remove = os.path.join(path_to_test262, 'test', 'suite', 'intl402') - if os.path.isdir(path_to_remove): - shutil.rmtree(path_to_remove) + path_to_remove = os.path.join(args.test_dir, 'test', 'suite', 'intl402') + if os.path.isdir(path_to_remove): + shutil.rmtree(path_to_remove) + + return 0 + +def main(args): + return_code = prepare_test262_test_suite(args) + if return_code: + return return_code if sys.platform == 'win32': - original_timezone = subprocess.check_output(get_platform_cmd_prefix() + ['tzutil', '/g']) - set_timezone('Pacific Standard Time') - signal.signal(signal.SIGINT, lambda signal, frame: set_timezone_and_exit(original_timezone)) + original_timezone = util.get_timezone() + util.set_sighdl_to_reset_timezone(original_timezone) + util.set_timezone('Pacific Standard Time') proc = subprocess.Popen(get_platform_cmd_prefix() + - [os.path.join(path_to_test262, 'tools/packaging/test262.py'), - '--command', (runtime + ' ' + engine).strip(), - '--tests', path_to_test262, + [os.path.join(args.test_dir, 'tools/packaging/test262.py'), + '--command', (args.runtime + ' ' + args.engine).strip(), + '--tests', args.test_dir, '--summary'], universal_newlines=True, stdout=subprocess.PIPE) - return_code = 0 - with open(os.path.join(os.path.dirname(engine), 'test262.report'), 'w') as output_file: + return_code = 1 + with open(os.path.join(os.path.dirname(args.engine), 'test262.report'), 'w') as output_file: counter = 0 summary_found = False while True: @@ -77,7 +123,7 @@ def run_test262_tests(runtime, engine, path_to_test262): if not output: break output_file.write(output) - if (counter % 100) == 0: + if not summary_found and (counter % 100) == 0: print("\rExecuted approx %d tests..." % counter, end='') if output.startswith('=== Summary ==='): @@ -86,34 +132,16 @@ def run_test262_tests(runtime, engine, path_to_test262): if summary_found: print(output, end='') - if ('Failed tests' in output) or ('Expected to fail but passed' in output): - return_code = 1 + if 'All tests succeeded' in output: + return_code = 0 proc.wait() if sys.platform == 'win32': - set_timezone(original_timezone) + util.set_timezone(original_timezone) return return_code -def main(): - if len(sys.argv) != 3: - print ("This script performs test262 compliance testing of the specified engine.") - print ("") - print ("Usage:") - print (" 1st parameter: JavaScript engine to be tested.") - print (" 2nd parameter: path to the directory with official test262 testsuite.") - print ("") - print ("Example:") - print (" ./run-test-suite-test262.py ") - sys.exit(1) - - runtime = os.environ.get('RUNTIME', '') - engine = sys.argv[1] - path_to_test262 = sys.argv[2] - - sys.exit(run_test262_tests(runtime, engine, path_to_test262)) - if __name__ == "__main__": - main() + sys.exit(main(get_arguments())) diff --git a/tools/runners/run-test-suite.py b/tools/runners/run-test-suite.py new file mode 100644 index 00000000..33f8bd34 --- /dev/null +++ b/tools/runners/run-test-suite.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python + +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +import argparse +import os +import subprocess +import sys + +import util + +def get_arguments(): + execution_runtime = os.environ.get('RUNTIME') + parser = argparse.ArgumentParser() + parser.add_argument('-q', '--quiet', action='store_true', + help='Only print out failing tests') + parser.add_argument('--runtime', metavar='FILE', default=execution_runtime, + help='Execution runtime (e.g. qemu)') + parser.add_argument('--engine', metavar='FILE', + help='JerryScript binary to run tests with') + parser.add_argument('--test-list', metavar='FILE', + help='File contains test paths to run') + parser.add_argument('--skip-list', metavar='LIST', + help='Add a comma separated list of patterns of the excluded JS-tests') + parser.add_argument('--test-dir', metavar='DIR', + help='Directory contains tests to run') + parser.add_argument('--snapshot', action='store_true', + help='Snapshot test') + + script_args = parser.parse_args() + if script_args.skip_list: + script_args.skip_list = script_args.skip_list.split(',') + else: + script_args.skip_list = [] + + return script_args + + +def get_tests(test_dir, test_list, skip_list): + tests = [] + if test_dir: + tests = [] + for root, _, files in os.walk(test_dir): + tests.extend([os.path.join(root, test_file) for test_file in files if test_file.endswith('.js')]) + + if test_list: + dirname = os.path.dirname(test_list) + with open(test_list, "r") as test_list_fd: + for test in test_list_fd: + tests.append(os.path.normpath(os.path.join(dirname, test.rstrip()))) + + tests.sort() + + def filter_tests(test): + for skipped in skip_list: + if skipped in test: + return False + return True + + return [test for test in tests if filter_tests(test)] + + +def get_platform_cmd_prefix(): + if sys.platform == 'win32': + return ['cmd', '/S', '/C'] + return [] + + +def execute_test_command(test_cmd): + kwargs = {} + if sys.version_info.major >= 3: + kwargs['encoding'] = 'unicode_escape' + kwargs['text'] = True + process = subprocess.Popen(test_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs) + stdout = process.communicate()[0] + return (process.returncode, stdout) + + +def main(args): + tests = get_tests(args.test_dir, args.test_list, args.skip_list) + total = len(tests) + if total == 0: + print("No test to execute.") + return 1 + + if sys.platform == 'win32': + original_timezone = util.get_timezone() + util.set_sighdl_to_reset_timezone(original_timezone) + util.set_timezone('UTC') + + if args.snapshot: + passed = run_snapshot_tests(args, tests) + else: + passed = run_normal_tests(args, tests) + + if sys.platform == 'win32': + util.set_timezone(original_timezone) + + failed = total - passed + + summary_list = [os.path.relpath(args.engine)] + if args.snapshot: + summary_list.append('--snapshot') + if args.test_dir: + summary_list.append(os.path.relpath(args.test_dir)) + if args.test_list: + summary_list.append(os.path.relpath(args.test_list)) + util.print_test_summary(' '.join(summary_list), total, passed, failed) + + return bool(failed) + + +def run_normal_tests(args, tests): + test_cmd = get_platform_cmd_prefix() + if args.runtime: + test_cmd.append(args.runtime) + test_cmd.extend([args.engine, '--call-on-exit', '__checkAsync']) + + total = len(tests) + tested = 0 + passed = 0 + for test in tests: + tested += 1 + test_path = os.path.relpath(test) + is_expected_to_fail = os.path.join(os.path.sep, 'fail', '') in test + (returncode, stdout) = execute_test_command(test_cmd + [test]) + + if (returncode == 0 and not is_expected_to_fail) or (returncode == 1 and is_expected_to_fail): + passed += 1 + if not args.quiet: + passed_string = 'PASS' + (' (XFAIL)' if is_expected_to_fail else '') + util.print_test_result(tested, total, True, passed_string, test_path) + else: + passed_string = 'FAIL%s (%d)' % (' (XPASS)' if returncode == 0 and is_expected_to_fail else '', returncode) + util.print_test_result(tested, total, False, passed_string, test_path) + print("================================================") + print(stdout) + print("================================================") + + return passed + + +def run_snapshot_tests(args, tests): + execute_snapshot_cmd = get_platform_cmd_prefix() + generate_snapshot_cmd = get_platform_cmd_prefix() + if args.runtime: + execute_snapshot_cmd.append(args.runtime) + generate_snapshot_cmd.append(args.runtime) + + execute_snapshot_cmd.extend([args.engine, '--exec-snapshot', 'js.snapshot']) + execute_snapshot_cmd.extend(['--call-on-exit', '__checkAsync']) + + # engine: jerry[.exe] -> snapshot generator: jerry-snapshot[.exe] + engine = os.path.splitext(args.engine) + generate_snapshot_cmd.append(engine[0] + '-snapshot' + engine[1]) + generate_snapshot_cmd.append('generate') + + total = len(tests) + tested = 0 + passed = 0 + for test in tests: + tested += 1 + test_path = os.path.relpath(test) + is_expected_to_fail = os.path.join(os.path.sep, 'fail', '') in test + (returncode, stdout) = execute_test_command(generate_snapshot_cmd + [test]) + + if (returncode == 0) or (returncode == 1 and is_expected_to_fail): + if not args.quiet: + passed_string = 'PASS' + (' (XFAIL)' if returncode else '') + util.print_test_result(tested, total, True, passed_string, test_path, True) + else: + util.print_test_result(tested, total, False, 'FAIL (%d)' % (returncode), test_path, True) + print("================================================") + print(stdout) + print("================================================") + + if returncode: + if is_expected_to_fail: + passed += 1 + continue + + (returncode, stdout) = execute_test_command(execute_snapshot_cmd) + os.remove('js.snapshot') + + if (returncode == 0 and not is_expected_to_fail) or (returncode == 1 and is_expected_to_fail): + passed += 1 + if not args.quiet: + passed_string = 'PASS' + (' (XFAIL)' if is_expected_to_fail else '') + util.print_test_result(tested, total, True, passed_string, test_path, False) + else: + passed_string = 'FAIL%s (%d)' % (' (XPASS)' if returncode == 0 and is_expected_to_fail else '', returncode) + util.print_test_result(tested, total, False, passed_string, test_path, False) + print("================================================") + print(stdout) + print("================================================") + + return passed + + +if __name__ == "__main__": + sys.exit(main(get_arguments())) diff --git a/tools/runners/run-test-suite.sh b/tools/runners/run-test-suite.sh deleted file mode 100755 index b5b376e3..00000000 --- a/tools/runners/run-test-suite.sh +++ /dev/null @@ -1,227 +0,0 @@ -#!/bin/bash - -# Copyright JS Foundation and other contributors, http://js.foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Usage: -# ./tools/runners/run-test-suite.sh ENGINE TESTS [-q] [--skip-list=item1,item2] [--snapshot] ENGINE_ARGS.... - -TIMEOUT=${TIMEOUT:=5} -TIMEOUT_CMD=`which timeout` -if [ $? -ne 0 ] -then - TIMEOUT_CMD=`which gtimeout` -fi - -ENGINE="$1" -shift - -TESTS="$1" -shift - -OUTPUT_DIR=`dirname $ENGINE` -TESTS_BASENAME=`basename $TESTS` - -TEST_FILES=$OUTPUT_DIR/$TESTS_BASENAME.files -TEST_FAILED=$OUTPUT_DIR/$TESTS_BASENAME.failed -TEST_PASSED=$OUTPUT_DIR/$TESTS_BASENAME.passed - -TERM_NORMAL="\033[0m" -TERM_RED="\033[1;31m" -TERM_GREEN="\033[1;32m" - -trap 'exit' SIGINT - -VERBOSE=1 -if [[ "$1" == "-q" ]] -then - unset VERBOSE - shift -fi - -if [[ "$1" =~ ^--skip-list=.* ]] -then - SKIP_LIST=${1#--skip-list=} - SKIP_LIST=${SKIP_LIST//,/ } - shift -fi - -if [ "$1" == "--snapshot" ] -then - TEST_FILES="$TEST_FILES.snapshot" - TEST_FAILED="$TEST_FAILED.snapshot" - TEST_PASSED="$TEST_PASSED.snapshot" - IS_SNAPSHOT=true - - SNAPSHOT_TOOL=${ENGINE}-snapshot - if [ ! -x $SNAPSHOT_TOOL ] - then - echo "$0: $SNAPSHOT_TOOL: not an executable" - exit 1 - fi - shift -fi - -ENGINE_ARGS="$@" - -if [ ! -x $ENGINE ] -then - echo "$0: $ENGINE: not an executable" - exit 1 -fi - -if [ -d $TESTS ] -then - TESTS_DIR=$TESTS - - ( cd $TESTS; find . -name "*.js" ) | sort > $TEST_FILES -elif [ -f $TESTS ] -then - TESTS_DIR=`dirname $TESTS` - - grep -e '.js\s*$' $TESTS | sort > $TEST_FILES -else - echo "$0: $TESTS: not a test suite" - exit 1 -fi - -# Remove the skipped tests from list -for TEST in ${SKIP_LIST} -do - ( sed -i -r "/$TEST/d" $TEST_FILES ) -done - -TOTAL=$(cat $TEST_FILES | wc -l) -if [ "$TOTAL" -eq 0 ] -then - echo "$0: $TESTS: no test in test suite" - exit 1 -fi - -rm -f $TEST_FAILED $TEST_PASSED - -ROOT_DIR="" -CURRENT_DIR=`pwd` -PATH_STEP=2 -while true -do - TMP_ROOT_DIR=`(echo "$CURRENT_DIR"; echo "$0"; echo "$ENGINE"; echo "$TESTS") | cut -f1-$PATH_STEP -d/ | uniq -d` - if [ -z "$TMP_ROOT_DIR" ] - then - break - else - ROOT_DIR="$TMP_ROOT_DIR" - fi - PATH_STEP=$((PATH_STEP+1)) -done -if [ -n "$ROOT_DIR" ] -then - ROOT_DIR="$ROOT_DIR/" -fi - -tested=1 -failed=0 -passed=0 - -ENGINE_TEMP=`mktemp engine-out.XXXXXXXXXX` - -for test in `cat $TEST_FILES` -do - if [[ $test =~ ^\.\/fail\/ ]] - then - error_code=1 - PASS="PASS (XFAIL)" - else - error_code=0 - PASS="PASS" - fi - - full_test=$TESTS_DIR/${test#./} - - if [ "$IS_SNAPSHOT" == true ] - then - # Testing snapshot - SNAPSHOT_TEMP=`mktemp $(basename -s .js $test).snapshot.XXXXXXXXXX` - - $TIMEOUT_CMD $TIMEOUT $RUNTIME $SNAPSHOT_TOOL generate -o $SNAPSHOT_TEMP $full_test &> $ENGINE_TEMP - status_code=$? - comment=" (generate snapshot)" - - if [ $status_code -eq 0 ] - then - test $VERBOSE && printf "[%4d/%4d] %bPASS: %s%s%b\n" "$tested" "$TOTAL" "$TERM_GREEN" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL" - - $TIMEOUT_CMD $TIMEOUT $RUNTIME $ENGINE $ENGINE_ARGS --exec-snapshot $SNAPSHOT_TEMP &> $ENGINE_TEMP - status_code=$? - comment=" (execute snapshot)" - fi - - rm -f $SNAPSHOT_TEMP - else - $TIMEOUT_CMD $TIMEOUT $RUNTIME $ENGINE $ENGINE_ARGS $full_test &> $ENGINE_TEMP - status_code=$? - comment="" - fi - - if [ $status_code -ne $error_code ] - then - printf "[%4d/%4d] %bFAIL (%d): %s%s%b\n" "$tested" "$TOTAL" "$TERM_RED" "$status_code" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL" - cat $ENGINE_TEMP - - echo "$status_code: $test" >> $TEST_FAILED - echo "============================================" >> $TEST_FAILED - cat $ENGINE_TEMP >> $TEST_FAILED - echo "============================================" >> $TEST_FAILED - echo >> $TEST_FAILED - echo >> $TEST_FAILED - - failed=$((failed+1)) - else - test $VERBOSE && printf "[%4d/%4d] %b%s: %s%s%b\n" "$tested" "$TOTAL" "$TERM_GREEN" "$PASS" "${full_test#$ROOT_DIR}" "$comment" "$TERM_NORMAL" - echo "$test" >> $TEST_PASSED - - passed=$((passed+1)) - fi - - tested=$((tested+1)) -done - -rm -f $ENGINE_TEMP - -ratio=$(echo $passed*100/$TOTAL | bc) -if [ $passed -eq $TOTAL ] -then - success_color=$TERM_GREEN -else - success_color=$TERM_RED -fi - -if [ "$IS_SNAPSHOT" == true ] -then - ENGINE_ARGS="--snapshot $ENGINE_ARGS" -fi - -echo -e "\n[summary] ${ENGINE#$ROOT_DIR} $ENGINE_ARGS ${TESTS#$ROOT_DIR}\n" -echo -e "TOTAL: $TOTAL" -echo -e "${TERM_GREEN}PASS: $passed${TERM_NORMAL}" -echo -e "${TERM_RED}FAIL: $failed${TERM_NORMAL}\n" -echo -e "${success_color}Success: $ratio%${TERM_NORMAL}\n" - -if [ $failed -ne 0 ] -then - echo "$0: see $TEST_FAILED for details about failures" - exit 1 -fi - -exit 0 diff --git a/tools/runners/run-unittests.py b/tools/runners/run-unittests.py index d0ef6719..6a38e332 100755 --- a/tools/runners/run-unittests.py +++ b/tools/runners/run-unittests.py @@ -21,14 +21,16 @@ import os import subprocess import sys -TERM_NORMAL = '\033[0m' -TERM_RED = '\033[1;31m' -TERM_GREEN = '\033[1;32m' +import util + def get_arguments(): + runtime = os.environ.get('RUNTIME') parser = argparse.ArgumentParser() parser.add_argument('-q', '--quiet', action='store_true', help='Only print out failing tests') + parser.add_argument('--runtime', metavar='FILE', default=runtime, + help='Execution runtime (e.g. qemu)') parser.add_argument('path', help='Path of test binaries') @@ -54,39 +56,30 @@ def main(args): print("%s: no unit-* test to execute", args.path) return 1 + test_cmd = [args.runtime] if args.runtime else [] + tested = 0 passed = 0 failed = 0 - - runtime = os.environ.get('RUNTIME') - test_cmd = [runtime] if runtime else [] - for test in unittests: tested += 1 - testpath = os.path.relpath(test) + test_path = os.path.relpath(test) try: subprocess.check_output(test_cmd + [test], stderr=subprocess.STDOUT, universal_newlines=True) passed += 1 if not args.quiet: - print("[%4d/%4d] %sPASS: %s%s" % (tested, total, TERM_GREEN, testpath, TERM_NORMAL)) + util.print_test_result(tested, total, True, 'PASS', test_path) except subprocess.CalledProcessError as err: failed += 1 - print("[%4d/%4d] %sFAIL (%d): %s%s" % (tested, total, TERM_RED, err.returncode, testpath, TERM_NORMAL)) + util.print_test_result(tested, total, False, 'FAIL (%d)' % err.returncode, test_path) print("================================================") print(err.output) print("================================================") - print("\n[summary] %s\n" % os.path.join(os.path.relpath(args.path), "unit-*")) - print("TOTAL: %d" % total) - print("%sPASS: %d%s" % (TERM_GREEN, passed, TERM_NORMAL)) - print("%sFAIL: %d%s\n" % (TERM_RED, failed, TERM_NORMAL)) - - success_color = TERM_GREEN if passed == total else TERM_RED - print("%sSuccess: %d%%%s" % (success_color, passed*100/total, TERM_NORMAL)) + util.print_test_summary(os.path.join(os.path.relpath(args.path), "unit-*"), total, passed, failed) if failed > 0: return 1 - return 0 diff --git a/tools/runners/util.py b/tools/runners/util.py new file mode 100644 index 00000000..876a8dd8 --- /dev/null +++ b/tools/runners/util.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +import signal +import subprocess +import sys + +TERM_NORMAL = '\033[0m' +TERM_RED = '\033[1;31m' +TERM_GREEN = '\033[1;32m' + + +def set_timezone(timezone): + assert sys.platform == 'win32', "set_timezone is Windows only function" + subprocess.call(['cmd', '/S', '/C', 'tzutil', '/s', timezone]) + + +def set_timezone_and_exit(timezone): + assert sys.platform == 'win32', "set_timezone_and_exit is Windows only function" + set_timezone(timezone) + sys.exit(1) + + +def get_timezone(): + assert sys.platform == 'win32', "get_timezone is Windows only function" + return subprocess.check_output(['cmd', '/S', '/C', 'tzutil', '/g']) + + +def set_sighdl_to_reset_timezone(timezone): + assert sys.platform == 'win32', "install_signal_handler_to_restore_timezone is Windows only function" + signal.signal(signal.SIGINT, lambda signal, frame: set_timezone_and_exit(timezone)) + + +def print_test_summary(summary_string, total, passed, failed): + print("\n[summary] %s\n" % summary_string) + print("TOTAL: %d" % total) + print("%sPASS: %d%s" % (TERM_GREEN, passed, TERM_NORMAL)) + print("%sFAIL: %d%s\n" % (TERM_RED, failed, TERM_NORMAL)) + + success_color = TERM_GREEN if passed == total else TERM_RED + print("%sSuccess: %d%%%s" % (success_color, passed*100/total, TERM_NORMAL)) + + +def print_test_result(tested, total, is_passed, passed_string, test_path, is_snapshot_generation=None): + if is_snapshot_generation is None: + snapshot_string = '' + elif is_snapshot_generation: + snapshot_string = ' (generate snapshot)' + else: + snapshot_string = ' (execute snapshot)' + + color = TERM_GREEN if is_passed else TERM_RED + print("[%4d/%4d] %s%s: %s%s%s" % (tested, total, color, passed_string, test_path, snapshot_string, TERM_NORMAL)) diff --git a/tools/settings.py b/tools/settings.py index 733f5605..a9eda53a 100755 --- a/tools/settings.py +++ b/tools/settings.py @@ -22,7 +22,6 @@ DEBUGGER_TESTS_DIR = path.join(PROJECT_DIR, 'tests/debugger') JERRY_TESTS_DIR = path.join(PROJECT_DIR, 'tests/jerry') JERRY_TEST_SUITE_DIR = path.join(PROJECT_DIR, 'tests/jerry-test-suite') JERRY_TEST_SUITE_MINIMAL_LIST = path.join(PROJECT_DIR, 'tests/jerry-test-suite/minimal-profile-list') -JERRY_TEST_SUITE_ES51_LIST = path.join(PROJECT_DIR, 'tests/jerry-test-suite/es51-profile-list') TEST262_TEST_SUITE_DIR = path.join(PROJECT_DIR, 'tests/test262') BUILD_SCRIPT = path.join(TOOLS_DIR, 'build.py') @@ -34,7 +33,7 @@ LICENSE_SCRIPT = path.join(TOOLS_DIR, 'check-license.py') MAGIC_STRINGS_SCRIPT = path.join(TOOLS_DIR, 'check-magic-strings.sh') PYLINT_SCRIPT = path.join(TOOLS_DIR, 'check-pylint.sh') SIGNED_OFF_SCRIPT = path.join(TOOLS_DIR, 'check-signed-off.sh') -TEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-test-suite.sh') +TEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-test-suite.py') TEST262_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-test-suite-test262.py') VERA_SCRIPT = path.join(TOOLS_DIR, 'check-vera.sh') UNITTEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-unittests.py') diff --git a/tools/unit-tests/gen-test-libm.c b/tools/unit-tests/gen-test-libm.c index 12dddd84..3ee4f00e 100644 --- a/tools/unit-tests/gen-test-libm.c +++ b/tools/unit-tests/gen-test-libm.c @@ -210,6 +210,93 @@ main (int argc, char **args) GEN_DBL_TEST (atan2 (0.4, 0.0003)); GEN_DBL_TEST (atan2 (1.4, -0.93)); + /* acosh tests */ + GEN_DBL_TEST (acosh (0.0)); + GEN_DBL_TEST (acosh (-0.0)); + GEN_DBL_TEST (acosh (1.0)); + GEN_DBL_TEST (acosh (-1.0)); + GEN_DBL_TEST (acosh (INFINITY)); + GEN_DBL_TEST (acosh (-INFINITY)); + GEN_DBL_TEST (acosh (NAN)); + GEN_DBL_TEST (acosh (7.08e+02)); + GEN_DBL_TEST (acosh (7.10e+02)); + GEN_DBL_TEST (acosh (-7.40e+02)); + GEN_DBL_TEST (acosh (-7.50e+02)); + GEN_DBL_TEST (acosh (0.34)); + GEN_DBL_TEST (acosh (-0.34)); + GEN_DBL_TEST (acosh (0.35)); + GEN_DBL_TEST (acosh (-0.35)); + GEN_DBL_TEST (acosh (1.03)); + GEN_DBL_TEST (acosh (-1.03)); + GEN_DBL_TEST (acosh (1.04)); + GEN_DBL_TEST (acosh (-1.04)); + GEN_DBL_TEST (acosh (3.72e-09)); + GEN_DBL_TEST (acosh (-3.72e-09)); + GEN_DBL_TEST (acosh (3.73e-09)); + GEN_DBL_TEST (acosh (-3.73e-09)); + GEN_DBL_TEST (acosh (2.0)); + GEN_DBL_TEST (acosh (3.0)); + GEN_DBL_TEST (acosh (0.7)); + GEN_DBL_TEST (acosh (38.0)); + + /* asinh tests */ + GEN_DBL_TEST (asinh (0.0)); + GEN_DBL_TEST (asinh (-0.0)); + GEN_DBL_TEST (asinh (1.0)); + GEN_DBL_TEST (asinh (-1.0)); + GEN_DBL_TEST (asinh (INFINITY)); + GEN_DBL_TEST (asinh (-INFINITY)); + GEN_DBL_TEST (asinh (NAN)); + GEN_DBL_TEST (asinh (7.08e+02)); + GEN_DBL_TEST (asinh (7.10e+02)); + GEN_DBL_TEST (asinh (-7.40e+02)); + GEN_DBL_TEST (asinh (-7.50e+02)); + GEN_DBL_TEST (asinh (0.34)); + GEN_DBL_TEST (asinh (-0.34)); + GEN_DBL_TEST (asinh (0.35)); + GEN_DBL_TEST (asinh (-0.35)); + GEN_DBL_TEST (asinh (1.03)); + GEN_DBL_TEST (asinh (-1.03)); + GEN_DBL_TEST (asinh (1.04)); + GEN_DBL_TEST (asinh (-1.04)); + GEN_DBL_TEST (asinh (3.72e-09)); + GEN_DBL_TEST (asinh (-3.72e-09)); + GEN_DBL_TEST (asinh (3.73e-09)); + GEN_DBL_TEST (asinh (-3.73e-09)); + GEN_DBL_TEST (asinh (2.0)); + GEN_DBL_TEST (asinh (3.0)); + GEN_DBL_TEST (asinh (0.7)); + GEN_DBL_TEST (asinh (38.0)); + + /* atanh tests */ + GEN_DBL_TEST (atanh (0.0)); + GEN_DBL_TEST (atanh (-0.0)); + GEN_DBL_TEST (atanh (1.0)); + GEN_DBL_TEST (atanh (-1.0)); + GEN_DBL_TEST (atanh (INFINITY)); + GEN_DBL_TEST (atanh (-INFINITY)); + GEN_DBL_TEST (atanh (NAN)); + GEN_DBL_TEST (atanh (7.08e+02)); + GEN_DBL_TEST (atanh (7.10e+02)); + GEN_DBL_TEST (atanh (-7.40e+02)); + GEN_DBL_TEST (atanh (-7.50e+02)); + GEN_DBL_TEST (atanh (0.34)); + GEN_DBL_TEST (atanh (-0.34)); + GEN_DBL_TEST (atanh (0.35)); + GEN_DBL_TEST (atanh (-0.35)); + GEN_DBL_TEST (atanh (1.03)); + GEN_DBL_TEST (atanh (-1.03)); + GEN_DBL_TEST (atanh (1.04)); + GEN_DBL_TEST (atanh (-1.04)); + GEN_DBL_TEST (atanh (3.72e-09)); + GEN_DBL_TEST (atanh (-3.72e-09)); + GEN_DBL_TEST (atanh (3.73e-09)); + GEN_DBL_TEST (atanh (-3.73e-09)); + GEN_DBL_TEST (atanh (2.0)); + GEN_DBL_TEST (atanh (3.0)); + GEN_DBL_TEST (atanh (0.7)); + GEN_DBL_TEST (atanh (38.0)); + /* ceil tests */ GEN_DBL_TEST (ceil (0.0)); GEN_DBL_TEST (ceil (-0.0)); @@ -309,6 +396,35 @@ main (int argc, char **args) GEN_DBL_TEST (exp (0.7)); GEN_DBL_TEST (exp (38.0)); + /* expm1 tests */ + GEN_DBL_TEST (expm1 (0.0)); + GEN_DBL_TEST (expm1 (-0.0)); + GEN_DBL_TEST (expm1 (1.0)); + GEN_DBL_TEST (expm1 (-1.0)); + GEN_DBL_TEST (expm1 (INFINITY)); + GEN_DBL_TEST (expm1 (-INFINITY)); + GEN_DBL_TEST (expm1 (NAN)); + GEN_DBL_TEST (expm1 (7.08e+02)); + GEN_DBL_TEST (expm1 (7.10e+02)); + GEN_DBL_TEST (expm1 (-7.40e+02)); + GEN_DBL_TEST (expm1 (-7.50e+02)); + GEN_DBL_TEST (expm1 (0.34)); + GEN_DBL_TEST (expm1 (-0.34)); + GEN_DBL_TEST (expm1 (0.35)); + GEN_DBL_TEST (expm1 (-0.35)); + GEN_DBL_TEST (expm1 (1.03)); + GEN_DBL_TEST (expm1 (-1.03)); + GEN_DBL_TEST (expm1 (1.04)); + GEN_DBL_TEST (expm1 (-1.04)); + GEN_DBL_TEST (expm1 (3.72e-09)); + GEN_DBL_TEST (expm1 (-3.72e-09)); + GEN_DBL_TEST (expm1 (3.73e-09)); + GEN_DBL_TEST (expm1 (-3.73e-09)); + GEN_DBL_TEST (expm1 (2.0)); + GEN_DBL_TEST (expm1 (3.0)); + GEN_DBL_TEST (expm1 (0.7)); + GEN_DBL_TEST (expm1 (38.0)); + /* fabs tests */ GEN_DBL_TEST (fabs (0.0)); GEN_DBL_TEST (fabs (-0.0)); @@ -455,6 +571,69 @@ main (int argc, char **args) GEN_DBL_TEST (log (2000.0)); GEN_DBL_TEST (log (2001.0)); + /* log1p tests */ + GEN_DBL_TEST (log1p (0.0)); + GEN_DBL_TEST (log1p (-0.0)); + GEN_DBL_TEST (log1p (1.0)); + GEN_DBL_TEST (log1p (-1.0)); + GEN_DBL_TEST (log1p (INFINITY)); + GEN_DBL_TEST (log1p (-INFINITY)); + GEN_DBL_TEST (log1p (NAN)); + GEN_DBL_TEST (log1p (M_E)); + GEN_DBL_TEST (log1p (1.0 / M_E)); + GEN_DBL_TEST (log1p (2)); + GEN_DBL_TEST (log1p (10)); + GEN_DBL_TEST (log1p (0.7)); + GEN_DBL_TEST (log1p (2.22e-308)); + GEN_DBL_TEST (log1p (2.23e-308)); + GEN_DBL_TEST (log1p (0.17)); + GEN_DBL_TEST (log1p (0.18)); + GEN_DBL_TEST (log1p (1999.0)); + GEN_DBL_TEST (log1p (2000.0)); + GEN_DBL_TEST (log1p (2001.0)); + + /* log2 tests */ + GEN_DBL_TEST (log2 (0.0)); + GEN_DBL_TEST (log2 (-0.0)); + GEN_DBL_TEST (log2 (1.0)); + GEN_DBL_TEST (log2 (-1.0)); + GEN_DBL_TEST (log2 (INFINITY)); + GEN_DBL_TEST (log2 (-INFINITY)); + GEN_DBL_TEST (log2 (NAN)); + GEN_DBL_TEST (log2 (M_E)); + GEN_DBL_TEST (log2 (1.0 / M_E)); + GEN_DBL_TEST (log2 (2)); + GEN_DBL_TEST (log2 (10)); + GEN_DBL_TEST (log2 (0.7)); + GEN_DBL_TEST (log2 (2.22e-308)); + GEN_DBL_TEST (log2 (2.23e-308)); + GEN_DBL_TEST (log2 (0.17)); + GEN_DBL_TEST (log2 (0.18)); + GEN_DBL_TEST (log2 (1999.0)); + GEN_DBL_TEST (log2 (2000.0)); + GEN_DBL_TEST (log2 (2001.0)); + + /* log10 tests */ + GEN_DBL_TEST (log10 (0.0)); + GEN_DBL_TEST (log10 (-0.0)); + GEN_DBL_TEST (log10 (1.0)); + GEN_DBL_TEST (log10 (-1.0)); + GEN_DBL_TEST (log10 (INFINITY)); + GEN_DBL_TEST (log10 (-INFINITY)); + GEN_DBL_TEST (log10 (NAN)); + GEN_DBL_TEST (log10 (M_E)); + GEN_DBL_TEST (log10 (1.0 / M_E)); + GEN_DBL_TEST (log10 (2)); + GEN_DBL_TEST (log10 (10)); + GEN_DBL_TEST (log10 (0.7)); + GEN_DBL_TEST (log10 (2.22e-308)); + GEN_DBL_TEST (log10 (2.23e-308)); + GEN_DBL_TEST (log10 (0.17)); + GEN_DBL_TEST (log10 (0.18)); + GEN_DBL_TEST (log10 (1999.0)); + GEN_DBL_TEST (log10 (2000.0)); + GEN_DBL_TEST (log10 (2001.0)); + /* pow tests */ GEN_DBL_TEST (pow (0.0, 0.0)); GEN_DBL_TEST (pow (0.0, -0.0)); @@ -625,6 +804,31 @@ main (int argc, char **args) GEN_DBL_TEST (sqrt (6642.25)); GEN_DBL_TEST (sqrt (15239.9025)); + /* cbrt tests */ + GEN_DBL_TEST (cbrt (0.0)); + GEN_DBL_TEST (cbrt (-0.0)); + GEN_DBL_TEST (cbrt (1.0)); + GEN_DBL_TEST (cbrt (-1.0)); + GEN_DBL_TEST (cbrt (INFINITY)); + GEN_DBL_TEST (cbrt (-INFINITY)); + GEN_DBL_TEST (cbrt (NAN)); + GEN_DBL_TEST (cbrt (0.7)); + GEN_DBL_TEST (cbrt (2)); + GEN_DBL_TEST (cbrt (10)); + GEN_DBL_TEST (cbrt (2.22e-308)); + GEN_DBL_TEST (cbrt (2.23e-308)); + GEN_DBL_TEST (cbrt (3.72e-09)); + GEN_DBL_TEST (cbrt (7.37e+19)); + GEN_DBL_TEST (cbrt (2209)); + GEN_DBL_TEST (cbrt (4)); + GEN_DBL_TEST (cbrt (0.25)); + GEN_DBL_TEST (cbrt (6642.25)); + GEN_DBL_TEST (cbrt (15239.9025)); + GEN_DBL_TEST (cbrt (3)); + GEN_DBL_TEST (cbrt (9)); + GEN_DBL_TEST (cbrt (-17.87)); + GEN_DBL_TEST (cbrt (-8941)); + /* sin tests */ GEN_DBL_TEST (sin (0.0)); GEN_DBL_TEST (sin (-0.0)); @@ -763,4 +967,151 @@ main (int argc, char **args) GEN_DBL_TEST (tan (-6.0)); GEN_DBL_TEST (tan (7.0)); GEN_DBL_TEST (tan (-7.0)); + + /* cosh tests */ + GEN_DBL_TEST (cosh (0.0)); + GEN_DBL_TEST (cosh (-0.0)); + GEN_DBL_TEST (cosh (1.0)); + GEN_DBL_TEST (cosh (-1.0)); + GEN_DBL_TEST (cosh (INFINITY)); + GEN_DBL_TEST (cosh (-INFINITY)); + GEN_DBL_TEST (cosh (NAN)); + GEN_DBL_TEST (cosh (M_PI)); + GEN_DBL_TEST (cosh (-M_PI)); + GEN_DBL_TEST (cosh (2.0 * M_PI)); + GEN_DBL_TEST (cosh (-2.0 * M_PI)); + GEN_DBL_TEST (cosh (M_PI / 2.0)); + GEN_DBL_TEST (cosh (-M_PI / 2.0)); + GEN_DBL_TEST (cosh (M_PI / 3.0)); + GEN_DBL_TEST (cosh (-M_PI / 3.0)); + GEN_DBL_TEST (cosh (M_PI / 4.0)); + GEN_DBL_TEST (cosh (-M_PI / 4.0)); + GEN_DBL_TEST (cosh (M_PI / 6.0)); + GEN_DBL_TEST (cosh (-M_PI / 6.0)); + GEN_DBL_TEST (cosh (M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (cosh (-M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (cosh (M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (cosh (-M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (cosh (6.9e-18)); + GEN_DBL_TEST (cosh (-6.9e-18)); + GEN_DBL_TEST (cosh (7.0e-18)); + GEN_DBL_TEST (cosh (-7.0e-18)); + GEN_DBL_TEST (cosh (7.4e-9)); + GEN_DBL_TEST (cosh (-7.4e-9)); + GEN_DBL_TEST (cosh (7.5e-9)); + GEN_DBL_TEST (cosh (-7.5e-9)); + GEN_DBL_TEST (cosh (0.2)); + GEN_DBL_TEST (cosh (-0.2)); + GEN_DBL_TEST (cosh (0.4)); + GEN_DBL_TEST (cosh (-0.4)); + GEN_DBL_TEST (cosh (0.7)); + GEN_DBL_TEST (cosh (-0.7)); + GEN_DBL_TEST (cosh (0.8)); + GEN_DBL_TEST (cosh (-0.8)); + GEN_DBL_TEST (cosh (3.0)); + GEN_DBL_TEST (cosh (-3.0)); + GEN_DBL_TEST (cosh (4.0)); + GEN_DBL_TEST (cosh (-4.0)); + GEN_DBL_TEST (cosh (6.0)); + GEN_DBL_TEST (cosh (-6.0)); + GEN_DBL_TEST (cosh (7.0)); + GEN_DBL_TEST (cosh (-7.0)); + + /* sinh tests */ + GEN_DBL_TEST (sinh (0.0)); + GEN_DBL_TEST (sinh (-0.0)); + GEN_DBL_TEST (sinh (1.0)); + GEN_DBL_TEST (sinh (-1.0)); + GEN_DBL_TEST (sinh (INFINITY)); + GEN_DBL_TEST (sinh (-INFINITY)); + GEN_DBL_TEST (sinh (NAN)); + GEN_DBL_TEST (sinh (M_PI)); + GEN_DBL_TEST (sinh (-M_PI)); + GEN_DBL_TEST (sinh (2.0 * M_PI)); + GEN_DBL_TEST (sinh (-2.0 * M_PI)); + GEN_DBL_TEST (sinh (M_PI / 2.0)); + GEN_DBL_TEST (sinh (-M_PI / 2.0)); + GEN_DBL_TEST (sinh (M_PI / 3.0)); + GEN_DBL_TEST (sinh (-M_PI / 3.0)); + GEN_DBL_TEST (sinh (M_PI / 4.0)); + GEN_DBL_TEST (sinh (-M_PI / 4.0)); + GEN_DBL_TEST (sinh (M_PI / 6.0)); + GEN_DBL_TEST (sinh (-M_PI / 6.0)); + GEN_DBL_TEST (sinh (M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (sinh (-M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (sinh (M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (sinh (-M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (sinh (6.9e-18)); + GEN_DBL_TEST (sinh (-6.9e-18)); + GEN_DBL_TEST (sinh (7.0e-18)); + GEN_DBL_TEST (sinh (-7.0e-18)); + GEN_DBL_TEST (sinh (7.4e-9)); + GEN_DBL_TEST (sinh (-7.4e-9)); + GEN_DBL_TEST (sinh (7.5e-9)); + GEN_DBL_TEST (sinh (-7.5e-9)); + GEN_DBL_TEST (sinh (0.2)); + GEN_DBL_TEST (sinh (-0.2)); + GEN_DBL_TEST (sinh (0.4)); + GEN_DBL_TEST (sinh (-0.4)); + GEN_DBL_TEST (sinh (0.7)); + GEN_DBL_TEST (sinh (-0.7)); + GEN_DBL_TEST (sinh (0.8)); + GEN_DBL_TEST (sinh (-0.8)); + GEN_DBL_TEST (sinh (3.0)); + GEN_DBL_TEST (sinh (-3.0)); + GEN_DBL_TEST (sinh (4.0)); + GEN_DBL_TEST (sinh (-4.0)); + GEN_DBL_TEST (sinh (6.0)); + GEN_DBL_TEST (sinh (-6.0)); + GEN_DBL_TEST (sinh (7.0)); + GEN_DBL_TEST (sinh (-7.0)); + + /* tanh tests */ + GEN_DBL_TEST (tanh (0.0)); + GEN_DBL_TEST (tanh (-0.0)); + GEN_DBL_TEST (tanh (1.0)); + GEN_DBL_TEST (tanh (-1.0)); + GEN_DBL_TEST (tanh (INFINITY)); + GEN_DBL_TEST (tanh (-INFINITY)); + GEN_DBL_TEST (tanh (NAN)); + GEN_DBL_TEST (tanh (M_PI)); + GEN_DBL_TEST (tanh (-M_PI)); + GEN_DBL_TEST (tanh (2.0 * M_PI)); + GEN_DBL_TEST (tanh (-2.0 * M_PI)); + GEN_DBL_TEST (tanh (M_PI / 2.0)); + GEN_DBL_TEST (tanh (-M_PI / 2.0)); + GEN_DBL_TEST (tanh (M_PI / 3.0)); + GEN_DBL_TEST (tanh (-M_PI / 3.0)); + GEN_DBL_TEST (tanh (M_PI / 4.0)); + GEN_DBL_TEST (tanh (-M_PI / 4.0)); + GEN_DBL_TEST (tanh (M_PI / 6.0)); + GEN_DBL_TEST (tanh (-M_PI / 6.0)); + GEN_DBL_TEST (tanh (M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (tanh (-M_PI * 2.0 / 3.0)); + GEN_DBL_TEST (tanh (M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (tanh (-M_PI * 5.0 / 6.0)); + GEN_DBL_TEST (tanh (6.9e-18)); + GEN_DBL_TEST (tanh (-6.9e-18)); + GEN_DBL_TEST (tanh (7.0e-18)); + GEN_DBL_TEST (tanh (-7.0e-18)); + GEN_DBL_TEST (tanh (7.4e-9)); + GEN_DBL_TEST (tanh (-7.4e-9)); + GEN_DBL_TEST (tanh (7.5e-9)); + GEN_DBL_TEST (tanh (-7.5e-9)); + GEN_DBL_TEST (tanh (0.2)); + GEN_DBL_TEST (tanh (-0.2)); + GEN_DBL_TEST (tanh (0.4)); + GEN_DBL_TEST (tanh (-0.4)); + GEN_DBL_TEST (tanh (0.7)); + GEN_DBL_TEST (tanh (-0.7)); + GEN_DBL_TEST (tanh (0.8)); + GEN_DBL_TEST (tanh (-0.8)); + GEN_DBL_TEST (tanh (3.0)); + GEN_DBL_TEST (tanh (-3.0)); + GEN_DBL_TEST (tanh (4.0)); + GEN_DBL_TEST (tanh (-4.0)); + GEN_DBL_TEST (tanh (6.0)); + GEN_DBL_TEST (tanh (-6.0)); + GEN_DBL_TEST (tanh (7.0)); + GEN_DBL_TEST (tanh (-7.0)); } /* main */ diff --git a/tools/vera++/profiles/jerry b/tools/vera++/profiles/jerry index 23fa0975..1ffa7a50 100644 --- a/tools/vera++/profiles/jerry +++ b/tools/vera++/profiles/jerry @@ -11,6 +11,8 @@ set rules { jerry_no_space_before_closing_parentheses jerry_no_tabs jerry_no_trailing_spaces + jerry_no_leading_or_trailing_empty_line + jerry_no_consecutive_empty_lines jerry_pointer_declarator_space jerry_switch_case jerry_typecast_space_parentheses diff --git a/tools/vera++/scripts/rules/jerry_no_consecutive_empty_lines.tcl b/tools/vera++/scripts/rules/jerry_no_consecutive_empty_lines.tcl new file mode 100644 index 00000000..030ce84c --- /dev/null +++ b/tools/vera++/scripts/rules/jerry_no_consecutive_empty_lines.tcl @@ -0,0 +1,36 @@ +#!/usr/bin/tclsh + +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set maxEmptyLines 1 + +foreach f [getSourceFileNames] { + set lineNumber 1 + set emptyCount 0 + set reported false + foreach line [getAllLines $f] { + if {[string trim $line] == ""} { + incr emptyCount + if {$emptyCount > $maxEmptyLines && $reported == "false"} { + report $f $lineNumber "too many consecutive empty lines" + set reported true + } + } else { + set emptyCount 0 + set reported false + } + incr lineNumber + } +} diff --git a/tools/vera++/scripts/rules/jerry_no_leading_or_trailing_empty_line.tcl b/tools/vera++/scripts/rules/jerry_no_leading_or_trailing_empty_line.tcl new file mode 100644 index 00000000..340dad2c --- /dev/null +++ b/tools/vera++/scripts/rules/jerry_no_leading_or_trailing_empty_line.tcl @@ -0,0 +1,30 @@ +#!/usr/bin/tclsh + +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +foreach f [getSourceFileNames] { + set lineCount [getLineCount $f] + if {$lineCount > 0} { + set firstLine [getLine $f 1] + if {[string trim $firstLine] == ""} { + report $f 1 "leading empty line(s)" + } + + set lastLine [getLine $f $lineCount] + if {[string trim $lastLine] == ""} { + report $f $lineCount "trailing empty line(s)" + } + } +} diff --git a/tools/vera++/scripts/rules/jerry_typecast_space_parentheses.tcl b/tools/vera++/scripts/rules/jerry_typecast_space_parentheses.tcl index 5b8c9c9c..c952ef99 100644 --- a/tools/vera++/scripts/rules/jerry_typecast_space_parentheses.tcl +++ b/tools/vera++/scripts/rules/jerry_typecast_space_parentheses.tcl @@ -22,7 +22,7 @@ proc check_part_of_the_file {file line_num col_start col_end} { set line [getLine $file $line_num] set line [string range $line $col_start $col_end] - if {[regexp {\)\w} $line]} { + if {[regexp {\)[\w\(&~=]} $line]} { report $file $line_num "there should be exactly one space after right parentheses" } }