Rust编写的JavaScript引擎,该项目是一个试验性质的项目。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
4.6 KiB

# Debugging
There are multiple ways to debug what Boa is doing. Or maybe you just want to
know how it works under the hood. Or even test some JavaScript.
One way to do so is to create a file in the root of the repository. For example
`test.js`. Then execute `cargo run -- test.js` to run the file with boa. You can
compile a list of JavaScript files by running `cargo run -- file1.js file2.js`
and so on.
You can also run boa interactively by simply calling `cargo run` without any
arguments to start a shell to execute JS.
These are added in order of how the code is read:
## Tokens and AST nodes
The first thing boa will do is to generate tokens from the source code.
These tokens are then parsed into an abstract syntax tree (AST).
Any syntax errors should be thrown while the AST is generated.
You can use the `boa_cli` command-line flag `--dump-ast` to print the AST.
The flag supports these formats: `Debug`, `Json`, `JsonPretty`. By default
it is the `Debug` format.
Dumping the AST of a file:
```bash
cargo run -- test.js --dump-ast # AST dump format is Debug by default.
```
or with interactive mode (REPL):
```bash
cargo run -- --dump-ast # AST dump format is Debug by default.
```
## Bytecode generation and Execution
Once the AST has been generated, boa will compile it into bytecode, which is then executed by the VM.
You can print the bytecode and the executed instructions with the command-line flag `--trace`.
For more detailed information about the VM and the trace output look [here](./vm.md).
Implement instruction flowgraph generator (#2422) This PR is a WIP implementation of a vm instruction flowgraph generator This aims to make the vm easier to debug and understand for both newcomers and experienced devs. For example if we have the following code: ```js let i = 0; while (i < 10) { if (i == 3) { break; } i++; } ``` It generates the following instructions (which is hard to read, especially jumps): <details> ``` ----------------------Compiled Output: '<main>'----------------------- Location Count Opcode Operands 000000 0000 PushZero 000001 0001 DefInitLet 0000: 'i' 000006 0002 LoopStart 000007 0003 LoopContinue 000008 0004 GetName 0000: 'i' 000013 0005 PushInt8 10 000015 0006 LessThan 000016 0007 JumpIfFalse 78 000021 0008 PushDeclarativeEnvironment 0, 1 000030 0009 GetName 0000: 'i' 000035 0010 PushInt8 3 000037 0011 Eq 000038 0012 JumpIfFalse 58 000043 0013 PushDeclarativeEnvironment 0, 0 000052 0014 Jump 78 000057 0015 PopEnvironment 000058 0016 GetName 0000: 'i' 000063 0017 IncPost 000064 0018 RotateRight 2 000066 0019 SetName 0000: 'i' 000071 0020 Pop 000072 0021 PopEnvironment 000073 0022 Jump 7 000078 0023 LoopEnd Literals: <empty> Bindings: 0000: i Functions: <empty> ``` </details> And the flow graph is generated: ![flowgraph](https://user-images.githubusercontent.com/8566042/200589387-40b36ad7-d2f2-4918-a3e4-5a8fa5eee89b.png) The beginning of the function is marked by the `start` node (in green) and end (in red). In branching the "yes" branch is marked in green and "no" in red. ~~This only generates in [graphviz format](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) (a widely used format) but it would be nice to also generate to a format that `mermaid.js` can understand and that could be put in articles https://github.com/boa-dev/boa-dev.github.io/issues/26~~ TODO: - [x] Generate graphviz format - [x] Generate mermaid format - [x] Programmatically generate colors push and pop env instructions - [x] Display nested functions in sub-sub-graphs. - [x] Put under a feature (`"flowgraph"`) - [x] Handle try/catch, switch instructions - [x] CLI option for configuring direction of flow (by default it is top down) - [x] Handle `Throw` instruction (requires keeping track of try blocks) - [x] Documentation - [x] Prevent node name collisions (functions with the same name)
2 years ago
## Instruction flowgraph
We can also get the VM instructions flowgraph, which is a visual representation of the instruction flow.
Implement instruction flowgraph generator (#2422) This PR is a WIP implementation of a vm instruction flowgraph generator This aims to make the vm easier to debug and understand for both newcomers and experienced devs. For example if we have the following code: ```js let i = 0; while (i < 10) { if (i == 3) { break; } i++; } ``` It generates the following instructions (which is hard to read, especially jumps): <details> ``` ----------------------Compiled Output: '<main>'----------------------- Location Count Opcode Operands 000000 0000 PushZero 000001 0001 DefInitLet 0000: 'i' 000006 0002 LoopStart 000007 0003 LoopContinue 000008 0004 GetName 0000: 'i' 000013 0005 PushInt8 10 000015 0006 LessThan 000016 0007 JumpIfFalse 78 000021 0008 PushDeclarativeEnvironment 0, 1 000030 0009 GetName 0000: 'i' 000035 0010 PushInt8 3 000037 0011 Eq 000038 0012 JumpIfFalse 58 000043 0013 PushDeclarativeEnvironment 0, 0 000052 0014 Jump 78 000057 0015 PopEnvironment 000058 0016 GetName 0000: 'i' 000063 0017 IncPost 000064 0018 RotateRight 2 000066 0019 SetName 0000: 'i' 000071 0020 Pop 000072 0021 PopEnvironment 000073 0022 Jump 7 000078 0023 LoopEnd Literals: <empty> Bindings: 0000: i Functions: <empty> ``` </details> And the flow graph is generated: ![flowgraph](https://user-images.githubusercontent.com/8566042/200589387-40b36ad7-d2f2-4918-a3e4-5a8fa5eee89b.png) The beginning of the function is marked by the `start` node (in green) and end (in red). In branching the "yes" branch is marked in green and "no" in red. ~~This only generates in [graphviz format](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) (a widely used format) but it would be nice to also generate to a format that `mermaid.js` can understand and that could be put in articles https://github.com/boa-dev/boa-dev.github.io/issues/26~~ TODO: - [x] Generate graphviz format - [x] Generate mermaid format - [x] Programmatically generate colors push and pop env instructions - [x] Display nested functions in sub-sub-graphs. - [x] Put under a feature (`"flowgraph"`) - [x] Handle try/catch, switch instructions - [x] CLI option for configuring direction of flow (by default it is top down) - [x] Handle `Throw` instruction (requires keeping track of try blocks) - [x] Documentation - [x] Prevent node name collisions (functions with the same name)
2 years ago
The `Start` (in green) and `End` (in red) node in the graph represents the start and end point of execution.
They are not instructions, just markers.
The conditional instructions are diamond shaped, with the `"YES"` branch in green and the `"NO"` branch in red.
The push and pop evironment pairs match colors and are connected by a dotted line.
You can use the `--flowgraph` (or `--flowgraph=mermaid` for [mermaid][mermaid] format) flag which outputs
[graphviz][graphviz] format by default, and pipe it to `dot` (from the `graphviz` package which is installed
on most linux distros by default) or use an online editor like: <https://dreampuf.github.io/GraphvizOnline> to
view the graph.
```bash
cargo run -- test.js --flowgraph | dot -Tpng > test.png
```
You can specify the `-Tsvg` to generate a `svg` instead of a `png` file.
![Graphviz flowgraph](./img/graphviz_flowgraph.svg)
Mermaid graphs can be displayed on github [natively without third-party programs][gihub-mermaid].
By using a `mermaid` block as seen below.
````
```mermaid
// graph contents here...
```
````
Additionaly you can specify the direction of "flow" by using the `--flowgraph-direction` cli option,
for example `--flowgraph-direction=left-to-right`, the default is `top-to-bottom`.
[mermaid]: https://mermaid-js.github.io/
[gihub-mermaid]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams
[graphviz]: https://graphviz.org/
Implement debug object for CLI (#2772) Currently some debugging stuff in JavaScript land is difficult to impossible, like triggering a GC collect, this is not impossible to do in JavaScript the way I triggered it was by creating a huge amount of object `for (let i = 0; i < 100000; ++i) { ({}) }` but this is cumbersome and not guaranteed to trigger a gc. This PR implements `--debug-object` flag that injects the `$boa` debug object in the context, the object is separated into modules currently `gc`, `function`, `object`. We can now do `$boa.gc.collect()`, which force triggers a GC collect. Or sometimes I wanted a trace (the current solution is great, you can trace stuff like `>>> 1 + 1` but that is also it's limitation), it traces everything, I sometimes have a scenario and just want to trace a single function in that scenario, that's why I added the `$boa.function.trace(func, this, ...args)` It only traces the function. ```js >> $boa.function.trace((a, b) => a + b, undefined, 1, 2) -------------------------Compiled Output: ''-------------------------- Location Count Opcode Operands 000000 0000 DefInitArg 0000: 'a' 000005 0001 DefInitArg 0001: 'b' 000010 0002 RestParameterPop 000011 0003 GetName 0000: 'a' 000016 0004 GetName 0001: 'b' 000021 0005 Add 000022 0006 Return 000023 0007 PushUndefined 000024 0008 Return ... (cut for brevity) ... ``` It also implements `$boa.function.flowgraph(func, options)`: ```js $boa.function.flowgraph(func, 'graphviz') $boa.function.flowgraph(func, { format: 'mermaid', direction: 'TopBottom' }) ``` Printing the object pointer: ```js $boa.object.id({}) // '0x566464F33' ``` It currently implements some functionality which we can grow it with our debugging needs since we are not restricted by a spec we can add whatever we want :) I was originally going to implement this in #2723 (but the PR is too big), for shapes having functions like: ```js $boa.shape.type({}) // Shared shape $boa.shape.id({}) // 0x8578FG355 (objects, shape pointer) $boa.shape.flowgraph({}) // printing the shape transition chain, like $boa.function.flowgraph ``` Shapes chains are very hard to debug once they are big... so having this type of debugging capability would make it much easier.
2 years ago
## Debugging through the debug object $boa
Certain debugging actions in JavaScript land are difficult to impossible, like triggering a GC collect.
For such puroposes we have the `$boa` object that contains useful utilities that can be used to debug JavaScript in JavaScript.
The debug object becomes available with the `--debug-object` cli flag, It injects the `$boa` debug object in the context as global variable,
the object is separated into modules `gc`, `function`, `object`, etc.
We can now do `$boa.gc.collect()`, which force triggers a GC collect.
If you want to trace only a particular function (without being flodded by the `--trace` flag, that traces everything),
for that we have the `$boa.function.trace(func, this, ...args)`.
The full documentation of the `$boa` object's modules and functionalities can be found [`here`](./boa_object.md).
## Compiler panics
In the case of a compiler panic, to get a full backtrace you will need to set
the environment variable `RUST_BACKTRACE=1`.
## Debugger
### VS Code Debugger
The quickest way to get debugging is to use the CodeLLDB plugin and add breakpoints. You can get
more information [here][blog_debugging].
### LLDB Manual debugging
You can also use rust-lldb. The `Dockerfile` already has this enabled, you
should be able to use that environment to run your code.
```
rust-lldb ./target/debug/boa [arguments]
```
[remote_containers]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
[blog_debugging]: https://jason-williams.co.uk/debugging-rust-in-vscode