Repository navigation
JavaScript Engine
op_js is OPBrowser's original ECMAScript implementation. It does not embed V8,
SpiderMonkey, JavaScriptCore, QuickJS or another JavaScript engine.
The executable core contains an owned lexer, AST parser, bytecode compiler and stack
interpreter. The current language subset covers scalar literals, let/const/var
declarations including comma-separated declarators, identifier load/assignment, unary
+/-/!, prefix/postfix ++/--, arithmetic, comparisons, loose/strict equality,
string concatenation, short-circuit &&/||, blocks, if/else, while, C-style for,
do/while, switch fallthrough, break and continue.
It also supports object and array literals, shorthand data properties, dot/computed member access,
member assignment, sparse array slots, dynamic index-driven array length growth and reference
identity through runtime-owned ObjectId handles.
Control flow compiles to patched bytecode jumps and the VM runs with an explicit instruction pointer. Every execution has an instruction budget, plus bounded object/environment allocation and call depth, so runaway loops/recursion terminate instead of monopolizing the renderer thread. Bindings live in an environment arena: scripts use the global environment, calls create function environments, blocks create lexical environments, let/const stay block-scoped and var targets the nearest function/global environment.
Objects live in a bounded runtime heap instead of being copied inside JsValue. Ordinary object
lookups walk an explicit prototype chain; object-literal __proto__ setters and later
__proto__ assignments can change that chain while cycle creation is rejected. Arrays currently
reuse the same property store with indexed keys and an own length property. String .length
uses UTF-16 code units.
Functions are heap objects backed by owned bytecode templates. Function declarations and
expressions accept positional parameters, return values, recurse and expose initial name and
length properties. Each function captures its creation environment, so closures can read and
mutate bindings after their defining function or block has exited; named function expressions get
a private recursive self-binding. Direct function declarations are instantiated before the other
statements in their compiled statement list, providing initial declaration hoisting.
Explicit thrown values use a distinct abrupt-completion path and can cross function calls into
catch. try/catch/finally preserves or overrides return/throw/break/continue according to the
finalizer completion, including break/continue that leave the try region and resume an outer
loop/switch. Runtime-generated Reference/Type failures are still engine errors rather than
catchable JavaScript Error objects.
Method calls now preserve their receiver, bare non-strict calls receive the runtime global object
as this, and every user function receives an array-like arguments object. User functions own
a prototype object with a constructor backlink; new allocates from constructor.prototype,
binds the new receiver as this, and honors object-return versus primitive-return constructor
rules. Error, TypeError and ReferenceError are initial built-in constructors with
prototype chains, name/message properties and catchable objects. Runtime Type/Reference failures
inside try regions are converted to those JavaScript objects; execution-limit failures deliberately
remain engine-level guards.
This is still not page scripting. Arrow/default/rest/destructuring forms, labels, for-in/of,
property descriptors/accessors, full array-length mutation rules, primitive boxing/ToPrimitive,
garbage collection, broad standard built-ins, promises/modules and DOM bindings are still absent.
C-style for(let ...) has one loop lexical environment rather than fresh per-iteration bindings,
and ASI/line-terminator restrictions around throw/postfix updates are still incomplete. Function
calls currently recurse through the native stack; the temporary depth limit is 64 until calls move
to explicit VM frames.
op_js includes test262_probe. It measures only whether the current parser accepts
positive parse tests and rejects Test262 tests whose frontmatter explicitly expects a parse
error. It intentionally does not report those results as runtime conformance.
Example:
cargo run -p op_js --bin test262_probe -- C:\src\test262\test --limit 2000For the combined local subsystem check use:
.\tools\compatibility.ps1 -Test262Path C:\src\test262\test -Test262Limit 2000The unchanged Test262 Parser v1 subset moved from 364/1983 (18.36%) to 391/1983 (19.72%), then 408/1983 (20.57%), 504/1983 (25.42%) after functions/closures, 508/1983 (25.62%) after broader control flow, updates and exceptions, and 523/1983 (26.37%) after this/new constructor parsing. This remains a parse-expectation metric, not runtime conformance.
The next JS work is modern function/parameter syntax, labels/for-in/of, per-iteration lexical bindings, broader built-ins/property semantics and explicit VM call frames. In parallel, M4 can now start consuming the VM through a narrow DOM binding boundary because ordinary receiver calls, constructors, arguments and catchable runtime errors exist; page scripting still must not be advertised as compatible until that binding/event-loop work lands.
Проект
Архитектура
Реализация
- CSS Syntax
- CSS Box Model
- Inline Layout
- Stylesheets
- Images
- Source Loading
- HTML Encoding
- Reflow
- Navigation
- JavaScript VM
- Request Filtering
Тесты и разработка