Changeset 55002 in webkit for trunk/JavaScriptCore/interpreter


Ignore:
Timestamp:
Feb 18, 2010, 10:23:25 PM (15 years ago)
Author:
[email protected]
Message:

2010-02-18 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Improve interpreter getter performance
https://bugs.webkit.org/show_bug.cgi?id=35138

Improve the performance of getter dispatch by making it possible
for the interpreter to cache the GetterSetter object lookup.

To do this we simply need to make PropertySlot aware of getters
as a potentially cacheable property, and record the base and this
objects for a getter access. This allows us to use more-or-less
identical code to that used by the normal get_by_id caching, with
the dispatch being the only actual difference.

I'm holding off of implementing this in the JIT until I do some
cleanup to try and making coding in the JIT not be as horrible
as it is currently.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures): (JSC::CodeBlock::refStructures):
  • bytecode/Opcode.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::resolveGlobal): (JSC::Interpreter::tryCacheGetByID): (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass):
  • jit/JITStubs.cpp: (JSC::JITThunks::tryCacheGetByID): (JSC::DEFINE_STUB_FUNCTION):
  • runtime/JSObject.cpp: (JSC::JSObject::fillGetterPropertySlot):
  • runtime/PropertySlot.cpp: (JSC::PropertySlot::functionGetter):
  • runtime/PropertySlot.h: (JSC::PropertySlot::isGetter): (JSC::PropertySlot::isCacheable): (JSC::PropertySlot::isCacheableValue): (JSC::PropertySlot::setValueSlot): (JSC::PropertySlot::setGetterSlot): (JSC::PropertySlot::setCacheableGetterSlot): (JSC::PropertySlot::clearOffset): (JSC::PropertySlot::thisValue):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r54843 r55002  
    4141#include "EvalCodeCache.h"
    4242#include "ExceptionHelpers.h"
     43#include "GetterSetter.h"
    4344#include "GlobalEvalFunction.h"
    4445#include "JSActivation.h"
     
    170171    if (globalObject->getPropertySlot(callFrame, ident, slot)) {
    171172        JSValue result = slot.getValue(callFrame, ident);
    172         if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
     173        if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
    173174            if (vPC[4].u.structure)
    174175                vPC[4].u.structure->deref();
     
    10301031
    10311032    if (slot.slotBase() == baseValue) {
    1032         vPC[0] = getOpcode(op_get_by_id_self);
     1033        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_self) : getOpcode(op_get_by_id_self);
    10331034        vPC[5] = slot.cachedOffset();
    10341035
     
    10571058        ASSERT(!baseObject->structure()->isUncacheableDictionary());
    10581059
    1059         vPC[0] = getOpcode(op_get_by_id_proto);
     1060        vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_proto) : getOpcode(op_get_by_id_proto);
    10601061        vPC[5] = baseObject->structure();
    10611062        vPC[6] = offset;
     
    10721073    }
    10731074
    1074     vPC[0] = getOpcode(op_get_by_id_chain);
     1075    vPC[0] = slot.isGetter() ? getOpcode(op_get_by_id_getter_chain) : getOpcode(op_get_by_id_chain);
    10751076    vPC[4] = structure;
    10761077    vPC[5] = structure->prototypeChain(callFrame);
     
    21622163        NEXT_INSTRUCTION();
    21632164    }
     2165#if HAVE(COMPUTED_GOTO)
     2166    goto *(&&skip_id_getter_proto);
     2167#endif
     2168    DEFINE_OPCODE(op_get_by_id_getter_proto) {
     2169        /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
     2170         
     2171         Cached property access: Attempts to get a cached getter property from the
     2172         value base's prototype. If the cache misses, op_get_by_id_getter_proto
     2173         reverts to op_get_by_id.
     2174         */
     2175        int base = vPC[2].u.operand;
     2176        JSValue baseValue = callFrame->r(base).jsValue();
     2177       
     2178        if (LIKELY(baseValue.isCell())) {
     2179            JSCell* baseCell = asCell(baseValue);
     2180            Structure* structure = vPC[4].u.structure;
     2181           
     2182            if (LIKELY(baseCell->structure() == structure)) {
     2183                ASSERT(structure->prototypeForLookup(callFrame).isObject());
     2184                JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
     2185                Structure* prototypeStructure = vPC[5].u.structure;
     2186               
     2187                if (LIKELY(protoObject->structure() == prototypeStructure)) {
     2188                    int dst = vPC[1].u.operand;
     2189                    int offset = vPC[6].u.operand;
     2190                    if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
     2191                        JSObject* getter = getterSetter->getter();
     2192                        CallData callData;
     2193                        CallType callType = getter->getCallData(callData);
     2194                        JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
     2195                        CHECK_FOR_EXCEPTION();
     2196                        callFrame->r(dst) = result;
     2197                    } else
     2198                        callFrame->r(dst) = jsUndefined();
     2199                    vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
     2200                    NEXT_INSTRUCTION();
     2201                }
     2202            }
     2203        }
     2204        uncacheGetByID(callFrame->codeBlock(), vPC);
     2205        NEXT_INSTRUCTION();
     2206    }
     2207#if HAVE(COMPUTED_GOTO)
     2208    skip_id_getter_proto:
     2209#endif
    21642210    DEFINE_OPCODE(op_get_by_id_self_list) {
    21652211        // Polymorphic self access caching currently only supported when JITting.
     
    21762222        NEXT_INSTRUCTION();
    21772223    }
     2224    DEFINE_OPCODE(op_get_by_id_getter_self_list) {
     2225        // Polymorphic self access caching currently only supported when JITting.
     2226        ASSERT_NOT_REACHED();
     2227        // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
     2228        vPC += OPCODE_LENGTH(op_get_by_id_self_list);
     2229        NEXT_INSTRUCTION();
     2230    }
     2231    DEFINE_OPCODE(op_get_by_id_getter_proto_list) {
     2232        // Polymorphic prototype access caching currently only supported when JITting.
     2233        ASSERT_NOT_REACHED();
     2234        // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
     2235        vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
     2236        NEXT_INSTRUCTION();
     2237    }
    21782238    DEFINE_OPCODE(op_get_by_id_chain) {
    21792239        /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
     
    22222282        NEXT_INSTRUCTION();
    22232283    }
     2284#if HAVE(COMPUTED_GOTO)
     2285    goto *(&&skip_id_getter_self);
     2286#endif
     2287    DEFINE_OPCODE(op_get_by_id_getter_self) {
     2288        /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
     2289         
     2290         Cached property access: Attempts to get a cached property from the
     2291         value base. If the cache misses, op_get_by_id_getter_self reverts to
     2292         op_get_by_id.
     2293         */
     2294        int base = vPC[2].u.operand;
     2295        JSValue baseValue = callFrame->r(base).jsValue();
     2296       
     2297        if (LIKELY(baseValue.isCell())) {
     2298            JSCell* baseCell = asCell(baseValue);
     2299            Structure* structure = vPC[4].u.structure;
     2300           
     2301            if (LIKELY(baseCell->structure() == structure)) {
     2302                ASSERT(baseCell->isObject());
     2303                JSObject* baseObject = asObject(baseCell);
     2304                int dst = vPC[1].u.operand;
     2305                int offset = vPC[5].u.operand;
     2306
     2307                if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
     2308                    JSObject* getter = getterSetter->getter();
     2309                    CallData callData;
     2310                    CallType callType = getter->getCallData(callData);
     2311                    JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
     2312                    CHECK_FOR_EXCEPTION();
     2313                    callFrame->r(dst) = result;
     2314                } else
     2315                    callFrame->r(dst) = jsUndefined();
     2316
     2317                vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
     2318                NEXT_INSTRUCTION();
     2319            }
     2320        }
     2321        uncacheGetByID(callFrame->codeBlock(), vPC);
     2322        NEXT_INSTRUCTION();
     2323    }
     2324#if HAVE(COMPUTED_GOTO)
     2325    skip_id_getter_self:
     2326#endif
    22242327    DEFINE_OPCODE(op_get_by_id_generic) {
    22252328        /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
     
    22422345        NEXT_INSTRUCTION();
    22432346    }
     2347#if HAVE(COMPUTED_GOTO)
     2348    goto *(&&skip_id_getter_chain);
     2349#endif
     2350    DEFINE_OPCODE(op_get_by_id_getter_chain) {
     2351        /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
     2352         
     2353         Cached property access: Attempts to get a cached property from the
     2354         value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
     2355         reverts to op_get_by_id.
     2356         */
     2357        int base = vPC[2].u.operand;
     2358        JSValue baseValue = callFrame->r(base).jsValue();
     2359       
     2360        if (LIKELY(baseValue.isCell())) {
     2361            JSCell* baseCell = asCell(baseValue);
     2362            Structure* structure = vPC[4].u.structure;
     2363           
     2364            if (LIKELY(baseCell->structure() == structure)) {
     2365                RefPtr<Structure>* it = vPC[5].u.structureChain->head();
     2366                size_t count = vPC[6].u.operand;
     2367                RefPtr<Structure>* end = it + count;
     2368               
     2369                while (true) {
     2370                    JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
     2371                   
     2372                    if (UNLIKELY(baseObject->structure() != (*it).get()))
     2373                        break;
     2374                   
     2375                    if (++it == end) {
     2376                        int dst = vPC[1].u.operand;
     2377                        int offset = vPC[7].u.operand;
     2378                        if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
     2379                            JSObject* getter = getterSetter->getter();
     2380                            CallData callData;
     2381                            CallType callType = getter->getCallData(callData);
     2382                            JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
     2383                            CHECK_FOR_EXCEPTION();
     2384                            callFrame->r(dst) = result;
     2385                        } else
     2386                            callFrame->r(dst) = jsUndefined();
     2387                        vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
     2388                        NEXT_INSTRUCTION();
     2389                    }
     2390                   
     2391                    // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
     2392                    baseCell = baseObject;
     2393                }
     2394            }
     2395        }
     2396        uncacheGetByID(callFrame->codeBlock(), vPC);
     2397        NEXT_INSTRUCTION();
     2398    }
     2399#if HAVE(COMPUTED_GOTO)
     2400    skip_id_getter_chain:
     2401#endif
    22442402    DEFINE_OPCODE(op_get_array_length) {
    22452403        /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
Note: See TracChangeset for help on using the changeset viewer.