EMME: A Formal Tool for ECMAScript Memory Model Evaluation
Abstract
Nearly all webbased interfaces are written in JavaScript. Given its prevalence, the support for high performance JavaScript code is crucial. The ECMA Technical Committee 39 (TC39) has recently extended the ECMAScript language (i.e., JavaScript) to support shared memory accesses between different threads. The extension is given in terms of a natural language memory model specification. In this paper we describe a formal approach for validating both the memory model and its implementations in various JavaScript engines. We first introduce a formal version of the memory model and report results on checking the model for consistency and other properties. We then introduce our tool, EMME, built on top of the Alloy analyzer, which leverages the model to generate all possible valid executions of a given JavaScript program. Finally, we report results using EMME together with small test programs to analyze industrial JavaScript engines. We show that EMME can find bugs as well as missed opportunities for optimization.
1 Introduction
As webbased applications written in JavaScript continue to increase in complexity, there is a corresponding need for these applications to interact efficiently with modern hardware architectures. Over the last decade, processor architectures have moved from singlecore to multicore, with the latter now present in the vast majority of both desktop and mobile platforms. In 2012, an extension to JavaScript was standardized [20] which supports the creation of multithreaded parallel Web Workers with messagepassing. More recently, the committee responsible for JavaScript standardization extended the language to support shared memory access [10]. This extension integrates a new datatype called SharedArrayBuffer which allows for concurrent memory accesses, thus enabling more efficient multithreaded program interaction.
Given a multithreaded program that uses shared memory, there can be several possible valid executions of the program, given that reads and writes may concurrently operate on the same shared memory and that every thread can have a different view of it. However, not all behaviors are allowed, and the separation between valid and invalid behaviors is defined by a memory model. In one common approach, memory models are specified using axioms, and the correctness of a program execution is determined by checking its consistency with the axioms in the memory model. Given a set of memory operations (i.e., reads and writes) over shared memory, the memory model defines which combinations of written values each read event can observe. Because many different programs can have the same behaviors, the memory model is also particularly important for helping to determine the set of possible optimizations that a compiler can apply to a given program. As an example, a memory model could specify that the only allowed multithreaded executions are those that are equivalent to a sequential program composed of some interleaving of the events in each thread. This model is the most stringent one and is called sequential consistency. With this approach, all threads observe the same total order of events. However, this model has significant performance limitations. In particular, it requires all cores/processors to synchronize their local cache with each other in order to maintain a coherent order of the memory events. In order to overcome such limitations, weaker memory models have been introduced. The ECMAScript Memory Model is a weak model.
Memory models are notoriously challenging to analyze with conventional testing alone, due to their nonintuitive semantics and formal axiomatic definitions. As a result, formal methods are frequently used in order to verify and validate the correctness of memory models [4, 5, 6, 7, 18]. Some of these models apply to instruction set architectures, whereas others apply to highlevel programming languages. In this work, we use formal methods to validate the ECMAScript Memory Model and to analyze the correctness and performance of different implementations of ECMAScript engines. JavaScript is usually regarded as a highlevel programming language, but its memory model is decidedly lowlevel and more closely matches that of instruction set architectures than that of other languages. The analyses that we provide are based on a formalization of the memory model using the Alloy language [12], which is then combined with a formal translation of the program to be analyzed in order to compute its set of valid executions. This result can then be used to automatically generate litmus tests that can be run on a concrete ECMAScript engine, allowing the developers to evaluate its correctness. The concrete executions observed when running the ECMAScript engine can either be a subset of, be equivalent to, or be a superset of the valid executions. Standard litmus test analyses usually target the latter case (incorrect engine behavior), providing little information in the other cases. However, when the concrete engine’s observed executions are a relatively small subset of the valid executions, (e.g., 1/5 the size), this can indicate a missed opportunity for code optimization. As part of our work, we introduce a novel approach in such cases that is able to identify specific predicates over the memory model that are always consistent with the executions of the concrete engine, thus providing guidance about where potential optimization opportunities might exist.
The analyses proposed in this paper have been implemented in a tool called ECMAScript Memory Model Evaluator (EMME), which has been used to validate the memory model and to test the compliance of all major ECMAScript engines, including Google’s V8 [1], Apple’s JSC [2], and Mozilla’s SpiderMonkey [3].
The rest of the paper is organized as follows: Sect. 2 covers related work on formal analysis of memory models; Sect. 3 describes the ECMAScript Memory Model and its formal representation; Sect. 4 characterizes the analyses that are presented in this paper; Sect. 5 provides an overview of the Alloy translation; Sect. 6 concentrates on the tool implementation and the design choices that were made; Sect. 7 provides an evaluation of the performance of the different techniques proposed in this paper; Sect. 8 describes the results of the analyses performed on the ECMAScript Memory Model and several specific engine implementations; and Sect. 9 provides concluding remarks.
2 Related Work
Most modern multiprocessor systems implement relaxed memory models, enabling them to deliver better performance when compared to more strict models. Well known approaches such as Sequential Consistency (SC), Processor Consistency (PC), RelaxedMemory Order (RMO), Total Store Order (TSO), and Partial Store Order (PSO) are mainly directed towards relaxing the constraints on when read and write operations can be reordered.
The formal analysis of weak memory model hardware implementations has typically been done using SATbased techniques [5, 9]. In [4], a formal analysis based on Coq is used in order to evaluate SC, TSO, PSO, and RMO memory models. The DIY tool developed in [4] generates assembly programs to run against Power and x86 architectures. In contrast, in this work we concentrate on the analysis of the ECMAScript memory model, assuming the processor behavior is correct.
MemSAT [19] is a formal tool, based on Alloy [12], that allows for the verification of axiomatic memory models. Given a program enriched with assertions, MemSAT finds a trace execution (if it exists) where both assertions and the axioms in the memory model are satisfied.
An analysis of the C++ memory model is presented in [6]. The formalization is based on the LEM language [17], and the CPPMem software provides all possible interpretations of a C/C++ program consistent with the memory model. More recently, an approach based on Alloy and oriented towards synthesizing litmus tests is proposed in [14].
3 The ECMAScript Memory Model
The objective of the ECMAScript Memory Model is to precisely define when an execution of a concurrent program that relies on shared memory is valid. From the point of view of the Memory Model, a JavaScript program can be abstracted as a set of threads, each of them composed of an ordered set of shared memory events. Each memory event has a set of attributes that specify its: operation (Read, Write, or ReadModifyWrite); ordering (SeqCst, Unordered, or Init); tear type (whether a single read operation can read from two different writes to the same location); (source or destination) memory block and address; payload value; and modify operation (in the case of a ReadModifyWrite). The shared memory is essentially an array of bytes, and a memory operation reads, writes, or modifies it. In these operations, the bytes can be interpreted either as signed/unsigned integer values or as floating point values. For instance, in Fig. 2, the notation xI16[1] represents an access to the memory block x starting at index 1, where the bytes are interpreted as 16bit signed integers (i.e., I16), while xF32[0] stands for a 32bit floating point value starting at byte 0.
Formally, a program is defined as a set of events E and a partial order between them, namely the Agent Order, that encodes the thread structure. For the example in Fig. 1, the set of events is defined as \(E = \{ev_1W^1\), \(ev_2W^2\), \(ev_3R^2\), \(ev_4R^3\), \(ev_5W^3\), \(ev_6W^3\}\), with agent order \(\text {AO} = AO^1\, \cup \, AO^2\, \cup \, AO^3\), where \(AO^1\), \(AO^2\), and \(AO^3\) are the agent orders for each thread: \(\text {AO}^1 = \{\}\), \(\text {AO}^2 = \{(ev_2W^2, ev_3R^2)\}\), and \(\text {AO}^3 = \{(ev_4R^3, ev_5W^3)\), \((ev_4R^3, ev_6W^3)\), \((ev_5W^3, ev_6W^3)\}\).
The execution semantics of a program is given by the Reads Bytes From (RBF) relation, a trinary relation which relates two events and a single byte index i, with the interpretation that the first event reads the byte at index i which was written by the second event. Looking again at the example in Fig. 1, one of the possible valid assignments to the RBF relation is \(\{(ev_4R^3, ev_1W^1, 0)\), \((ev_3R^2, ev_2W^2, 0)\), \((ev_3R^2, ev_6W^3, 1)\}\), meaning that the Read event \(ev_4R^3\) reads byte 0 from \(ev_1W^1\) (taking the else branch), and \(ev_3R^2\) reads byte 0 from \(ev_2W^2\) and 1 from \(ev_6W^3\).

Reads From (RF): a binary relation that generalizes RBF by dropping the byte location;

Synchronizes With (SW): the synchronization relation between sequentially consistent writes and reads;

Happens Before (HB): a partial order relation between all events;

Memory Order (MO): a total order relation between sequentially consistent events.

Coherent Reads (CR): RF and HB relations are consistent;

Tear Free Reads (TFR): for reads and writes for which the tear attribute is false, a single read event cannot read from two different write events (both of which are to the same memory address);

Sequential Consistent Atomics (SCA): the MO relation is not empty.
3.1 Formal Representation
The formalization of the ECMAScript Memory Model is based on the formal definition of a Memory Operation, shown in Definition 1.
Definition 1

ID is a unique event identifier;

\(O \in \{\text {Read (R)}, \text {Write (W)}, \text {ReadModifyWrite (M)}\}\) is the operation;

\(T \in \mathbb {B}\) is the Tear attribute;

\(R \in \{\text {Init (I)}, \text {SeqCst (SC)}, \text {Unordered (U)}\}\) is the order attribute;

B is the name of a Shared Data Block;

M is a set of integers representing the memory addresses in B accessed by the operation O, with the requirement that \(M = \{i \in \mathbb {N}\ \ ByteIndex \le i < ByteIndex + ElementSize \}\), for some \(ByteIndex, ElementSize \in \mathbb {N}\)

\(A \in \mathbb {B}\) is an Activation attribute.

In [10], the memory address range for an operation is represented by two numbers, the ByteIndex and the ElementSize, whereas in Definition 1, we represent the memory address range explicitly as a set of bytes (which must contain some set of consecutive numbers, so the two representations are equivalent). This representation allows for a simpler encoding of some operators like computing the intersection of two address ranges.

Definition 1 omits the payload and modify operation attributes, as these are only needed to compute the concrete value(s) of the data being read or written. The formal model does not need to reason about such concrete values in order to partition candidate executions into valid and invalid ones. Furthermore, for any specific candidate execution of a JavaScript program, these values can be computed from the original program using the RBF relation.

The activation attribute A is an extension used to encode whether an event should be considered active based on the control flow path taken in an execution. In particular, we model ifthenelse statements by enabling or disabling the events in the then and else branches depending on the value of the condition.
4 Formal Analyses
The design and development of a critical (software or hardware) system often follows a process in which highlevel requirements (such as the standards committee’s specification of the memory model) are used to guide an actual implementation. This process can be integrated with different formal analyses to ensure that the result is a faithful implementation with respect to the requirements. In this section, we describe the set of analyses that we used to validate the requirements and implementations of the ECMAScript Memory Model. Results of our analyses are reported in Sect. 8.
4.1 Formal Requirements Validation
The ECMAScript Memory Model defines a set of constraints which together make up a formula (Eq. (1)). The solutions of this formula are the valid executions. The Memory Model also lists a number of assertions, formulas that are expected to be true in every valid execution (and thus must follow from the constraints). Complete formal requirements validation would require checking two things: (i) the constraints are consistent with each other, i.e. they contain no contradictions; and (ii) each assertion is logically entailed by the set of constraints in the Memory Model. However, because we used Alloy (see Sect. 5) we were unable to show full logical entailment, as Alloy can only reason about a finite number of events. So we instead showed that for finite sets of events up to a certain size, (i) and (ii) hold. In future work, we plan to explore using an SMT solver to see if we can prove unbounded entailment in some cases. When (i) or (ii) do not hold, there is a bug in either the requirements or the formal modeling of the requirements. To help debug problems with (i), we used the unsat core feature of Alloy, which identifies a subset of the constraints that are inconsistent. To further aid debugging, we labeled each constraint \(c_i\) with a Boolean activation variable \(av_i\) (i.e. we replaced \(c_i\) with \((av_i \rightarrow c_i) \wedge av_i\)). This allowed us to inspect the unsat core for activation variables and immediately discern which constraints were active in producing the unsatisfiable result.
4.2 Implementation Testing
The Implementation testing phase analyzes whether a specific JavaScript engine correctly implements the ECMAScript Memory Model. In particular, given a program with shared memory operations, we generate: (1) the set of valid executions, (2) a litmus test, and (3) behavioral coverage constraints.
Litmus Tests. Litmus test generation uses the generated list of valid executions to construct a JavaScript program enriched with an assertion that is violated if the output of the program does not match any of the valid executions. A litmus test is executed multiple times (e.g., millions), in order to increase the chance of exposing a problem if there is one.
The result of running a litmus test many times can (in general) have one of three outcomes: the assertion is violated at least once, the assertion is not violated and all possible executions are observed, and the assertion is not violated and only some of the possible executions are observed. More specifically, given a program P, the set of its valid executions \({ VE}(P)\), and the set of concrete executions \(E_{N}(P)\) (obtained by running the JavaScript program on engine E some number of times N), the possible results can be respectively expressed as \(E_{N}(P) {\setminus } { VE}(P) \ne \emptyset \), \(E_{N}(P) = { VE}(P)\), and \(E_{N}(P) \subset { VE}(P)\).
Behavioral Coverage Constraints. Though they can expose bugs, the litmus tests do not provide a guarantee of implementation correctness. In fact, even when a “bug” is found, it could be that the specification is too tight (i.e., it is incompatible with some intended behaviors) rather than that the implementation wrong. On the other hand, when \(E_{N}(P) \subset { VE}(P)\), and especially if the cardinality of \(E_{N}(P)\) is significantly smaller than that of \({ VE}(P)\), it might be the case that the implementation is too simple: it is not taking sufficient advantage of the weak memory model and is therefore unnecessarily inefficient.
Whenever \(E_{N}(P) \subset { VE}(P)\), this situation can be analyzed by the generation of Behavioral Coverage Constraints. The goal of this analysis is to synthesize the formulae \(\varSigma _{OBS}\) and \(\varSigma _{UNOBS}\), for observed and unobserved outputs, that restrict the behavior of the memory model in order to match \(E_{N}(P)\) and \({ VE}(P){\setminus } E_{N}(P)\).
5 Alloy Formalization
Alloy is a widely used modeling language that can be used to describe data structures. The Alloy language is based on relational algebra and has been successfully used in many applications, including the analysis of memory models [14].
However, further analysis and discussions with the people responsible for the Memory Model revealed that the correct interpretation is: \(\forall \,(e_1,e_2){.}\text {HB}(e_1,e_2) \leftrightarrow (\text {AO}(e_1,e_2) \vee \text {SW}(e_1,e_2) \vee \ldots )\). The Alloy formalization of the Happens Before relation is shown in Fig. 4. The Active2 predicate evaluates to true when both events are active.
6 Implementation
Input Format and Encoding. The input format of EMME uses a simplified JavaScriptlike syntax. It supports the definition of Read, Write, and ReadModifyWrite events, allows events to be atomic or not atomic, and supports operations on integer or floating point values. The input format also supports ifthenelse and bounded forloop statements, as well as parametric values. An example of an input program is shown in Fig. 6. The program is encoded in Alloy and combined with the memory model in order to provide the input formula for the formal analyses.
Generation of All Valid Executions. The generation of all valid executions is computed by using Alloy to solve the AllSAT problem. In this case, the distinguishing models of the formula are the assignments to the RBF relation. Thus, after each satisfiability check iteration of the Alloy Analyzer, an additional constraint is added in order to block the current assignment to the RBF relation. This procedure is performed until the model becomes unsatisfiable.
As described in Sect. 3.1, our formal model does not encode the concrete values of each memory operation; thus, the extraction of a valid execution, given a satisfiable assignment to the formula, requires an additional step. This step is to reconstruct the values of each read or modify operation based on the program and the assignment to the RBF relation. For example, given the program in Fig. 1, and assuming that the RBF relation contains the tuples \((ev_3R^2, ev_2W^2, 0)\) and \((ev_3R^2, ev_6W^3, 1)\), the reconstruction of the value read by \(ev_3R^2\) depends on the fact that \(ev_2W^2\) writes 1 with an 8bit integer encoding at position 0, while \(ev_6W^3\) writes 3 at position 1. The composition of byte 0 and byte 1 from those two writes is the input for the decoding of a 16bit integer for the event \(ev_3R^2\), resulting in a read of the value 769. Clearly, each event could also have a different size and format (i.e., integer, unsigned integer, or float); thus, the reconstruction of the correct value must also take this into account.
When interpreting a program containing ifthenelse statements, the possible outcomes must be filtered to exclude executions that break the semantics of ifthenelse. In particular, it might be the case that the Boolean condition in the model does not match the concrete value, given the read values. For instance, consider the example in Fig. 6 in which the conditional is encoded as a Boolean variable id1_cond representing the statement xI8[0] == 1. However, the tool may assign id1_cond to false even though the event xI8[0] turns out to read a value different from 1 based on the information in the RBF relation. In this case, this execution is discarded since it is not possible given the semantics of the ifthenelse statement.
Litmus Test Generation. The generation of all valid executions also constructs a JavaScript litmus test that can be used to evaluate whether the engine respects the semantics of the Memory Model. The structure of the litmus test mirrors that of the input program, but the syntax follows the official TEST262 ECMAScript conformance standard [11].
To check whether a test produced a valid result, the results of memory operations must be collected. The basic idea consists of printing the values of each read and collecting them all at the thread level. The main thread is then responsible for collecting all the results. The sorted report is then compared with the set of expected outputs using an assertion. Moreover, the test contains a part that is parsed by the Litmus script, which is provided along with the EMME tool, and provides a list of expected outputs. The Litmus script is used to facilitate the execution of multiple runs of the same test, and it will provide a summary of the results as well as a warning whenever one of the executions observed is a not valid according to the standard.
Generation of the Behavioral Coverage Constraints. As described in Sect. 6, for each assignment to the RBF relation, it is possible to construct a concrete value for each memory event. Thus, for each RBF assignment in a set of valid executions for a given program, we can determine the output of the corresponding litmus test. Thus, running the litmus test many times on a JavaScript engine, it is possible to determine which assignments to the RBF relation have been matched. We denote these \(\mathrm{MA\_rbf}_1, \ldots , \mathrm{MA\_rbf}_n\). The unmatched assignments to RBF can also be determined simply by removing the matched ones from the set of all valid executions. We denote the unmatched ones \(\text {UN\_rbf}_1,\) \(\ldots ,\) \(\text {UN\_rbf}_m\).
7 Experimental Evaluations
In this section, we evaluate the performance of EMME over a set of programs, each containing up to 8 memory events. The analyses can be reproduced using the package available at [16].
Programs Under Analysis. In this work, we rely on programs from previous work [6] as well as handcrafted and automatically generated programs. The handcrafted examples are part of the EMME [15] distribution, and they cover a variety of different configurations with 1 to 8 memory events, ifstatements, forloops, and parametric definitions.
The programs from previous work as well as the handcrafted examples cover an interesting set of examples, but provide no particular guarantees on the space of programs that are covered. To overcome this limitation, we implemented a tool that enumerates all possible programs of a fixed size, thus giving us the possibility of generating programs to entirely cover the space of configurations, given a fixed set of events.
All Valid Executions. As described in Sect. 6, the generation of all valid executions is based on a single AllSAT procedure. Figure 8 shows a scalability evaluation when generating all valid executions of 1200 program instances, each with from 3 to 8 memory events (200 programs for each configuration). The xaxis refers to the program number, ordered first by number of memory events, and then by increasing execution time, while the yaxis reports the execution time (in seconds on an Intel i76700 @ 3.4 GHz) on a logarithmic scale. The results show that the proposed approach is able to analyze programs with 7 memory events in fewer than 10 s, providing reasonable responsiveness to deal with small, but informative, programs.
Behavioral Coverage Constraints. For the coverage constraints analysis, we first extracted a subset of the 1200 tests, considering only the ones that could produce at least 5 different outputs. There were 288 such tests. For each test, we ran the JavaScript engine 500 times, and performed an analysis using 11 predicates, each of which corresponds to a subpart of the Memory Model, as well as some additional formulae. During this evaluation, the average computation time required to perform the behavioral coverage constraints analysis was 3.25 s, with a variance of 0.37 s.
8 Results of the Formal Analyses
In this Section we provide an overview of the results of the formal analyses for the ECMAScript Memory Model.
Circular relations definition. In the original Memory Model, a subset of the relations were specified using circular definitions. More specifically, using the notation a \(\rightarrow \) b as “the definition of a depends on b”, the loop was Synchronizes With \(\rightarrow \) Reads From \(\rightarrow \) Reads Bytes From \(\rightarrow \) Happens Before \(\rightarrow \) Synchronizes With. Cyclic definitions can result in vacuous constraints, and in the case of binary relations, this manifests as solutions with unconstrained tuples that belong to all relations involved in the cycle. In order to solve this problem, the definition of Reads Bytes From was changed so that it no longer depends on Happens Before. In addition, the memory model was extended with a property called Valid Coherent Reads that constrains the possible tuples belonging to the Reads Bytes From relation.
Misalignment of the ComposeWriteEventBytes. The memory model defines a Reads Bytes From relation, and checks whether the tuples belonging to it are valid by relying on a function called ComposeWriteEventBytes. Given a list of writes, the ComposeWriteEventBytes function creates a vector of values associated with a read event; however, the index for each write event was not correct, resulting in a misalignment w.r.t. the Reads Bytes From relation. An additional offset was added in order to fix the problem.
Distinct events quantification. Another problem encountered while analyzing the ECMAScript memory model was caused by a series of inconsistent constraints. One example of inconsistency was in the definition of the Happens Before relation which prescribes that for any two events \(ev_1\) and \(ev_2\) with overlapping ranges, whenever \(ev_1\) is of type Init, \(ev_2\) should be of a different type (i.e., not Init). However, there was no constraint stating that \(ev_1\) and \(ev_2\) have to be distinct, and certainly, whenever \(ev_1\) and \(ev_2\) are not distinct then this expression is unsatisfiable.
A similar inconsistency was found in the definition of the Memory Order relation. In this case, if the SW relation contains the pair \((ev_1, ev_2)\), and \((ev_1, ev_2) \in \) HB, then the MO should contain \((ev_1, ev_2)\). However, this is inconsistent with another constraint requiring that no event \(ev_3\) should exist operating on the same memory addresses as \(ev_2\) such that both \((ev_1, ev_3) \in \) MO and \((ev_3, ev_2) \in \) MO. This constraint is false when \(ev_1 = ev_2 = ev_3\). Both the Happens Before and the Memory Order relations initially permitted any pairs of elements to be related (including two equal elements). The solution was to only allow pairs of distinct events in these relations.
The definition of the Reads Bytes From relation stated that each read or modify event \(ev_1R\) is associated with a list of pairs of byte indices and write or modify events. The definition did not specifically preclude allowing modify events to read from themselves. This does not cause any particular issues at the formal model level, but it is not clear what the implication at the JavaScript engine implementation level would be. In order to resolve this issue, the definition of the Reads Bytes From relation was modified to allow only events that are distinct to be related by Reads Bytes From.
Outputs coverage on ECMAScript engines. As described in Sect. 4, the litmus test analysis can result in three possible outcomes, e.g., \(E_{x}(P) {\setminus } { VE}(P) \ne \emptyset \) when the engine violates the specification, \(E_{x}(P) = { VE}(P)\) when the engine matches the specification, and \(E_{x}(P) \subset { VE}(P)\) when the engine is more restrictive than the specification. Typically, such an analysis is designed to find bugs in the software implementation of the memory model [4, 6], focusing on the first case (\(E_{x}(P) {\setminus } { VE}(P) \ne \emptyset \)). However, in this project, the last case was most prevalent, where \(E_{x}(P)\) is significantly smaller than \({ VE}(P)\).
For instance, when we ran the 288 examples with at least 5 possible outputs (from Sect. 7) 1000 times for each combination of program and JavaScript engine, the overall output coverage reached \(75\%\), but for 1/6 of the examples, the coverage did not exceed \(50\%\), and some were even below \(15\%\)^{2}.
This situation (frequently having far fewer observed behaviors than allowed behaviors) guided our development of alternative analyses, such as the generation of the behavioral coverage constraints, to help developers understand the relationship between an engine’s implementation and the memory model specification. Future improvements of JavaScript engines will likely be less conservative, meaning that more behaviors will be covered. The tests produced in this project will be essential to ensure that no bugs are introduced. Currently, we are in the process of adapting the litmus tests so that they can be included as part of the official TEST262 test suite for the ECMAScript Memory Model.
9 Conclusion
Extending JavaScript, the language used by nearly all webbased interfaces, to support shared memory operations warrants the use of extensive verification techniques. In this work, we have presented a tool that has been developed in order to support the design and development of the ECMAScript Memory Model. The formal analysis of the original specification allowed us to identify a number of potential issues and inconsistencies. The evaluation of the valid executions and litmus tests coverage analysis identified a conservative level of optimization in current engine implementations. This situation motivated us to develop a specific technique for understanding differences between the Memory Model specification and JavaScript engine implementations.
Future extensions to this work will consider providing additional techniques to help developers improve code optimizations in JavaScript engines. Techniques such as the synthesis of equivalent programs, and automated value instantiation given a parametric program will provide additional analytical capabilities able to identify possible directions for code optimization. Moreover, we will also consider integration with other constraint solving engines in order to deal with more complex programs.
Footnotes
 1.
The complete Alloy model is available at https://github.com/FMJS/EMME/blob/master/model/memory_model.als.
 2.
On an x86 machine, and with the latest version of the engines available on October 1st, 2017.
References
 1.Chrome V8: Google’s High Performance, Open Source, JavaScript Engine (2017). https://developers.google.com/v8/
 2.JavaScriptCore: Is the Builtin JavaScript Engine for WebKit (2017). https://developer.apple.com/reference/javascriptcore
 3.SpiderMonkey: Mozilla’s JavaScript Engine (2017). https://developer.mozilla.org/enUS/docs/Mozilla/Projects/SpiderMonkey
 4.Alglave, J.: A shared memory poetics. Ph.D. thesis, lUniversitè Paris 7 Denis Diderot, Paris, France, 11 2010Google Scholar
 5.Atig, M.F., Bouajjani, A., Burckhardt, S., Musuvathi, M.: On the verification problem for weak memory models. ACM SIGPLAN Not. 45(1), 7–18 (2010)CrossRefGoogle Scholar
 6.Batty, M.: The C11 and C++11 concurrency model. Ph.D. thesis, University of Kent, Canterbury, UK, 1 2015Google Scholar
 7.Batty, M., Owens, S., Sarkar, S., Sewell, P., Weber, T.: Mathematizing C++ concurrency. ACM SIGPLAN Not. 46, 55–66 (2011)CrossRefGoogle Scholar
 8.Bryant, R.E.: Symbolic Boolean manipulation with ordered binarydecision diagrams. ACM Comput. Surv. 24(3), 293–318 (1992)MathSciNetCrossRefGoogle Scholar
 9.Burckhardt, S., Alur, R., Martin, M.M.: Checkfence: checking consistency of concurrent data types on relaxed memory models. ACM SIGPLAN Not. 42, 12–21 (2007)CrossRefGoogle Scholar
 10.ECMA TC39 Committee: ECMAScript Shared Memory and Atomics (2016). https://tc39.github.io/ecmascript_sharedmem/shmem.html
 11.ECMA TC39 Committee: Official ECMAScript Conformance Test Suite (2017). https://github.com/tc39/test262
 12.Jackson, D.: Alloy: a lightweight object modelling notation. ACM Trans. Softw. Eng. Methodol. 11(2), 256–290 (2002)CrossRefGoogle Scholar
 13.Jackson, D.: Alloy: A Language & Tool for Relational Models (2017). http://alloy.mit.edu/alloy/
 14.Lustig, D., Wright, A., Papakonstantinou, A., Giroux, O.: Automated synthesis of comprehensive memory model litmus test suites. In: Proceedings of the TwentySecond International Conference on Architectural Support for Programming Languages and Operating Systems, ASPLOS 2017, pp. 661–675. ACM, New York (2017)Google Scholar
 15.Mattarei, C.: EMME: ECMAScript Memory Model Evaluator (2017). https://github.com/fmjs/EMME
 16.Mattarei, C., Barrett, C., Guo, S.Y., Nelson, B., Smith, B.: Artifact Evaluation for the ECMAScript Memory Model Evaluator (EMME) Tool (2018). https://doi.org/10.6084/m9.figshare.5923312.v1
 17.Owens, S., Böhm, P., Zappa Nardelli, F., Sewell, P.: Lem: a lightweight tool for heavyweight semantics. In: van Eekelen, M., Geuvers, H., Schmaltz, J., Wiedijk, F. (eds.) ITP 2011. LNCS, vol. 6898, pp. 363–369. Springer, Heidelberg (2011). https://doi.org/10.1007/9783642228636_27CrossRefGoogle Scholar
 18.ten Dijke, N.: Comparison of verification methods for weak memory models (2014)Google Scholar
 19.Torlak, E., Vaziri, M., Dolby, J.: MemSAT: checking axiomatic specifications of memory models. ACM SIGPLAN Not. 45, 341–350 (2010)CrossRefGoogle Scholar
 20.W3C Web Application Working Group. Web Workers Specification (2012). https://www.w3.org/TR/2012/CRworkers20120501
Copyright information
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made. The images or other third party material in this book are included in the book's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the book's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.