• No results found

Cachable Profiling Information

Cachable profiling information consists of data that is gathered by the JavaScript engine’s online profiler that is not dependent on the current state of the heap or any data structure that resides in memory. Thus, this information can easily be stored in an external database and used by other JavaScript engines. In this section we describe which information gathered by the online profiler can be considered cachable and how it is used.

Primitive types. Primitive types as recorded by the profiler are used to type-specialize

code generated by the optimizing compiler. A simple example is the addition operator. If the profiler records at a certain program point that the types of the two operands for

1The program is not actual server-side code, which is event-driven and would unnecessarily complicate

(1) function hotFun(a, obj) {

(2) var inc = a + 1;

(3) inc = obj.x + bar();

(4) return inc;

}

(5) function bar() {

(6) return SOME_INT_VALUE;

}

(7) var point = {x:0, y:0};

(8) var zpoint = {x:0, y:0, z:0};

(9) var ind = 0;

(10) for (;ind < 2000; ++ind){

(11) if (ind < 100) (12) hotFunc(ind, point) (13) else if (ind < 500) (14) hotFunc(ind, zpoint); (15) else (16) hotFunc(2.5, zpoint) }

Figure 5.6: Functions hotFun and bar are invoked 2,000 times. hotFun becomes hot after 1,000 iterations. The online profiler captures profile information at lines 2 and 3 for the function hotFun which is used by the optimizing compiler to optimize it.

that operator have always been integers, the optimizing compiler can use this informa- tion to generate type-specialized integer arithmetic code. Because primitive types like int, bool, double, null, and undefined can be represented using simple enum- like constructs, it is easy to capture them in the profiling database. The information that is captured in the database is of the format <filename, lineNo, columnNo, pcOffset, type>, where the first three fields designate a unique function, the fourth field designates a point within that function, and the last field designates the enum value representing a primitive type.

In the running example from Section 5.4.1, for the first 500 iterations the profiler records a to be int at line number 2, obj.x and the return value of bar to be int at line 3, and the resultant type of the addition at lines 2 and 3 to be ints. For the remaining iterations, the profiler records that a is a double.

Deoptimization information. The profiler records function deoptimization information

in order to keep track of how effective the engine’s optimization decisions were. De- optimization happens when an assumption made by the optimizing compiler (based on information provided by the profiler) turns out to be incorrect, rendering the optimized code invalid and requiring the engine to revert back to the unoptimized code. This can happen for a number of reasons. The ones we focus on in this chapter are:

1. A new primitive type could be observed in future invocations of the function that wasn’t seen in previous invocations.

2. An overflow could occur after an arithmetic operation which was assumed to result in an integer but now requires a floating point value.

3. Array bounds could have been violated after having the bounds checks optimized out.

4. Fast object property access could fail to account for new object shapes that are seen in future invocations.

Information about the above problems can potentially enable the optimizing compiler to make better decisions while generating the optimized code:

1. If a new primitive type is observed after type specialization, the profile database records the new type along with the program point where it occurred. The optimizer for the newly spawned engine can then account for that type when the function is compiled. The program point is represented as a tuple <filename, lineNo, columnNo, pcOffset>, where the first three fields designate a unique function and the last field designates a point within that function. The profile database, then, contains a mapping from program points to sets of observed primitive types that caused deoptimization.

2. If an arithmetic operation causes integer overflow and thus deoptimization then the profile database records the program point where that happened along with a flag indicating the integer overflow problem. The optimizer for the newly spawned engines can then take care to use floating point operations instead of integer oper- ations, thus avoiding the deoptimization.

3. If an array access at a particular program point causes deoptimization then the profile database records that fact and the newly spawned engine uses it similarly to integer overflow as described above.

4. If an unanticipated object shape causes deoptimization (because the object does not have the proper layout assumed by the optimizer) then again the program point is recorded in the profile database and the newly spawned engine’s optimizer uses

this information to avoid using the fast object property access code that assumes a specific layout, thus avoiding the deoptimization.

In the running example, if we assume that bar returns a large int value that caused an integer overflow during the execution of function hotFun during the monitoring run, the profile database can be updated with this information so that in the subsequent runs the optimizing compiler can generate code to avoid deoptimizations due to overflow.

Inlining information. The JavaScript engine’s optimizing compiler uses heuristics to

decide whether to inline callee functions at certain program points. These heuristics are based on size and hotness of the callee function. At the time the caller function is optimized, if the callee function is not marked as hot and it is considered too large then it will not be inlined into the caller function.

However, it may happen that the callee function becomes hot after the caller function is optimized. This is a missed opportunity for optimization. The profile database records instances where a callee function at a certain program point was not inlined and yet later became hot; the newly spawned engine’s optimizer can use this information to make a better inlining decision for itself.

Related documents