Coder Social home page Coder Social logo

jint2's People

Contributors

pvginkel avatar

Watchers

 avatar  avatar

jint2's Issues

Optimize function calls

It may be possible to not have real function objects in certain circumstances:

  • When the function object is only used to call the function; and
  • No reference is taken of the function object (so no global functions); and
  • The number of arguments passed to the function is always less or equal to the number of arguments on the function.

In this case, don't create a function object; change the signature of the function to make it have real arguments and change calls from JsObject.Execute to a real call.

Redesign JsSchema

Currently, when a new schema is created, the existing one is copied to the new one. This is a relatively expensive operation because the whole hashset that is backing the schema needs to be copied.

An alternative would be to change JsSchema into a linked list. A JsSchema then becomes the tail with only the addition or removal (the transition really) is added in the new JsSchema.

The advantage of this scheme is that creating a new schema becomes very cheap. The disadvantage is that a cache miss (the DictionaryCacheSlot) becomes quite expensive. Do performance tests on the V8/Octane benchmarks to find out how many cache misses we normally have, what the impact of polymorphic/megamorphic call sites is.

Use native .NET values where possible

Currently, all values are still JsInstance values. This should be changed to native .NET values where possible.

There are two levels to this. Firstly, all variables (locals and lifted) should be typed object and start out as their native values. This means that e.g. a double becomes a boxed double. When an operation is performed on the variable that requires it to become a JsInstance (e.g. a property is set), the boxed double is silently converted to a JsInstance. This means that all operations that could have this effect on a variable should get ref references to the storage location.

The second level is more interesting and is where the real performance gains are. We could do a usage analysis on variables. When we can prove that no operations can be performed on the variable that would require it to become a JsInstance, and the variable keeps it original type all the way through its lifetime, the type of the variable could be its real native type. We may have to add some special support for its initial value, because all variables start out as undefined. This could be solved by making the variables Nullable<> and returning JsUndefined.Instance when the variable hasn't been assigned yet. This could also be optimized away when the variable is definitely assigned.

One thing that should be taken into account is that not all member operations require it to become a JsInstance. E.g. when we execute a method on a variable, this should still work on native variables. Normally, we would get the prototype of the JsInstance to find out how to resolve the method. When the variable is (still) a native value, we could hard code the prototype lookup and resolve members that way.

Where this gets more complicated is when variables are assigned to. If a variable is assigned a new time, and it's not lifted, we may create a new variable for this. The idea here is that when we can prove that the original value of the variable isn't read after the point it's assigned a value of a new type, we can just create a new variable for it (e.g. i`1) and give that a new type.

One thing to also take into account is that it may be a good idea to also allow int as a type for local variables, specifically for these circumstances. One of the major gains you'll see here is for optimizing a "for (var i = 0; i < arr.length; i++)", and that specifically is an int.

Remove the syntax tree

Currently we have two trees representing the source code: the syntax tree and the bound tree. This was done because it made migration to the IL backend easier, but isn't really necessary.

Remove the syntax tree and instead directly generate the bound tree from the grammar. This depends on #35.

Move proxies to IL

Proxies were moved to Expression trees a while ago, but since we've implemented an IL backend, the proxies should be moved too. After this change, the main assembly can be moved back to .NET 2.0.

Implement variable aliasing

Variable aliasing must be implemented to solve the following:

var i = 0;
i = '';

The type marker identifies the above variable as object because it's assigned values of different types. However, this is not necessary because the first assignment of i is never observed. Aliasing must be implemented to alias the second i to a new variable that can have its own native type.

Expand benchmarks

Jurassic and the original Jint project (and maybe others) must be added as benchmark engines.

Improve native types

Native types have been implemented through #4, but can still be improved. See #4 for more information.

Execute all Mozilla tests

Only a few of the Mozilla tests are executed. There are a lot of them and all of them should be executed.

Expand support for native types

Introduce integer as an alternative number type. This would allow for better optimizations if the type system can prove that a variable is only used as an integer.

Review FastHashSet

FastHashSet (the types that are generated from it) must be reviewed. It is currently correct and optimized for lookups, but inserts and removals can use a tweak.

Fix all test262 tests

All tests from test262 must run. See the Jint-Test262 project for the unit tests for this test suite.

Limit the amount of rewriting that needs to be done

Currently we introduce a lot of blocks and temporaries that later on are taken out again. See whether this can be optimized and whether we can prevent certain blocks/temporaries from being introduced in the first place.

Implement a dead code elimination phase

Implement a dead code elimination phase. This shouldn't be of much use. However, it currently creates issues with type assignment, e.g.:

var i = 0;
return i;
i = "";

The above sequence makes i Unknown. However, this is not required because the string will never be assigned.

Only create the arguments object when its referenced

The arguments object currently is always created. When it isn't referenced, two things must happen:

  • Arguments must be copied to locals and these must be used instead;
  • The arguments object must not be created.

Review emitted sequence points

Review the emitted sequence points. Some may be missing or not ideal, and currently a sequence point is emitted for whole functions, which makes debugging irritating.

Create locals for not-lifted variables

Currently, all variables are hoisted to a compiled scope. Variables that don't need to be lifted, don't have to be in a compiled scope. When making this change, also get rid of scopes without variables.

Correctly implement strict mode

Strict mode is not correctly implemented. Currently the engine takes options to specify whether it should work in EcmaScript5 mode and whether it must work in strict mode. EcmaScript5 must be enabled by default and strict mode must be applied when the program or function specifies the strict flag:

function f() {
    'use strict';
}

A side effect of the current implementation is that parsing scripts at the moment does not just depend on the source code of the script which prohibits caching of the compilation result.

Review all API implementations

Most of the API implementations are still inherited from the original Jint project, and a lot of performance can be gained there. E.g. the RegEx implementation is extremely slow (see e.g. the regexp-dns.js SunSpider test).

Fix tests that don't stop

There are a number of tests that don't stop; probably because they generate code that goes into an endless loop. These are marked with TODO comments and must be solved.

Clean up name usages

There are a lot of hard strings in the code and usage of strings and consts for certain names in inconsistent. All const strings should be declared in JsNames and comparison based on strings there should be limited.

Restructure unit tests

The unit tests can be restructured. One of the things that can be changed is that we can make use of test cases. A lot of the tests simply redirect to a specific JavaScript file to execute. This can be replaced by a TestCase attribute that specifies the script to execute.

Cache compilations

When a compilation is done on the same engine instance for the same source code, a cached compilation must be returned.

Consider not caching literal syntax trees

Currently, literal syntax trees are also cached. However, this probably isn't of much use and only introduces memory leaks. The thinking here is that when the tree is a literal, it is most likely an eval of a JSON expression, which most likely will never be re-used again. Caching of literal syntax trees should be disabled.

Create benchmarks

After completing the initial rewrite, create benchmarks against Jint, IronJS, Jurassic and IE8.

Implement delayed emit

Implement delayed emit. There are two major changes that fall under this:

  • JsDelegate must get a stub with a reference to the AST. This stub starts the emitter and replaces the delegate on the stub with the real thing and after it has emitted the code, redirect to that;
  • The marshaller takes a very long time to load. This must be delayed too. The whole thing should become a stub and only when something is required do we need to actually generate something. An optimization that we could also implement here is how mapping is done to CLR types. Currently, complete objects are created that have all the proxies there. This is very inefficient and most likely never needed. An alternative would be to do all of this late bound.

JQuery scripts don't parse

The JQuery scripts don't parse. jquery-1.2.6 on line 699 has an argument name which isn't identified as an argument. The problem is that certain constructs (catch, variable declaration and in this case, for in) declare a variable. However, this is too early and the arguments haven't yet been put into the declared variables collection. Solution is probably to move inserting the arguments into the declared variables collection earlier.

Also check whether a for in actually implies a variable declaration. Currently, besides variable declaration, catch and for in imply a variable declaration. Check whether this is correct.

ToPropertyDescriptor should be wrong

Previously, there was a test in ToPropertyDescriptor that only defined a setter, and PropertyAccessor fails when no setter is provided. Check what's going on here.

Remove JsScope

It looks like the entire JsScope system can be removed and replaced with compiled scopes. The only exception may be the global scope, because that's used to pass parameters from JintEngine to the application. This however can also be replaced by a different mechanism which is only used to communicate the values from JintEngine to the program and back.

Note that we don't create native variables for parameters that we pass from JintEngine. The reason for this is in the current implementation, we can cache the compilation based only on the compiled text. This means that we will always need an interpreted mechanism for JintEngine parameters.

With this change, the scope stack must also be removed (so also EnterScope, ExitScope and GetScope). This will be replaced by hard linking of the scopes. A scope will get a parent scope field which is used to link scopes upwards. At the beginning of the function, this list will be walked to create local variables that reference all scopes that are used. The last step is to give a hard reference to the current scope to the JsFunction. That way we can completely get rid of the stack and only work with direct references, all strongly typed.

Implement variable type speculation

Variable type speculation must be implemented. We have a type marker phase that determines the hard type of a variable. This is the type the variable must have for the IL to compile. However, through type speculation, we can guess the real type and optimize for that.

E.g., in the following case, the speculator would identify i as being a dictionary object:

var i = f();
i['a'] = 7;
var j = i.a;

The idea here is that operations that you normally perform on a dictionary object are performed on i. In the following example, i will be identified as an array object:

var i = f();
i[0] = 7;
var j = i[0];

When a variable is identified as being e.g. a dictionary object, the variable is replaced with a speculated variable type, with a signature like:

struct DictionaryObjectVariable
{
    public JsObject Value { get; set; }
    public DictionaryPropertyStore PropertyStore { get; set; }
}

This struct can now get methods that optimize on the value being a dictionary object. Instead of having everything go through JsObject, of the type matches, operations are performed directly on the dictionary property store.

Implement support for TypeDescriptor

Currently the only way Jint can interact with .NET types is through the runtime Type system. This should be extended to also support TypeDescriptor.

Implement support for string builders

A special string type must be introduced that is optimized for concatenation. The idea here is that the following should automatically be optimized:

var result = '';
for (var i = 0; i < 1000; i++)
{
  result += i;
}

A way to implement this (the way IronJS does it) is to have an alternative string type. When a concatenation is detected, the new string that is produced isn't a string anymore but instead becomes an object that is prepared for concatenation. The primary impact here is that the current runtime system expects a value to be represented by a single native type. This change would introduce a second native type for string which will complicate things.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.