Skip to content

Re-thinking the Jerry Port API (proposal) #964

Closed
@akosthekiss

Description

@akosthekiss

Motivation

Lately, there have been several PRs (#945 #946 #956 #957) that pointed out that the port API of jerry is not that easy to use by embedders that are not in the main code base and thus could benefit from improvements.

Taking a closer look at some parts of the code also revealed that even the use cases in the main code base could become cleaner after some rethinking-refactoring.

Analysis

I've built jerry with make LTO=OFF ALL_IN_ONE=ON and ran nm on the resulting jerry-core library to see what symbols it defines and -- most importantly -- what external symbols it references. Below is the list of external symbols (categorization by me):

"termination"
                 U abort
                 U exit
"i/o"
                 U printf
                 U putchar
                 U stderr
                 U vfprintf
"math"
                 U acos
                 U asin
                 U atan
                 U atan2
                 U ceil
                 U cos
                 U exp
                 U fabs
                 U floor
                 U fmod
                 U log
                 U pow
                 U sin
                 U sqrt
                 U tan
"general libc"
                 U longjmp
                 U memcmp
                 U memcpy
                 U memmove
                 U memset
                 U rand
                 U setjmp
                 U strlen
                 U strncmp

IMO, the "math" and "general libc" categories cover very fundamental functionalities, which a port shouldn't be allowed to override. However, the "termination" and "i/o" categories can be port specific, and we should think about what we actually use them for and how we should let the ports give their specific implementation.

Proposal

I propose not to replicate the low-level libc API in the port API but to make the port functions "semantic".

Port API: Termination

/**
 * Signal the port that jerry experienced a fatal failure from which it cannot
 * recover.
 *
 * @param code gives the cause of the error.
 *
 * Note: jerry expects the function not to return.
 *
 * Example: a libc-based port may implement this with exit() or abort().
 */
void jerry_port_fatal (jerry_fatal_code_t code);

It should be the embedder application and/or the port that decides whether exit or abort is to be called. This differs from the current approach, where jerry even provides an api function to switch between exit/abort mode of fatal termination. This would make that function unnecessary.

Note: It is highly questionable whether a library should be able to terminate an application. However, as of now, we only have the concept of completion code around jerry_parse and jerry_run. Most of the other API functions have no way of signaling an error. So, let's keep the termination approach for now with this port function.

Port API: I/O

/**
 * Print a string to the console. The function should implement a printf-like
 * interface, where the first argument specifies a format string on how to
 * stringify the rest of the parameter list.
 *
 * This function is only called with strings coming from the executed ECMAScript
 * wanting to print something as the result of its normal operation.
 *
 * Example: a libc-based port may implement this with vprintf().
 */
void jerry_port_log_console (const char *fmt, ...);

/**
 * Display or log an error message. The function should implement a printf-like
 * interface, where the first argument specifies a format string on how to
 * stringify the rest of the parameter list.
 *
 * This function is only called with messages coming from the jerry engine as
 * the result of some abnormal operation.
 *
 * @param level ??? (warning, error, fatal)
 *
 * Example: a libc-based port may implement this with vfprintf(stderr).
 */
void jerry_port_log_error (int level, const char *fmt, ...);

/**
 * Display or log a debug message. The function should implement a printf-like
 * interface, where the first argument specifies a format string on how to
 * stringify the rest of the parameter list.
 *
 * This function is only called with debug messages coming from the jerry engine
 * describing its internal operations (e.g., data structure dumps or tracing
 * info).
 *
 * @param level ??? (numeric?)
 *
 * Example: a libc-based port may implement this with vfprintf(logfile).
 */
void jerry_port_log_debug (int level, const char *fmt, ...);

These should be the only I/O functions jerry calls. All calls to putchar, vfprintf, and putchar should be rewritten to one of these, depending on what jerry wants to print.

It should be the port that decides what a console is, or whether error and debug messages are logged to the same console or saved to a database or to a file.

Additional Port APIs

The above proposal covers and re-thinks only those functionalities, which are already in the project. There might be need for additional port APIs (e.g., memory management, #946). They should/might be analysed and proposed a similar way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiRelated to the public APIdiscussionOngoing discussion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions