diff --git a/02.how-to.md b/02.how-to.md new file mode 100644 index 000000000..9c5c290bb --- /dev/null +++ b/02.how-to.md @@ -0,0 +1,97 @@ +--- +layout: page +title: How To +permalink: /how-to/ +--- + +# How to Get the Sources +This step should be simple: + +{% highlight bash %} +git clone https://github.com/Samsung/jerryscript.git +cd jerryscript +{% endhighlight %} + +# How to Setup Recommended Prerequisites + +Currently, we are using Ubuntu Linux 14.04+ as our development environment, so this tutorial was written based on this assumption. Additionaly, it'd be useful to read [Prerequisites]({{ site.baseurl }}/wiki/Prerequisites) wiki page, also. + +There are dependencies, that should be installed manually. The following list is required for building: + +- `gcc` or `g++` higher than `4.8.2` + - native + - arm-none-eabi +- `cmake` higher than `2.8.12.2` +- `make` higher than `3.81` +- `bash` higher than `4.3.11` + +These tools are required for development: + +- `cppcheck` requires `libpcre` +- `vera++` requires `tcl`, `tk` and `boost` + +{% highlight bash %} +sudo apt-get install gcc g++ +sudo apt-get install gcc-arm-none-eabi g++-arm-none-eabi +sudo apt-get install cmake +sudo apt-get install libpcre3 libpcre3-dev +sudo apt-get install tcl8.6 tcl8.6-dev tk8.6-dev libboost-all-dev +{% endhighlight %} + +To make our scripts run correctly, several shell utilities should be available the system: + +- `find` +- `bc` +- `awk` +- `sed` +- `sha256sum` +- `wget` + +# How to Build + +After setting up prerequisites, let's built the engine: + +{% highlight bash %} +make +{% endhighlight %} + +Upon first build, `make` would try to setup prerequisites, required for further development and pre-commit testing: +- stm32f3 and stm32f4 libraries +- nuttx's headers +- cppcheck 1.66 +- vera++ 1.2.1 + +It may take time, so go grab some coffee: + +{% highlight bash %} +Setting up prerequisites... (log file: ./build/prerequisites/prerequisites.log) +{% endhighlight %} + +## How to Build Debug Version +To build debug version for Linux: + +{% highlight bash %} +make debug.linux +{% endhighlight %} + +To build debug version for Linux without LTO (Link Time Optimization): + +{% highlight bash %} +LTO=off make debug.linux +{% endhighlight %} + +# How to Run Unittests +{% highlight bash %} +make unittests +{% endhighlight %} + +# How to Check the Patch +{% highlight bash %} +make precommit -j +{% endhighlight %} + +Sometimes pre-commit testing fails, in that case you'll see message like that: + +{% highlight bash %} +Build failed. See ./build/bin/unittests/make.log for details. +{% endhighlight %} diff --git a/03.api.md b/03.api.md new file mode 100644 index 000000000..0e7a73670 --- /dev/null +++ b/03.api.md @@ -0,0 +1,1102 @@ +--- +layout: page +title: API +permalink: /API/ +--- + +* toc +{:toc} + +# jerry_run_simple + +**Summary** +The simplest way to run JavaScript. + +**Prototype** + +{% highlight cpp %} +jerry_completion_code_t +jerry_run_simple (const char * script_source, + size_t script_source_size, + jerry_flag_t flags); +{% endhighlight %} + +- `script_source` - source code; +- `script_source_size` - size of source code buffer, in bytes; +- returned value - completion code that indicates whether run performed successfully (`JERRY_COMPLETION_CODE_OK`), or an unhandled JavaScript exception occurred (`JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION`). + + +**See also** + +- [jerry_init](#jerryinit) +- [jerry_cleanup](#jerrycleanup) +- [jerry_parse](#jerryparse) +- [jerry_run](#jerryrun) + +**Example** + +{% highlight cpp linenos=table %} +{ + const char * script = "print ('Hello, World!');"; + + jerry_run_simple (script, strlen (script), JERRY_FLAG_EMPTY); +} +{% endhighlight %} + +# jerry_init + +**Summary** + +Initializes JerryScript engine, making possible to run JavaScript code and perform operations on JavaScript values. + +**Prototype** + +{% highlight cpp %} +void +jerry_init (jerry_flag_t flags); +{% endhighlight %} + +`flags` - combination of various engine configuration flags: + +- `JERRY_FLAG_MEM_STATS` - dump memory statistics; +- `JERRY_FLAG_ENABLE_LOG` - enable logging; +- `JERRY_FLAG_SHOW_OPCODES` - print compiled byte-code; +- `JERRY_FLAG_EMPTY` - no flags, just initialize in default configuration. + +**See also** + +- [jerry_cleanup](#jerrycleanup) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_init (JERRY_FLAG_ENABLE_LOG); + + // ... + + jerry_cleanup (); +} +{% endhighlight %} + +# jerry_cleanup + +**Summary** + +Finish JavaScript engine execution, freeing memory and JavaScript values. + +JavaScript values, received from engine, are inaccessible after the cleanup. + +**Prototype** + +{% highlight cpp %} +void +jerry_cleanup (void); +{% endhighlight %} + +**See also** + +- [jerry_init](#jerryinit) + +# jerry_parse + +**Summary** +Parse specified script to execute in Global scope. + +Current API doesn't permit replacement or modification of Global scope's code without engine restart, +so `jerry_parse` could be invoked only once between `jerry_init` and `jerry_cleanup`. + +**Prototype** + +{% highlight cpp %} +bool +jerry_parse (const char* source_p, size_t source_size); +{% endhighlight %} +- `source_p` - string, containing source code to parse; +- `source_size` - size of the string, in bytes. + +**See also** + +- [jerry_run](#jerryrun) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_init (JERRY_FLAG_ENABLE_LOG); + + char script [] = "print ('Hello, World!');"; + jerry_parse (script, strlen (script)); + + jerry_run (); + + jerry_cleanup (); +} +{% endhighlight %} + +# jerry_run + +**Summary** +Run code of Global scope. + +The code should be previously registered through `jerry_parse`. + +**Prototype** + +{% highlight cpp %} +jerry_completion_code_t +jerry_run (void); +{% endhighlight %} + +- returned value - completion code that indicates whether run performed successfully (`JERRY_COMPLETION_CODE_OK`), or an unhandled JavaScript exception occurred (`JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION`). + +**See also** + +- [jerry_parse](#jerryparse) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_init (JERRY_FLAG_ENABLE_LOG); + + char script [] = "print ('Hello, World!');"; + jerry_parse (script, strlen (script)); + + jerry_run (); + + jerry_cleanup (); +} +{% endhighlight %} + +# jerry_api_value_t + +**Summary** +The data type represents any JavaScript value that can be sent to / received from the engine. + +Type of value is identified by `jerry_api_value_t::type`, and can be one of the following: + +- `JERRY_API_DATA_TYPE_UNDEFINED` - JavaScript undefined; +- `JERRY_API_DATA_TYPE_NULL` - JavaScript null; +- `JERRY_API_DATA_TYPE_BOOLEAN` - boolean; +- `JERRY_API_DATA_TYPE_FLOAT64` - number; +- `JERRY_API_DATA_TYPE_STRING` - string; +- `JERRY_API_DATA_TYPE_OBJECT` - reference to JavaScript object. + +**Structure** + +{% highlight cpp %} +typedef struct jerry_api_value_t +{ + jerry_api_data_type_t type; + + union + { + bool v_bool; + + float v_float32; + double v_float64; + + uint32_t v_uint32; + + union + { + jerry_api_string_t * v_string; + jerry_api_object_t * v_object; + }; + }; +} jerry_api_value_t; +{% endhighlight %} + +**See also** + +- [jerry_api_eval](#jerryapieval) +- [jerry_api_call_function](#jerryapicallfunction) +- [jerry_api_construct_object](#jerryapiconstructobject) + + +# jerry_api_eval + +**Summary** +Perform JavaScript `eval`. + +**Prototype** + +{% highlight cpp %} +jerry_completion_code_t +jerry_api_eval (const char * source_p, + size_t source_size, + bool is_direct, + bool is_strict, + jerry_api_value_t * retval_p); +{% endhighlight %} + +- `source_p` - source code to evaluate; +- `source_size` - length of the source code; +- `is_direct` - whether to perform `eval` in "direct" mode (possible only if `eval` invocation is performed from native function, called from JavaScript); +- `is_strict` - perform `eval` as it is called from "strict mode" code; +- `retval_p` - value, returned by `eval` (output parameter); +- returned value - completion code that indicates whether run performed successfully (`JERRY_COMPLETION_CODE_OK`), or an unhandled JavaScript exception occurred (`JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION`). + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_external_function](#jerryapicreateexternalfunction) +- [jerry_external_handler_t](#jerryexternalhandlert) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_value_t ret_val; + + jerry_completion_code_t status = jerry_api_eval (str_to_eval, + strlen (str_to_eval), + false, false, + &ret_val); +} +{% endhighlight %} + +# jerry_api_create_string + +**Summary** +Create new JavaScript string. + +Upon the JavaScript string becomes unused, all pointers to it should be released using [jerry_api_release_string](#jerryapireleasestring). + +**Prototype** + +{% highlight cpp %} +jerry_api_string_t* +jerry_api_create_string (const char * v); +{% endhighlight %} + +- `v` - value of string to create; +- returned value is pointer to created string. + +**See also** + +- [jerry_api_acquire_string](#jerryapiacquirestring) +- [jerry_api_release_string](#jerryapireleasestring) +- [jerry_api_string_to_char_buffer](#jerryapistringtocharbuffer) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_string_t * string_p = jerry_api_create_string ("abc"); + + ... + + jerry_api_release_string (string_p); +} +{% endhighlight %} + +# jerry_api_string_to_char_buffer + +**Summary** +Copy string characters to specified buffer, append zero character at end of the buffer. + +**Prototype** + +{% highlight cpp %} +ssize_t +jerry_api_string_to_char_buffer (const jerry_api_string_t * string_p, + char * buffer_p, + ssize_t buffer_size); +{% endhighlight %} + +- `string_p` - pointer to a string; +- `buffer_p` - pointer to output buffer (can be NULL, is `buffer_size` is 0); +- `buffer_size` - size of the buffer; +- returned value: + - number of bytes, actually copied to the buffer - if characters were copied successfully; + - otherwise (in case size of buffer is insuficcient) - negative number, which is calculated as negation of buffer size, that is required to hold characters. + +**See also** + +- [jerry_api_create_string](#jerryapicreatestring) +- [jerry_api_value_t](#jerryapivaluet) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * obj_p = jerry_api_get_global (); + jerry_api_value_t val; + + bool is_ok = jerry_api_get_object_field_value (obj_p, + "field_with_string_value", + &val); + + if (is_ok) { + bool is_string = (val.type == JERRY_API_DATA_TYPE_STRING); + + if (is_string) { + // neg_req_sz would be negative, as zero-size buffer is insufficient for any string + ssize_t neg_req_sz = jerry_api_string_to_char_buffer (val.string_p, + NULL, + 0); + char * str_buf_p = (char*) malloc (-neg_req_sz); + + // sz would be -neg_req_sz + size_t sz = jerry_api_string_to_char_buffer (val.string_p, + str_buf_p, + -neg_req_sz); + + printf ("%s", str_buf_p); + + free (str_buf_p); + } + + jerry_api_release_value (&val); + } + + jerry_api_release_object (obj_p); +} +{% endhighlight %} + +# jerry_api_acquire_string + +**Summary** +Acquire new pointer to the string for usage outside of the engine. + +The acquired pointer should be released with [jerry_api_release_string](#jerryapireleasestring). + +**Prototype** + +{% highlight cpp %} +jerry_api_string_t* +jerry_api_acquire_string (jerry_api_string_t * string_p); +{% endhighlight %} + +- `string_p` - pointer to the string; +- returned value - new pointer to the string. + +**See also** + +- [jerry_api_release_string](#jerryapireleasestring) +- [jerry_api_create_string](#jerryapicreatestring) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_string_t * str_ptr1_p = jerry_api_create_string ("abc"); + jerry_api_string_t * str_ptr2_p = jerry_api_acquire_string (str_ptr1_p); + + ... // usage of both pointers + + jerry_api_release_string (str_ptr1_p); + + ... // usage of str_ptr2_p pointer + + jerry_api_release_string (str_ptr2_p); +} +{% endhighlight %} + +# jerry_api_release_string + +**Summary** +Release specified pointer to the string. + +**Prototype** + +{% highlight cpp %} +void +jerry_api_release_string (jerry_api_string_t * string_p); +{% endhighlight %} + +- `string_p` - pointer to the string. + +**See also** + +- [jerry_api_acquire_string](#jerryapiacquirestring) +- [jerry_api_create_string](#jerryapicreatestring) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_string_t * str_ptr1_p = jerry_api_create_string ("abc"); + jerry_api_string_t * str_ptr2_p = jerry_api_acquire_string (str_ptr1_p); + + ... // usage of both pointers + + jerry_api_release_string (str_ptr1_p); + + ... // usage of str_ptr2_p pointer + + jerry_api_release_string (str_ptr2_p); +} +{% endhighlight %} + +# jerry_api_create_object + +**Summary** +Create new JavaScript object, like with `new Object()`. + +Upon the JavaScript object becomes unused, all pointers to it should be released using [jerry_api_release_object](#jerryapireleaseobject). + +**Prototype** + +{% highlight cpp %} +jerry_api_object_t* +jerry_api_create_object (const char * v); +{% endhighlight %} + +- `v` - value of object to create; +- returned value is pointer to created object. + + +**See also** + +- [jerry_api_acquire_object](#jerryapiacquireobject) +- [jerry_api_release_object](#jerryapireleaseobject) +- [jerry_api_add_object_field](#jerryapiaddobjectfield) +- [jerry_api_delete_object_field](#jerryapideleteobjectfield) +- [jerry_api_get_object_field_value](#jerryapigetobjectfieldvalue) +- [jerry_api_set_object_field_value](#jerryapisetobjectfieldvalue) +- [jerry_api_get_object_native_handle](#jerryapigetobjectnativehandle) +- [jerry_api_set_object_native_handle](#jerryapisetobjectnativehandle) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * object_p = jerry_api_create_object ("abc"); + + ... + + jerry_api_release_object (object_p); +} +{% endhighlight %} + +# jerry_api_acquire_object + +**Summary** +Acquire new pointer to the object for usage outside of the engine. + +The acquired pointer should be released with [jerry_api_release_object](#jerryapireleaseobject). + +**Prototype** + +{% highlight cpp %} +jerry_api_object_t* +jerry_api_acquire_object (jerry_api_object_t * object_p); +{% endhighlight %} + +- `object_p` - pointer to the object; +- returned value - new pointer to the object. + +**See also** + +- [jerry_api_release_object](#jerryapireleaseobject) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * obj_ptr1_p = jerry_api_create_object ("abc"); + jerry_api_object_t * obj_ptr2_p = jerry_api_acquire_object (obj_ptr1_p); + + ... // usage of both pointers + + jerry_api_release_object (obj_ptr1_p); + + ... // usage of obj_ptr2_p pointer + + jerry_api_release_object (obj_ptr2_p); +} +{% endhighlight %} + +# jerry_api_release_object + +**Summary** +Release specified pointer to the object. + +**Prototype** + +{% highlight cpp %} +void +jerry_api_release_object (jerry_api_object_t * object_p); +{% endhighlight %} + +- `object_p` - pointer to the object. + +**See also** + +- [jerry_api_acquire_object](#jerryapiacquireobject) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * obj_ptr1_p = jerry_api_create_object ("abc"); + jerry_api_object_t * obj_ptr2_p = jerry_api_acquire_object (obj_ptr1_p); + + ... // usage of both pointers + + jerry_api_release_object (obj_ptr1_p); + + ... // usage of obj_ptr2_p pointer + + jerry_api_release_object (obj_ptr2_p); +} +{% endhighlight %} + +# jerry_api_get_global + +**Summary** +Get the Global object. + +**Prototype** + +{% highlight cpp %} +jerry_api_object_t* +jerry_api_get_global (void); +{% endhighlight %} + +- returned value - pointer to the Global object. + +Received pointer should be released with [jerry_api_release_object](#jerryapireleaseobject), just when the value becomes unnecessary. + +**See also** + +- [jerry_api_release_object](#jerryapireleaseobject) +- [jerry_api_add_object_field](#jerryapiaddobjectfield) +- [jerry_api_delete_object_field](#jerryapideleteobjectfield) +- [jerry_api_get_object_field_value](#jerryapigetobjectfieldvalue) +- [jerry_api_set_object_field_value](#jerryapisetobjectfieldvalue) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * glob_obj_p = jerry_api_get_global (); + + jerry_api_value_t val; + bool is_ok = jerry_api_get_object_field_value (glob_obj_p, "some_field_name", &val); + if (is_ok) + { + ... // usage of 'val' + + jerry_api_release_value (&val); + } + + jerry_api_release_object (glob_obj_p); +} +{% endhighlight %} + +# jerry_api_add_object_field + +**Summary** +Create field (named data property) in an object + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_add_object_field (jerry_api_object_t * object_p, + const char * field_name_p, + const jerry_api_value_t * field_value_p, + bool is_writable); +{% endhighlight %} + +- `object_p` - object to add field at; +- `field_name_p` - name of the field; +- `field_value_p` - value of the field; +- `is_writable` - flag indicating whether the created field should be writable. +- returned value - true, if field was created successfully, i.e. upon the call: + - there is no field with same name in the object; + - the object is extensible. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t * obj_p = jerry_api_create_object (); + + jerry_api_value_t val; + + ... // initialize val + + // Make new constant field + jerry_api_add_object_field (obj_p, "some_field_name", &val, false); +} +{% endhighlight %} + +# jerry_api_delete_object_field + +**Summary** +Delete field (property) in the specified object + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_delete_object_field (jerry_api_object_t * object_p, + const char * field_name_p); +{% endhighlight %} + +- `object_p` - object to delete field at; +- `field_name_p` - name of the field. +- returned value - true, if field was deleted successfully, i.e. upon the call: + - there is field with specified name in the object. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t* obj_p; + ... // receive or construct obj_p + + jerry_api_delete_object_field (obj_p, "some_field_name"); +} +{% endhighlight %} + +# jerry_api_get_object_field_value + +**Summary** +Get value of field (property) in the specified object, i.e. perform [[Get]] operation. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_get_object_field_value (jerry_api_object_t * object_p, + const char * field_name_p, + jerry_api_value_t * field_value_p); +{% endhighlight %} + +- `object_p` - object; +- `field_name_p` - name of the field; +- `field_value_p` - retrieved field value (output parameter). +- returned value - true, if field value was retrieved successfully, i.e. upon the call: + - there is field with specified name in the object. + +If value was retrieved successfully, it should be freed with [jerry_api_release_object](#jerryapireleaseobject) just when it becomes unnecessary. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t* obj_p; + ... // receive or construct obj_p + + jerry_api_value_t val; + bool is_ok = jerry_api_get_object_field_value (obj_p, "some_field_name", &val); + if (is_ok) + { + ... // usage of 'val' + + jerry_api_release_value (&val); + } +} +{% endhighlight %} + +# jerry_api_set_object_field_value + +**Summary** +Set value of a field (property) in the specified object, i.e. perform [[Put]] operation. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_set_object_field_value (jerry_api_object_t * object_p, + const char * field_name_p, + jerry_api_value_t * field_value_p); +{% endhighlight %} + +- `object_p` - object; +- `field_name_p` - name of the field; +- `field_value_p` - field value to set. +- returned value - true, if field value was set successfully, i.e. upon the call: + - field value is writable. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_object](#jerryapicreateobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t* obj_p; + jerry_api_value_t val; + + ... // receive or construct obj_p and val + + bool is_ok = jerry_api_set_object_field_value (obj_p, "some_field_name", &val); +} +{% endhighlight %} + +# jerry_api_get_object_native_handle + +**Summary** + +Get native handle, previously associated with specified object. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_get_object_native_handle (jerry_api_object_t * object_p, + uintptr_t* out_handle_p); +{% endhighlight %} + +- `object_p` - object to get handle from; +- `out_handle_p` - handle value (output parameter); +- returned value - true, if there is handle associated with the object. + +**See also** + +- [jerry_api_create_object](#jerryapicreateobject) +- [jerry_api_set_object_native_handle](#jerryapisetobjectnativehandle) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t* obj_p; + uintptr_t handle_set; + + ... // receive or construct obj_p and handle_set value + + jerry_api_set_object_native_handle (obj_p, handle_set, NULL); + + ... + + uintptr_t handle_get; + bool is_there_associated_handle = jerry_api_get_object_native_handle (obj_p, + &handle_get); +} +{% endhighlight %} + +# jerry_api_set_object_native_handle + +**Summary** + +Set native handle and, optionally, "free" callback for the specified object. + +If native handle or "free" callback were already set for the object, corresponding value is updated. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_set_object_native_handle (jerry_api_object_t * object_p, + uintptr_t handle, + jerry_object_free_callback_t freecb_p); +{% endhighlight %} + +- `object_p` - object to set handle in; +- `handle` - handle value; +- `freecb_p` - pointer to "free" callback or NULL (if not NULL the callback would be called upon GC of the object). + +**See also** + +- [jerry_api_create_object](#jerryapicreateobject) +- [jerry_api_get_object_native_handle](#jerryapigetobjectnativehandle) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_object_t* obj_p; + uintptr_t handle_set; + + ... // receive or construct obj_p and handle_set value + + jerry_api_set_object_native_handle (obj_p, handle_set, NULL); + + ... + + uintptr_t handle_get; + bool is_there_associated_handle = jerry_api_get_object_native_handle (obj_p, + &handle_get); +} +{% endhighlight %} + +# jerry_api_is_function + +**Summary** +Check whether the specified object is a function object. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_is_function (const jerry_api_object_t* object_p); +{% endhighlight %} + +- `object_p` - object to check; +- returned value - just boolean, indicating whether the specified object can be called as function. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_is_constructor](#jerryapiisconstructor) +- [jerry_api_call_function](#jerryapicallfunction) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_value_t val; + + ... // receiving val + + if (val.type == JERRY_API_DATA_TYPE_OBJECT) { + if (jerry_api_is_function (val.v_object)) { + // the object is function object + } + } +} +{% endhighlight %} + +# jerry_api_is_constructor + +**Summary** +Check whether the specified object is a constructor function object. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_is_constructor (const jerry_api_object_t* object_p); +{% endhighlight %} + +- `object_p` - object to check; +- returned value - just boolean, indicating whether the specified object can be called as constructor. + +**See also** + +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_is_function](#jerryapiisfunction) +- [jerry_api_construct_object](#jerryapiconstructobject) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_value_t val; + + ... // receiving val + + if (val.type == JERRY_API_DATA_TYPE_OBJECT) { + if (jerry_api_is_constructor (val.v_object)) { + // the object is constructor function object + } + } +} +{% endhighlight %} + +# jerry_api_call_function + +**Summary** +Call function object. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_call_function (jerry_api_object_t * function_object_p, + jerry_api_object_t * this_arg_p, + jerry_api_value_t * retval_p, + const jerry_api_value_t args_p[], + uint16_t args_count); +{% endhighlight %} + +- `function_object_p` - the function object to call; +- `this_arg_p` - object to use as 'this' during the invocation, or NULL - to set the Global object as 'this'; +- `retval_p` - function's return value (output parameter); +- `args_p`, `args_count` - array of arguments and number of them; +- returned value - true, if call was performed successfully, i.e.: + - specified object is a function object (see also jerry_api_is_function); + - no unhandled exceptions were thrown in connection with the call. + + If call was performed successfully, returned value should be freed with [jerry_api_release_object](#jerryapireleaseobject) just when it becomes unnecessary. + +**See also** + +- [jerry_api_is_function](#jerryapiisfunction) +- [jerry_api_value_t](#jerryapivaluet) +- [jerry_api_create_external_function](#jerryapicreateexternalfunction) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_value_t val; + + ... // receiving val + + if (val.type == JERRY_API_DATA_TYPE_OBJECT) { + if (jerry_api_is_function (val.v_object)) { + jerry_api_value_t ret_val; + + bool is_ok = jerry_api_call_function (val.v_object, + NULL, + &ret_val, + NULL, 0); + + if (is_ok) { + ... // handle return value + + jerry_api_release_value (&ret_val); + } + } + } +} +{% endhighlight %} + +# jerry_api_construct_object + +**Summary** +Construct object invoking specified function object as constructor. + +**Prototype** + +{% highlight cpp %} +bool +jerry_api_construct_object (jerry_api_object_t * function_object_p, + jerry_api_value_t * retval_p, + const jerry_api_value_t args_p[], + uint16_t args_count); +{% endhighlight %} + +- `function_object_p` - the function object to invoke; +- `retval_p` - return value of function invoked as constructor, i.e. like with 'new' operator (output parameter); +- `args_p`, `args_count` - array of arguments and number of them; +- returned value - true, if call was performed successfully, i.e.: + - specified object is a constructor function object; + - no unhandled exceptions were thrown in connection with the call. + +If call was performed successfully, returned value should be freed with [jerry_api_release_object](#jerryapireleaseobject) just when it becomes unnecessary. + +**See also** + + - [jerry_api_is_constructor](#jerryapiisconstructor) + - [jerry_api_value_t](#jerryapivaluet) + +**Example** + +{% highlight cpp linenos=table %} +{ + jerry_api_value_t val; + + ... // receiving val + + if (val.type == JERRY_API_DATA_TYPE_OBJECT) { + if (jerry_api_is_constructor (val.v_object)) { + jerry_api_value_t ret_val; + + bool is_ok = jerry_api_construct_object (val.v_object, + &ret_val, + NULL, 0); + + if (is_ok) { + ... // handle return value + + jerry_api_release_value (&ret_val); + } + } + } +} +{% endhighlight %} + +# jerry_external_handler_t + +**Summary** + +The data type represents pointer to call handler of a native function object. + +**Structure** + +{% highlight cpp %} +typedef bool (* jerry_external_handler_t) (const jerry_api_object_t * function_obj_p, + const jerry_api_value_t * this_p, + jerry_api_value_t * ret_val_p, + const jerry_api_value_t args_p[], + const uint16_t args_count); +{% endhighlight %} + +**See also** + +- [jerry_api_create_external_function](#jerryapicreateexternalfunction) + +# jerry_api_create_external_function + +**Summary** +Create an external function object. + +**Prototype** + +{% highlight cpp %} +jerry_api_object_t* +jerry_api_create_external_function (jerry_external_handler_t handler_p); +{% endhighlight %} + +- `handler_p` - pointer to native handler of the function object; +- returned value - pointer to constructed external function object. + +Received pointer should be released with [jerry_api_release_object](#jerryapireleaseobject), just when the value becomes unnecessary. + +**See also** + +- [jerry_external_handler_t](#jerryexternalhandlert) +- [jerry_api_is_function](#jerryapiisfunction) +- [jerry_api_call_function](#jerryapicallfunction) +- [jerry_api_release_object](#jerryapireleaseobject) + +**Example** + +{% highlight cpp linenos=table %} +static bool +handler (const jerry_api_object_t * function_obj_p, + const jerry_api_value_t * this_p, + jerry_api_value_t * ret_val_p, + const jerry_api_value_t args_p[], + const uint16_t args_cnt) +{ + printf ("native handler called!\n"); + + ret_val_p->type = JERRY_API_DATA_TYPE_BOOLEAN; + ret_val_p->v_bool = true; +} + +{ + jerry_api_object_t * obj_p = jerry_api_create_external_function (handler); + jerry_api_object_t * glob_obj_p = jerry_api_get_global (); + + jerry_api_value_t val; + val.type = JERRY_API_DATA_TYPE_OBJECT; + val.v_object = obj_p; + + // after this, script can invoke the native handler through "handler_field (1, 2, 3);" + jerry_api_set_object_field_value (glob_obj_p, "handler_field", &val); + + jerry_api_release_object (glob_obj_p); + jerry_api_release_object (obj_p); +} +{% endhighlight %} diff --git a/04.internals.md b/04.internals.md new file mode 100644 index 000000000..1b6a36fcd --- /dev/null +++ b/04.internals.md @@ -0,0 +1,670 @@ +--- +layout: page +title: Internals +permalink: /internals/ +--- + +* toc +{:toc} + +# High-Level Design +![High-Level Design]({{ site.baseurl }}/img/engines_high_level_design.jpg){: class="thumbnail center-block img-responsive" } + +On the diagram above is shown interaction of major components of software system: Parser and Runtime. Parser performs translation of input ECMAScript application into byte-code with specified format (refer to [Bytecode](/internals/#byte-code) and [Parser](/internals/#parser) page for details). Prepared bytecode is executed by Runtime engine that performs interpretation (refer to [Virtual Machine](/internals/#virtual-machine) and [ECMA](/internals/#ECMA) pages for details). + +# Parser + +The parser is implemented as recursive descent parser. The parser does not build any type of Abstract Syntax Tree. It converts source JavaScript code directly into byte-code. + +The parser consists of three major parts: +- lexer +- parser +- opcodes dumper +- syntax errors checker +- serializer + +These four (except the parser itself) components are initialized during `parser_init` call (jerry-core/parser/js/parser.cpp). + +This initializer requires two following subsystems to be initialized: memory allocator and serializer. The need for allocator is clear. The serializer resets internal bytecode_data structure(jerry-core/parser/js/bytecode-data.h). Currently bytecode_data is singleton. During parsing it is filled by data which is needed for further execution: + +* Byte-code - array of opcodes (`bytecode_data.opcodes`). +* Literals - array of literals (`bytecode_data.literals`). +* Strings buffer (`bytecode_data.strings_buffer`) - literals of type `LIT_STR` contain pointers to strings, which are located in this buffer. + +The following is brief review of the mentioned components. See more concise description in the following chapters. + +* Lexer +The lexer splits input file (given as the first parameter of the parser_init call) into sequence of tokens. These tokens are then matched on demand. +* Opcodes dumper +This component does necessary checks and preparations, and dumps opcodes using serializer. +* Serializer +The serializer puts opcodes, prepared by the dumper, to a continuous array that represents current scope's code. Also it provides API for accessing byte-code. +* Syntax error checker +This is bunch of simple die-on-error checks. + +After initialization `parser_parse_program` (`./jerry-core/js/parser.cpp`) should be called. This function performs the following steps (so-called parsing steps) for all scopes (global code and functions): + +1. Initialize a scope. +2. Do pre-parser stage. +3. Parse scope code. + +After every scope is processed, parser merges all scopes into single byte-code array. + +Two new entities were introduced - scopes and pre-parser. + +* There are two types of scopes in the parser: global scope and function declaration scope. Notice that function expressions do not create a new scope in terms of the parser. A reason why is described below. Parsing process starts on global scope. If a function declaration occurs string the process, new scope is created, this new scope is pushed to a stack of current scopes; then steps 1-3 of parsing are performed. Note, that only global scope parsing shall merge all scopes into a byte-code. All scopes are stored in a tree to represent a hierarchy of them. +* Pre-parser. This step performs hoisting of variable declarations. First, it dumps `reg_var_decl` opcodes. Then it goes through the script and looks for variable declaration lists. For every found variable in the scope (not in a sub-scope or function expression) it dumps var_decl opcode. After this step byte-code in the scope starts with optional `'use strict'` marker, then `reg_var_decl` and several (optional) `var_decls`. + +Due to some limitations of the parser, some parsing functions take `this_arg` and/or `prop` as parameters. They are further used to dump `prop_setter` opcode. During parsing all necessary data is stored in either stacks or scope trees. After parsing of whole program, the parser merges all scopes into a single byte-code, hoisting function declarations in process. This task, so-called post-parser, is performed by `scopes_tree_raw_data` (jerry-core/js/scopes-tree.c) function. For further information about post-parser, check opcodes dumper section. + +### Lexer + +The lexer splits input string on set of tokens. The token structure (`./jerry-core/parser/js/lexer.h`) consists of three elements: token type, location of the token and optional data: + +```cpp +typedef struct +{ + locus loc; + token_type type; + literal_index_t uid; +} +token; +``` + +Location of token (`locus`). It is just an index of first token's character at a string that represents the program. Token types are are listed in lexer.h header file (`token_type` enum). Depending on token type, token specific data (`uid` field) has the different meaning. + +
+ +Token type | 'uid' meaning +TOK_KEYWORD | Keyword id, like KW_DO, KW_CONST, etc. (see 'keyword' enum in lexer.h). +TOK_NAME, TOK_STRING, TOK_NUMBER | Literal index in the stack of literals. +TOK_BOOL | 0 - 'false'
1 - 'true' +TOK_SMALL_INT | Value of small integer (0-255). +Other (punctuators) | Not used. + +
+ +Token matching algorithm is straightforward - look at the first character of new token, recognize the type, and then just match the rest. Comments and space characters (except new line) are ignored, so they produce no token. The algorithm uses two pointers: buffer and token_start. The first one points to the next character of the input, the other one points to the first character of token, being matched, so-called current token. + +The lexer remembers two tokens during scan: current and previously seen. It also allows buffering one token to be rescanned (`lexer_save_token`) and setting scan position to any location in the file (`lexer_seek`). + +The parser uses lexer two scan file two times - during pre-parsing and parsing stages. + +Currently the lexer does not support any encoding except ASCII. Also the lexer does not support regular expressions. + +### Opcodes dumper + +It is a quite high level wrapper for the serializer. It was introduced to split functionality of parsing and dumping opcodes. To understand how opcodes dumper works, one should be acquainted with the byte-code layout (see the corresponding description). + +The main data structure of the dumper is an operand (jerry-core/parser/js/opcodes-dumper.h). Operand can represent either variable (i.e. literal) or temporary register (tmp). The most annoying thing of the dumper is a difference between these types. + +Byte-code is divided into blocks of fixed size (`BLOCK_SIZE` in jerry-core/parser/js/bytecode-data.h) and each block has independent encoding of variable names, which are represented by 8 bit numbers - uids. +Operands are encoded as uids in each opcode (see the `opcode_t` structure). +As byte-code decomposition into blocks is not possible until parsing is finished, uids can't be calculated on the fly. Therefore literal operands are encoded by literal indexes (`literal_index_t` - index in the global literals array) during parsing. In the post-parser stage these indexes are converted to block specific uids. + +During parsing scopes tree structure is constructed (see `scopes_tree_int` in the jerry-core/parser/js/scopes-tree.h). Each tree node comprises of its byte-code and list of child scopes. While final byte-code is the plain array of `opcode_t` structures, byte-code in tree nodes is represented by the list of `op_meta` structures. Op\_meta structure wraps `opcode_t` with an array of 3 values (result, operand_1 and operand_2), which holds literal indexes, so that literal operands could be encoded. + +In each dump\_\* function (jerry-core/parser/js/opcodes-dumper.h) the dumper checks for the operand type and dumps appropriate op\_meta to the scopes tree using serializer. The dumper also keeps opcode counters of rewritable opcodes inside a bunch of stacks. It dumps an op\_meta and pushed an opcodes counter of the op\_meta to a stack in functions with a name like dump\_\*\_for\_rewrite, then pops an opcode counter from the stack, retrieves op\_meta by the dematerializer and rewrites necessary fields of opcodes in functions with names like rewrite\_\*. + +The post-parser merges scopes into a single byte-code. For each scope it first dumps a header of the scope, which consists of optional func_decl with function_end opcode pair, optional ‘use strict’ marker, `reg_var_decl` and optional `var_decls`. Then it recursively dumps sub-scopes. Finally, it dumps the remainder of opcodes. The byte-code is split into blocks with fixed size; each block has its own counter of literals. While dumping opcodes the post-parser replaces LITERAL_TO_REWRITE markers with this counter’s value. + +### Serializer + +Serializer dumps literals collected by the lexer to bytecode_data, is used by the dumper to dump or rewrite op_metas to a current scope. There is no much to say about this component. + +### Syntax Errors Checker + +This component is just checks for syntax errors defined in the specification. It uses stacks to store necessary data, for example arguments names. + +# Byte-code +Every instruction of bytecode consists of opcode and up to three operands. Operand (idx) can be either a "register" or a string +literal, specifying identifier to evaluate (i.e. `var //Storage idx`). General structure of instruction is shown on the picture. + +
+ +| opcode | idx | idx | idx | + +
+ +
Special kinds of instructions are described below. + +## Arithmetic/bitwise-logic/logic/comparison/shift +Arithmetic instruction can have the following structure: + +
+ +|opcode|dst|left|right| + +
+
+ +|opcode|dst|value|-| + +
+ +where `dst`/`left`/`right`/`value` identify an operand. + +## Control (jumps) +Control instructions utilize two bytes to encode jump location. Destination offset is contained inside `offset_high` and `offset_low` fields. + +
+ +|opcode|offset-high|offset-low|-| + +
+
+ +|opcode|cond value|offset-high|offset-low| + +
+ +Condition jump checks `cond value` field, which identifies an operand, and performs a jump if the operand has `true` value. + +## Assignment + +Assignment instructions perform assignment of immediate value (contained inside instruction) to the operand, which is marked as `idx` on the picture. + +
+ +|op_assignment|dst|type|value| + +
+ +where +`dst` - "storage idx", identifies where to store the value +`type` - specifies value type +`value` - depends on type field + +Type of the immediate value is encoded in the `type` field of instruction. The following values are supported: +- "simple value" (see ECMA types encoding) +- small integer/negative small integer +- number literal/negative number literal +- sring value, initialized by string literal ("literal idx") +- "Srorage idx" + +## Exit + +Exit instruction serves to stop the execution and exit with a specified status. + +
+ +|op_exit|status(0/1)|-|-| + +
+ +Exit instruction is employed in following cases: +- at script end (exit with "succesful" stats); +- in script assertion fail handling code (exit with "fail" status) + +## Native call (intrinsic call) + +Native call instruction is used to call intrinsics. Arguments are not encoded directly inside this instruction, instead they follow it as special "meta" instructions (see the according section). Id of desired intrinsic is encoded in the `intrinsic id` field. + +
+ +|op_native_call|dst|intrinsic_id|arg_list| + +
+ +where +`dst` - "storage idx" +`arg_list` - number of arguments + +## Function call/Constructor call + +Function/constructor call are utilized to perform calls to functions and constructors. Destination operand is encoded in `dst` field. Operand `name_idx` specifies the name of the function to call. Arguments are encoded the same way as in native call instruction. + +
+ +|opcode|dst|name_idx|arg_list| + +
+ +where +`dst` - "storage idx" +`name_idx` - "storage idx" (which value to call) +`arg_list` - number of arguments + +## Function declaration + +Function declarations are represented by special kind of instructions. Function name and number of arguments are located in `name_idx` and `arg_list` fields respectively. + +
+ +|opcode|name_idx|arg_list|-| + +
+ +where +`name_idx` - literal idx +`arg_list` - namber of arguments + +## Function expression + +Very similar to function declaration. But additionally contains destination (`dst`) field and `name` operand is optional, because anonymous functions are possible. + +
+ +|opcode|dst|name_idx|arg_list| + +
+ +where +`dst` - "storage idx" +`name_idx` - literal idx (can be unspecified for anonymos function expression) +`arg_list` - number of arguments + +## Return from function/eval + +Return instructions perfrom unconditional return from function/eval code. Return value can be specified (`idx` field). + +
+ +|op_ret|-|-|-| + +
+ +
+ +|op_retval|idx|-|-| + +
+ +where +`idx` - "storage idx" + +## "Meta" (special marker opcode) + +
+ +|op_meta|type|arg1|arg2| + +
+ +Meta instructions are usually utilized as continuations of other instructions. Depending on `type` field, meta instruction can have the following meaning: + +- 'this' argument (for calls in a.f() form, a = this), put right after call opcode +- `varg` (encodes an argument for calls and array declarations (`arg1` - storage idx) / parameters name for function decl/expr (`arg1` - literal idx, i.e. string)) +- carg_prop_data / varg_prop_getter / varg_prop_setter - name (literal idx) and value/getter/setter (storage idx) of a property (see also: object declaration) +- end_with / function_end / end_of_try_catch_finally - end offset of 'with' block/function/try_catch_finally sequence +- catch / finally - start of catch/finally block and offset to the end of the block +- strict code - placed at the start of a scope's code if the source code contains 'use strict' at the beginning + +## Delete + +JavaScript delete operator is modeled with delete instruction in the bytecode. There are two types of delete instruction, applied either to element of lexical environment or to object's property. + +
+ +|op_delete_var|dst|name|-| + +
+
+ +|op_delete_prop|dst|base_value|name| + +
+ +where +`dst` - "storage idx" +`name` - literal idx +`base_value` - "storage idx" + +## This binding (evaluate "this") +This binding instruction writes value of "this" to the `dst` operand. + +
+ +|op_this|dst|-|-| + +
+ +where +`dst` - "storage idx" + +## typeof (typeof operation) + +Typeof instruction executes JavaScript operator with the same name. Result is written to the `dst` operand. + +
+ +|op_typeof|dst|value|-| + +
+ +where +`dst` and `value` - "storage idx" + +## with block + +To specify bounds of "with" block, a pair of instructions is used. "With" instruction specifies its start. + +
+ +| op_with | value | - | - | + +
+ +where +`value` - "storage idx" (evaluated expression - argument of with) + +Followed by a number of arbitrary instructions, the block ends with `end_with` meta instruction. + +
+ +|op_with| +|| +|| +|...| +|op_meta (end_with)| + +
+ + +## try block + +Try block consists of try instruction, followed by a number of arbitrary instructions, meta instruction `catch` or `finally` or both of them, separating catch and finally blocks respectively and meta instruction `end_try_catch_finally`, which finishes the whole construction. + +
+ +| op_try_block | offset_high | offset_low | - | + +
+ +where +`offset_high` and `offset_low` - offset of the end of try block + +
+ +|op_try_block| +|...| +|op_meta (catch)| +|...| +|op_meta (finally)| +|...| +|op_meta (end_try_catch_finally)| + +
+ +## Object declaration + +Obect declaration instruction represents object literal in JavaScript specification. It consists of `op_obj_decl` instruction, followed by a list of `prop_data`, `prop_getter` and `prop_setter` meta instructions. A series of instructions which evaluate property values can precede meta instructions. Number of meta instructions, e.g. number of properties, is specified in the `prop_num` field. + +
+ +| op_obj_decl | dst | prop_num | - | + +
+ +where +`dst` - "storage idx" (where to save the created object) +`prop_num` - number of properties + +
+ +|op_obj_decl| +|...
(intermediate evaluation of value/function expression, etc.)| +|op_meta (prop_data/ prop_getter/ prop_setter)| + +
+ +## Arguments and array declarartion + +The strategy descibed in previous section is also used for encoding of arguments in function/constructor calls and elements in array declarations. +See the according pictures. + +
+ +| op_with | value | - | - | + +
+ +where +`value` - "storage idx" (evaluated expression - argument of with) + +
+ +|op_with| +|| +|| +|...| +|op_meta (end_with)| + +
+ +# Virtual machine + +Virtual machine executes bytecode by interpreting instructions one by one. Bytecode is a continuous array of instructions, divided into blocks of fixed size. Main loop of interpreter calls `opfunc_*` for every instruction. This function returns completion value and position of the next instruction. + +![Bytecode storage]({{ site.baseurl }}/img/bytecode_storage.jpg){: class="thumbnail center-block img-responsive" } + +Instruction can have up to three operands which are represented by `idx` values. Meaning of `idx` value depends on opcode and can be the following: + +- id of a temporary variable (register) +- id of literal (quiried form serializer, specific to every block of bytecode) +- type of assigned value, id of number/string literal or simple value in `op_assignment` +- type of meta and corresponding arguments in `op_meta` +- idx pair may represent opcode position + +During execution every function of the source code has associated +interpreter context, which consists of the following items: + +- current position (byte-code instruction to execute) +- 'this' binding (ecma-value) +- lexical environment +- `is_strict` flag (is current execution code strict) +- `is_eval_code_lag` (is current execution mode eval) +- `min_reg_num`, `max_reg_num` - range of `idx`'s used for "registers" +- stack frame (array of "register" values) + +Main routines of the virtual machine are: + +- `run_int` - starts execution of Global code (main program). +- `run_int_from_pos` - executes specified code scope + (global/function/eval), expects the following arguments: starting + position, 'this' binding, lexical environment. +- `run_int_loop` - interpretation loop. + +# ECMA + +ECMA component of the engine is responsible for following notions: +- Data representation +- Runtime representation +- GC + +## Data representation + +The major structure for data representation is `ECMA_value`. Lower two bits of this structure encode value tag, which determines the type of the value: + +* simple +* number +* string +* object + +![ECMA value representation]({{ site.baseurl }}/img/ecma_value.jpg){: class="thumbnail center-block img-responsive" } + +The immediate value is placed in higher bits. "Simple value" is an enumeration, which consists of the following elements: +- undefined +- null +- true +- false +- empty +- array_redirect (implementation defined, currently unused, for array storage optimization) + +For other value types higher bits of `ECMA_value` structure contain compressed pointer to the real value. + +### Compressed pointers + +Compressed pointers were introduced to save heap space. They are possible because heap size is currently limited by 256 KB, which requires 18 bits to cover it. ECMA values in heap are aligned by 8 bytes and this allows to save three more bits, so that compressed pointer consumes 15 bits only. + +![Heap and ECMA elements]({{ site.baseurl }}/img/ecma_compressed.jpg){: class="thumbnail center-block img-responsive" } + +ECMA data elements are allocated in pools (pools are allocated on heap) +Chunk size of the pool is 8 bytes (reduces fragmentation). + +### Number + +There are two possible representation of numbers: +- 4-byte (float, compact profile - no memory consumption, but hardware limitations) +- 8-byte (double, full profile) + +Several references to single allocated number are not supported. Each reference holds its own copy of a number. + +### String + +String values are encoded by 8-byte structure, which contains the following fields: + +- references counter - each stack (and non_stack) reference is counted (upon overflow, string is duplicated) +- is_stack_allocated - some temporary strings are stack_allocated to reduce loading of memory (perf) +- container - type of actual string storage/encoding +- hash - hash, calculated from two last characters (for faster comparison (perf)) +- literal identifier - actual string is in the literal storage +- magic_string_id - string is equal to one of engine's magic strings +- uint32 - string is represented with unsigned integers (useful for array indexing) +- number_cp (compressed pointer to number) - string is represented with floating point number +- collection_cp - string is stored in one or several pool's chunks (see also: chars collection, collection header, collection chunk) +- concatenation_1_cp, concatenation_2_cp - pointers to two strings (parts of concatenation) + +### Object / Lexical environment + +Object and lexical environment structures, 8 bytes each, have common (GC) header: +- Stack refs counter +- Next object/lexical environment in list of objects/lexical environments +- GC's visited flag +- is_lexenv flag + +Remaining fields of these structures are different and are shown on the picture. + +![Object/Lexicat environment structures]({{ site.baseurl }}/img/ecma_object.jpg){: class="thumbnail center-block img-responsive" } + +### Property of an object / description of a lexical environment variable + +While objects comprise of properties, lexical environments consist of variables. Both of these units are tied up into lists. Unit types could be different: +- named data (property or variable) +- named accessor (property) +- internal (implementation defined) + +All these units occupy 8 bytes and have common header: +- type - 2 bit +- next property/variable in the object/lexical environment (compressed pointer) + +The remaining parts are differnt: +![Object property/lexcial environment variable]({{ site.baseurl }}/img/ecma_object_property.jpg){: class="thumbnail center-block img-responsive" } + +### Collections + +ECMA runtime utilizes collections for intermediate calculations. Collection consists of a header and a number of linked chunks, which hold collection values. + +Header occupies 8 bytes and consists of: + +- compressed pointer to the next chunk +- number of elements +- rest space, aligned down to byte, is for first chunk of data in collection + +Chunk's layout is following: + +- compressed pointer to next chunk +- rest space, aligned down to byte, is for data stored in corresponding part of the collection + +### Internal properties: + +- [[Class]] - class of the object (ECMA-defined) +- [[Prototipe]] - is stored in object description +- [[Extensible]] - is stored in object description +- [[CScope]] - lexical environment (function's variable space) +- [[ParametersMap]] - arguments object -0 code of the function +- [[Code]] - where to find bytecode of the function +- native code - where to find code of native unction +- native handle - some uintptr_t assosiated with the objec +- [[FormalParameters]] - collection of pointers to ecma_string_t (the listof formal parameters of the function) +- [[PrimitiveValue]] for String - for String object +- [[PrimitiveValue]] for Number - for Number object +- [[PrimitiveValue]] for Boolean - for Boolean object +- built-in related: + - built-in id - id of built-in object + - built-in routine id - id of built-in routine + - "non-instantiated" mask - what built-in properties where notinstantiated yet (lazy instantiation) + - extention object identifier + +### LCache + +LCache is a cache for property variable search requests. + +![LCache]({{ site.baseurl }}/img/ecma_lcache.jpg){: class="thumbnail center-block img-responsive"} + +Entry of LCache has the following layout: +- object pointer +- property name (pointer to string) +- property pointer + +Caches's row is defined by string's hash. When a property access occurs, all row's entries are searched by comparing object pointer and property name to according entry's fields, full comparison is used for property name. + +If corresponding entry was found, its property pointer is returned (may be NULL - in case when there is no property with specified name in given object). +Otherwise, object's property set is iterated fully and corresponding record is registered in LCache (with property pointer if it was found or NULL otherwise). + +## Runtime + +ECMA-defined runtime operations are implemented mostly with routine having the following signature: + +`ecma_completion_value_t ecma_op_* ([ecma_value_t arguments])` +or +`ecma_property_t * ecma_op_[find/get]*_property (objs, name string, ...)` + +However, there could be some combinations. + +### Completion value + +Many algorithms/routines described in ECMA return a value of "completion" type, that is triplet of the following form: + +![ECMA completion]({{ site.baseurl }}/img/ecma_completion.jpg){: class="thumbnail center-block img-responsive" } + +Jerry introduces two additional completion types: +- exit - produced by `exitval` opcode, indicates request to finish execution +- meta - produced by meta instruction, used to catch meta opcodes in interpreter loop without explicit comparison on every iteration (for example: meta 'end_with') + +### Value management and ownership + +Every value stored by engine is associated with virtual "ownership" (that is responsibility to manage the value and free it when is is not needed, or pass ownership of the value to somewhere) + +
+ +| Value type| "Alloc" op | "Free" op| +| Number| ecma_alloc_number| ecma_dealloc_number| +| String| ecma_copy_or_ref_ecma_string| ecma_deref_ecma_string| +| Object|ecma_ref_object (for on_stack references) on_heap references are managed by GC|ecma_deref_object (for on_stack references) on_heap references are managed by GC| +| Property|(ownership is strongly connected with corresponding object)|(ownership is strongly connected with corresponding object)| +| Simple value|no memory management|no memory management| +| ecma_value (including values contained in completion value)|ecma_copy_value| ecma_free_value| + +
+ +Initially, value is allocated by its owner (i.e with ownership). +Value, passed in argument is passed without ownership. +Value, returned from function is returned with ownership. +Rules for completion value are the same as rules for values, contained in them. + +## Opcode handler structure + +Most opcode handlers consists of the following steps: +1. Decode instruction (i.e. extract `idx`-s) +2. Read input values from variables/registers +3. Perform necessary type conversions +4. Perform calls to runtime +5. Save execution result to output variable +6. Increment opcode position counter +7. Return completion value. + +Steps 2-5 can produce exceptions. +In this case execution is continued after corresponding FINALIZE mark, and completion value is set to throw exception. + +## Exception handling + +Operations that could produce exceptions should be performed in one of the following ways: +- wrapped into ECMA_TRY_CATCH block: + `ECMA_TRY_CATCH (value_returned_from_op, op (... ),` + `ret_value_of_the_whole_routine_handler)`` + `...` + `ECMA_FINALIZE(value_returned_from_op);` + `return ret_value;` +- `ret_value = op(...);` +- manual handling (for special cases like interpretation of opfunc_try_block). diff --git a/05.dev-guide.md b/05.dev-guide.md new file mode 100644 index 000000000..78ec4f613 --- /dev/null +++ b/05.dev-guide.md @@ -0,0 +1,304 @@ +--- +layout: page +title: Development +permalink: /dev-guide/ +--- + +The JerryScript Engine can be embedded into any application, providing way to run JavaScript in large range of environments - from desktops to low-memory microcontrollers. + +This guide is intended to introduce you to JerryScript embedding API through creation of simple JavaScript shell. + +## Step 1. Execute JavaScript from your application + +{% highlight cpp linenos=table %} +#include +#include "jerry.h" + +int +main (int argc, char * argv[]) { + char script [] = "print ('Hello, World!');"; + + jerry_completion_code_t code = jerry_run_simple (script, + strlen (script), + JERRY_FLAG_EMPTY); +} +{% endhighlight %} + +The application will generate the following output: + +{% highlight bash %} +Hello, World! +{% endhighlight %} + +## Step 2. Split engine initialization and script execution + +Here we perform the same actions, as `jerry_run_simple`, while splitting into several steps: + +- engine initialization +- script code setup +- script execution +- engine cleanup + + +{% highlight cpp linenos=table %} +#include +#include "jerry.h" + +int +main (int argc, char * argv[]) { + char script [] = "print ('Hello, World!');"; + + // Initialize engine + jerry_init (JERRY_FLAG_EMPTY); + + // Setup Global scope code + jerry_parse (script, strlen (script)); + + // Execute Global scope code + jerry_completion_code_t code = jerry_run (); + + // Cleanup engine + jerry_cleanup (); +} +{% endhighlight %} + +While code became a bit more complex, the change introduced possibilities to interact with JerryScript step by step, setup native objects, call Javascript functions, etc. + +## Step 3. Execution in 'eval'-mode + +{% highlight cpp linenos=table %} +#include +#include "jerry.h" + +int +main (int argc, char * argv[]) { + char script1 [] = "var s = 'Hello, World!';"; + char script2 [] = "print (s);"; + + // Initialize engine + jerry_init (JERRY_FLAG_EMPTY); + + jerry_api_value_t eval_ret; + + // Evaluate script1 + jerry_api_eval (script1, strlen (script1), + false, false, &eval_ret); + // Free JavaScript value, returned by eval + jerry_api_release_value (&eval_ret); + + // Evaluate script2 + jerry_api_eval (script2, strlen (script2), + false, false, &eval_ret); + // Free JavaScript value, returned by eval + jerry_api_release_value (&eval_ret); + + // Cleanup engine + jerry_cleanup (); +} +{% endhighlight %} + +This way, we execute two independent script parts in one execution environment. The first part initializes string variable, and the second outputs the variable. + +## Step 4. Interaction with JavaScript environment + +{% highlight cpp linenos=table %} +#include +#include "jerry.h" + +int +main (int argc, char * argv[]) { + char str [] = "Hello, World!"; + char var_name [] = "s"; + char script [] = "print (s);"; + + // Initializing JavaScript environment + jerry_init (JERRY_FLAG_EMPTY); + + // Getting pointer to the Global object + jerry_api_object_t *obj_p = jerry_api_get_global_object (); + + // Constructing string + jerry_api_string_t *str_val_p = jerry_api_create_string (str); + + // Constructing string value descriptor + jerry_api_value_t val; + val.type = JERRY_API_DATA_TYPE_STRING; + val.string_p = str_val_p; + + // Setting the string value to field of the Global object + jerry_api_set_object_field_value (obj_p, var_name, &val); + + // Releasing string value, as it is no longer necessary outside of engine + jerry_api_release_string (str_val_p); + + // Same for pointer to the Global object + jerry_api_release_object (obj_p); + + jerry_api_value_t eval_ret; + + // Now starting script that would output value of just initialized field + jerry_api_eval (script, strlen (script), + false, false, &eval_ret); + jerry_api_release_value (&eval_ret); + + // Freeing engine + jerry_cleanup (); +} +{% endhighlight %} + +The sample would also output 'Hello, World!'. However, now it is not just part of source script, but value, dynamically supplied to the engine. + +## Step 5. Description of JavaScript value descriptors + +Structure, used to put values to / receive values from engine is the following: + +- `type` of value: + - JERRY_API_DATA_TYPE_UNDEFINED (undefined); + - JERRY_API_DATA_TYPE_NULL (null); + - JERRY_API_DATA_TYPE_BOOLEAN (true / false); + - JERRY_API_DATA_TYPE_FLOAT64 (number); + - JERRY_API_DATA_TYPE_STRING (string); + - JERRY_API_DATA_TYPE_OBJECT (object reference); +- `v_bool` (if JERRY_API_DATA_TYPE_BOOLEAN) - boolean value; +- `v_float64` (if JERRY_API_DATA_TYPE_FLOAT64) - number value; +- `v_string` (if JERRY_API_DATA_TYPE_STRING) - pointer to string; +- `v_object` (if JERRY_API_DATA_TYPE_OBJECT) - pointer to object. + +Abstract values, to be sent to / received from engine are described with the structure. + +Pointers to strings / objects and values should be released just when become unnecessary, using `jerry_api_release_string` / `jerry_api_release_object` and `jerry_api_release_value`, correspondingly. + +The following example function would output a JavaScript value: + +{% highlight cpp linenos=table %} +static void +print_value (const jerry_api_value_t * value_p) +{ + switch (value_p->type) + { + // Simple values: undefined, null, false, true + case JERRY_API_DATA_TYPE_UNDEFINED: + printf ("undefined"); + break; + case JERRY_API_DATA_TYPE_NULL: + printf ("null"); + break; + case JERRY_API_DATA_TYPE_BOOLEAN: + if (value_p->v_bool) + printf ("true"); + else + printf ("false"); + break; + + // Number value + case JERRY_API_DATA_TYPE_FLOAT64: + printf ("%lf", value_p->v_float64); + break; + + // String value + case JERRY_API_DATA_TYPE_STRING: + { + ssize_t neg_req_sz, sz; + // determining required buffer size + neg_req_sz = jerry_api_string_to_char_buffer (value_p->v_string, + NULL, + 0); + assert (neg_req_sz < 0); + char * str_buf_p = (char*) malloc (-neg_req_sz); + sz = jerry_api_string_to_char_buffer (value_p->v_string, + str_buf_p, + -neg_req_sz); + assert (sz == -neg_req_sz); + + printf ("%s", str_buf_p); + + free (str_buf_p); + break; + } + + // Object reference + case JERRY_API_DATA_TYPE_OBJECT: + printf ("[JS object]"); + break; + } + + printf ("\n"); +} +{% endhighlight %} + +## Simple JavaScript shell + +Now all build blocks, necessary to construct JavaScript shell, are ready. + +Shell operation can be described with following loop: + +- read command; +- if command is 'quit' + - exit loop; +- else + - eval (command); + - print result of eval; + - loop. + +{% highlight cpp linenos=table %} +#include +#include +#include +#include + +#include "jerry.h" + +static void +print_value (const jerry_api_value_t * value_p); + +int +main (int argc, char * argv[]) { + // Initialize engine + jerry_init (JERRY_FLAG_EMPTY); + + char cmd [256]; + while (true) { + printf ("> "); + + // Input next command + if (fgets (cmd, sizeof (cmd), stdin) == NULL + || strcmp (cmd, "quit\n") == 0) { + // If the command is 'quit', exit from loop + break; + } + + jerry_api_value_t ret_val; + + // Evaluate entered command + jerry_completion_code_t status = jerry_api_eval (cmd, strlen (cmd), + false, false, + &ret_val); + + // If command evaluated successfully, print value, returned by eval + if (status == JERRY_COMPLETION_CODE_OK) { + // 'eval' completed successfully + print_value (&ret_val); + jerry_api_release_value (&ret_val); + } else { + // evaluated JS code thrown an exception + // and didn't handle it with try-catch-finally + printf ("Unhandled JS exception occured\n"); + } + + printf ("\n"); + fflush (stdout); + } + + // Cleanup engine + jerry_cleanup (); + + return 0; +} +{% endhighlight %} + +The application inputs commands and evaluates them, one after another. + + +## Further steps + +For further API description, please look at [Embedding API](/API). diff --git a/_includes/head.html b/_includes/head.html index 0478c84c7..d83e45a4f 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -9,50 +9,13 @@ JavaScript engine for Internet of Things{% if page.title %}: {{ page.title }} {% endif %} - - + + + + + + + diff --git a/_sass/_base.scss b/_sass/_base.scss index 2dd13d61b..c10641991 100644 --- a/_sass/_base.scss +++ b/_sass/_base.scss @@ -1,44 +1,97 @@ /** * Reset some basic elements */ -body, h1, h2, h3, h4, h5, h6, +/*body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; -} +}*/ p { margin: 0; padding: 0; + text-align: justify; + -moz-text-align-last: left; + text-align-last: left; } - /** * Basic styling */ body { - font-family: $base-font-family; + /*font-family: $base-font-family;*/ font-size: $base-font-size; line-height: $base-line-height; - font-weight: 300; + /*font-weight: 300;*/ color: $text-color; background-color: white; -webkit-text-size-adjust: 100%; } - /** * Set `margin-bottom` to maintain vertical rhythm */ -h1, h2, h3, h4, h5, h6, +/*h1, h2, h3, h4, h5, h6,*/ p, blockquote, pre, ul, ol, dl, figure, %vertical-rhythm { margin-bottom: $spacing-unit / 2; } +/** + * Styles from index + */ + html { + position: relative; + min-height: 100%; + } + body { + padding-top: 50px; + margin-bottom: 50px; + } + .footer { + position: absolute; + bottom: 0; + width: 100%; + height: 40px; + background-color: #f5f5f5; + } + .project_title h1{ + font-size: 64px; text-align: center; + font-weight: bold; + } + .project_title { + padding: 40px 20px; + text-align: center; + border-radius: 6px; + + p { + text-align: center; + -moz-text-align-last: center; + } + } + .lead { + color:#245580; + } + .project_overview { + font-family:"Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 18px; + padding: 40px; padding-bottom: 20px; + background-color: #f5f5f5; + } + .learn_more { + font-family:"Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 18px; + padding: 40px; padding-bottom: 20px; + } + .container .copyright_and_license_notice { + margin: 8px 0; + font-size:14px; text-align: center; + color:#3C3C3C; + } + /** * Images @@ -70,9 +123,9 @@ figcaption { /** * Lists */ -ul, ol { +/*ul, ol { margin-left: $spacing-unit; -} +}*/ li { > ul, diff --git a/_sass/_layout.scss b/_sass/_layout.scss index d471efd16..75f4beb70 100644 --- a/_sass/_layout.scss +++ b/_sass/_layout.scss @@ -1,6 +1,3 @@ -html {height: 100%;} -body{ height: 100%; margin: 0;} - /** * Site header */ @@ -208,7 +205,7 @@ body{ height: 100%; margin: 0;} /** * Posts */ -.post-header { +/*.post-header { margin-bottom: $spacing-unit; } @@ -222,7 +219,7 @@ body{ height: 100%; margin: 0;} @include media-query($on-laptop) { font-size: 28px; } -} +}*/ .post-content { margin-bottom: $spacing-unit; diff --git a/css/block.css b/css/block.css new file mode 100644 index 000000000..768f0b4f7 --- /dev/null +++ b/css/block.css @@ -0,0 +1,91 @@ +.CSSTableGeneratorBlock { + margin-left:35%;magin-right:35%;padding:0px; + width:30%; + border:3px solid #0000ff; + + -moz-border-radius-bottomleft:0px; + -webkit-border-bottom-left-radius:0px; + border-bottom-left-radius:0px; + + -moz-border-radius-bottomright:0px; + -webkit-border-bottom-right-radius:0px; + border-bottom-right-radius:0px; + + -moz-border-radius-topright:0px; + -webkit-border-top-right-radius:0px; + border-top-right-radius:0px; + + -moz-border-radius-topleft:0px; + -webkit-border-top-left-radius:0px; + border-top-left-radius:0px; +}.CSSTableGeneratorBlock table{ + border-collapse: collapse; + border-spacing: 0; + width:100%; + height:100%; + margin-left:0%;magin-right:0%;padding:0px; + table-layout: fixed +}.CSSTableGeneratorBlock tr:last-child td:last-child { + -moz-border-radius-bottomright:0px; + -webkit-border-bottom-right-radius:0px; + border-bottom-right-radius:0px; +} +.CSSTableGeneratorBlock table tr:first-child td:first-child { + -moz-border-radius-topleft:0px; + -webkit-border-top-left-radius:0px; + border-top-left-radius:0px; +} +.CSSTableGeneratorBlock table tr:first-child td:last-child { + -moz-border-radius-topright:0px; + -webkit-border-top-right-radius:0px; + border-top-right-radius:0px; +}.CSSTableGeneratorBlock tr:last-child td:first-child{ + -moz-border-radius-bottomleft:0px; + -webkit-border-bottom-left-radius:0px; + border-bottom-left-radius:0px; +}.CSSTableGeneratorBlock tr:hover td{ + background-color:#ffffff; + + +} +.CSSTableGeneratorBlock td{ + vertical-align:middle; + + background-color:#ffffff; + + border:1px solid #0000ff; + border-width:0px 3px 3px 0px; + text-align:left; + padding:6px; + font-size:14px; + font-family:Arial; + font-weight:normal; + color:#000000; +}.CSSTableGeneratorBlock tr:last-child td{ + border-width:0px 3px 0px 0px; +}.CSSTableGeneratorBlock tr td:last-child{ + border-width:0px 0px 3px 0px; +}.CSSTableGeneratorBlock tr:last-child td:last-child{ + border-width:0px 0px 0px 0px; +} +.CSSTableGeneratorBlock tr:first-child td{ + + background-color:#ffffff; + border:0px solid #0000ff; + text-align:left; + border-width:0px 0px 3px 3px; + font-size:14px; + font-family:Arial; + font-weight:normal; + color:#000000; +} +.CSSTableGeneratorBlock tr:first-child:hover td{ + + background-color:#ffffff; +} +.CSSTableGeneratorBlock tr:first-child td:first-child{ + border-width:0px 0px 3px 0px; +} +.CSSTableGeneratorBlock tr:first-child td:last-child{ + border-width:0px 0px 3px 0px; +} diff --git a/bootstrap.min.css b/css/bootstrap.min.css similarity index 100% rename from bootstrap.min.css rename to css/bootstrap.min.css diff --git a/css/bytecode.css b/css/bytecode.css new file mode 100644 index 000000000..eeefcfac1 --- /dev/null +++ b/css/bytecode.css @@ -0,0 +1,92 @@ +.CSSTableGeneratorByte { + margin-left:30%;margin-righ:30%;padding:0px; + width:40%; + border:1px solid #ffffff; + + -moz-border-radius-bottomleft:5px; + -webkit-border-bottom-left-radius:5px; + border-bottom-left-radius:5px; + + -moz-border-radius-bottomright:5px; + -webkit-border-bottom-right-radius:5px; + border-bottom-right-radius:5px; + + -moz-border-radius-topright:5px; + -webkit-border-top-right-radius:5px; + border-top-right-radius:5px; + + -moz-border-radius-topleft:5px; + -webkit-border-top-left-radius:5px; + border-top-left-radius:5px; +}.CSSTableGeneratorByte table{ + border-collapse: collapse; + border-spacing: 0; + width:100%; + height:100%; + margin-left:0%;margin-righ:0%;padding:0px; + table-layout:fixed; +}.CSSTableGeneratorByte tr:last-child td:last-child { + -moz-border-radius-bottomright:5px; + -webkit-border-bottom-right-radius:5px; + border-bottom-right-radius:5px; +} +.CSSTableGeneratorByte table tr:first-child td:first-child { + -moz-border-radius-topleft:5px; + -webkit-border-top-left-radius:5px; + border-top-left-radius:5px; +} +.CSSTableGeneratorByte table tr:first-child td:last-child { + -moz-border-radius-topright:5px; + -webkit-border-top-right-radius:5px; + border-top-right-radius:5px; +}.CSSTableGeneratorByte tr:last-child td:first-child{ + -moz-border-radius-bottomleft:5px; + -webkit-border-bottom-left-radius:5px; + border-bottom-left-radius:5px; +}.CSSTableGeneratorByte tr:hover td{ + background-color:#f97777; + + +} +.CSSTableGeneratorByte td{ + vertical-align:middle; + + background-color:#ffffff; + + border:1px solid #ffffff; + border-width:0px 1px 1px 0px; + text-align:center; + padding:5px; + font-size:12px; + font-family:Arial; + font-weight:normal; + color:#000000; +}.CSSTableGeneratorByte tr:last-child td{ + border-width:0px 1px 0px 0px; +}.CSSTableGeneratorByte tr td:last-child{ + border-width:0px 0px 1px 0px; +}.CSSTableGeneratorByte tr:last-child td:last-child{ + border-width:0px 0px 0px 0px; +} +.CSSTableGeneratorByte tr:first-child td{ + + background-color:#f97777; + border:0px solid #ffffff; + text-align:center; + border-width:0px 0px 1px 1px; + font-size:12px; + font-family:Arial; + font-weight:bold; + color:#000000; +} +.CSSTableGeneratorByte tr:first-child:hover td{ + + + background-color:#f97777; +} +.CSSTableGeneratorByte tr:first-child td:first-child{ + border-width:0px 0px 1px 0px; +} +.CSSTableGeneratorByte tr:first-child td:last-child{ + border-width:0px 0px 1px 1px; +} diff --git a/css/table.css b/css/table.css new file mode 100644 index 000000000..a7db87d3e --- /dev/null +++ b/css/table.css @@ -0,0 +1,96 @@ +.CSSTableGenerator { + margin:0px;padding:0px; + width:100%; + border:1px solid #000000; + + -moz-border-radius-bottomleft:0px; + -webkit-border-bottom-left-radius:0px; + border-bottom-left-radius:0px; + + -moz-border-radius-bottomright:0px; + -webkit-border-bottom-right-radius:0px; + border-bottom-right-radius:0px; + + -moz-border-radius-topright:0px; + -webkit-border-top-right-radius:0px; + border-top-right-radius:0px; + + -moz-border-radius-topleft:0px; + -webkit-border-top-left-radius:0px; + border-top-left-radius:0px; +}.CSSTableGenerator table{ + border-collapse: collapse; + border-spacing: 0; + width:100%; + height:100%; + margin:0px;padding:0px; +}.CSSTableGenerator tr:last-child td:last-child { + -moz-border-radius-bottomright:0px; + -webkit-border-bottom-right-radius:0px; + border-bottom-right-radius:0px; +} +.CSSTableGenerator table tr:first-child td:first-child { + -moz-border-radius-topleft:0px; + -webkit-border-top-left-radius:0px; + border-top-left-radius:0px; +} +.CSSTableGenerator table tr:first-child td:last-child { + -moz-border-radius-topright:0px; + -webkit-border-top-right-radius:0px; + border-top-right-radius:0px; +}.CSSTableGenerator tr:last-child td:first-child{ + -moz-border-radius-bottomleft:0px; + -webkit-border-bottom-left-radius:0px; + border-bottom-left-radius:0px; +}.CSSTableGenerator tr:hover td{ + background-color:#ffffff; + + +} +.CSSTableGenerator td{ + vertical-align:middle; + + background-color:#e5e5e5; + + border:1px solid #000000; + border-width:0px 1px 1px 0px; + text-align:left; + padding-left:10px; + font-size:15px; + font-family:Arial; + font-weight:normal; + color:#000000; +}.CSSTableGenerator tr:last-child td{ + border-width:0px 1px 0px 0px; +}.CSSTableGenerator tr td:last-child{ + border-width:0px 0px 1px 0px; +}.CSSTableGenerator tr:last-child td:last-child{ + border-width:0px 0px 0px 0px; +} +.CSSTableGenerator tr:first-child td{ + background:-o-linear-gradient(bottom, #cccccc 5%, #cccccc 100%); background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #cccccc), color-stop(1, #cccccc) ); + background:-moz-linear-gradient( center top, #cccccc 5%, #cccccc 100% ); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#cccccc", endColorstr="#cccccc"); background: -o-linear-gradient(top,#cccccc,cccccc); + + background-color:#cccccc; + border:0px solid #000000; + text-align:center; + border-width:0px 0px 1px 1px; + font-size:15px; + font-family:Arial; + font-weight:bold; + color:#000000; +} +.CSSTableGenerator tr:first-child:hover td{ + background:-o-linear-gradient(bottom, #cccccc 5%, #cccccc 100%); background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #cccccc), color-stop(1, #cccccc) ); + background:-moz-linear-gradient( center top, #cccccc 5%, #cccccc 100% ); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#cccccc", endColorstr="#cccccc"); background: -o-linear-gradient(top,#cccccc,cccccc); + + background-color:#cccccc; +} +.CSSTableGenerator tr:first-child td:first-child{ + border-width:0px 0px 1px 0px; +} +.CSSTableGenerator tr:first-child td:last-child{ + border-width:0px 0px 1px 1px; +} diff --git a/index.html b/index.html index 4c31a72b7..4246adcf9 100644 --- a/index.html +++ b/index.html @@ -7,14 +7,14 @@ permalink: /

A JavaScript engine for Internet of Things

- -

JerryScript is a lightweight JavaScript engine intended to run on a very constrained devices such as microcontrollers:

+

JerryScript is the lightweight JavaScript engine intended to run on a very constrained devices such as microcontrollers: +

  • Only few kilobytes of RAM available to the engine (<64 KB RAM)
  • Constrained ROM space for the code of the engine (<200 KB ROM)
  • -
  • On-device compilation and execution
  • -
  • The engine provides access to peripherals from JavaScript
+

The engine supports on-device compilation, execution and provides access to peripherals from JavaScript. +

To learn more, please visit the project on Github.