test-bytecode-js.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Bytecode/Generator.h>
  7. #include <LibJS/Bytecode/Interpreter.h>
  8. #include <LibJS/Interpreter.h>
  9. #include <LibJS/Runtime/VM.h>
  10. #include <LibJS/Script.h>
  11. #include <LibTest/TestCase.h>
  12. #define SETUP_AND_PARSE(source) \
  13. auto vm = JS::VM::create(); \
  14. auto ast_interpreter = JS::Interpreter::create<JS::GlobalObject>(*vm); \
  15. \
  16. auto script_or_error = JS::Script::parse(source, ast_interpreter->realm()); \
  17. EXPECT(!script_or_error.is_error()); \
  18. \
  19. auto script = script_or_error.release_value(); \
  20. auto const& program = script->parse_node(); \
  21. JS::Bytecode::Interpreter bytecode_interpreter(ast_interpreter->global_object(), ast_interpreter->realm());
  22. #define EXPECT_NO_EXCEPTION(executable) \
  23. auto executable = JS::Bytecode::Generator::generate(program); \
  24. auto result = bytecode_interpreter.run(executable); \
  25. EXPECT(!result.is_error()); \
  26. EXPECT(!vm->exception());
  27. #define EXPECT_NO_EXCEPTION_WITH_OPTIMIZATIONS(executable) \
  28. auto& passes = JS::Bytecode::Interpreter::optimization_pipeline(); \
  29. passes.perform(executable); \
  30. \
  31. auto result_with_optimizations = bytecode_interpreter.run(executable); \
  32. \
  33. EXPECT(!result_with_optimizations.is_error()); \
  34. EXPECT(!vm->exception())
  35. #define EXPECT_NO_EXCEPTION_ALL(source) \
  36. SETUP_AND_PARSE(source) \
  37. EXPECT_NO_EXCEPTION(executable) \
  38. EXPECT_NO_EXCEPTION_WITH_OPTIMIZATIONS(executable)
  39. TEST_CASE(empty_program)
  40. {
  41. EXPECT_NO_EXCEPTION_ALL("");
  42. }
  43. TEST_CASE(if_statement_pass)
  44. {
  45. EXPECT_NO_EXCEPTION_ALL("if (false) throw new Exception('failed');");
  46. }
  47. TEST_CASE(if_statement_fail)
  48. {
  49. SETUP_AND_PARSE("if (true) throw new Exception('failed');");
  50. auto executable = JS::Bytecode::Generator::generate(program);
  51. auto result = bytecode_interpreter.run(executable);
  52. EXPECT(result.is_error());
  53. }
  54. TEST_CASE(trivial_program)
  55. {
  56. EXPECT_NO_EXCEPTION_ALL("if (1 + 1 !== 2) throw new Exception('failed');");
  57. }
  58. TEST_CASE(variables)
  59. {
  60. EXPECT_NO_EXCEPTION_ALL("var a = 1; \n"
  61. "if (a + 1 !== 2) throw new Exception('failed'); ");
  62. }
  63. TEST_CASE(function_call)
  64. {
  65. EXPECT_NO_EXCEPTION_ALL("if (!isNaN(NaN)) throw new Exception('failed'); ");
  66. }
  67. TEST_CASE(function_delcaration_and_call)
  68. {
  69. EXPECT_NO_EXCEPTION_ALL("var passed = false; \n"
  70. "function f() { passed = true; return 1; }\n"
  71. "if (f() !== 1) throw new Exception('failed');\n"
  72. // The passed !== true is needed as otherwise UBSAN
  73. // complains about unaligned access, until that
  74. // is fixed or ignored care must be taken to prevent such cases in tests.
  75. "if (passed !== true) throw new Exception('failed');");
  76. }
  77. TEST_CASE(generator_function_call)
  78. {
  79. EXPECT_NO_EXCEPTION_ALL("function *g() { yield 2; }\n"
  80. "var gen = g();\n"
  81. "var result = gen.next();\n"
  82. "if (result.value !== 2) throw new Exception('failed');");
  83. }
  84. TEST_CASE(loading_multiple_files)
  85. {
  86. // This is a testcase which is very much like test-js and test262
  87. // which load some common files first and only then the actual test file.
  88. SETUP_AND_PARSE("function f() { return 'hello'; }");
  89. {
  90. EXPECT_NO_EXCEPTION(common_file_executable);
  91. }
  92. {
  93. auto test_file_script_or_error = JS::Script::parse("if (f() !== 'hello') throw new Exception('failed'); ", ast_interpreter->realm());
  94. EXPECT(!test_file_script_or_error.is_error());
  95. auto test_file_script = test_file_script_or_error.release_value();
  96. auto const& test_file_program = test_file_script->parse_node();
  97. auto executable = JS::Bytecode::Generator::generate(test_file_program);
  98. auto result = bytecode_interpreter.run(executable);
  99. EXPECT(!result.is_error());
  100. EXPECT(!vm->exception());
  101. }
  102. }