Ignore:
Timestamp:
Sep 1, 2008, 2:22:54 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


SunSpider says 4% faster. Tests heavy on dictionary-like access have
regressed a bit -- we have a lot of room to improve in this area,
but this patch is over-ripe as-is.


JSCells now have a StructureID that uniquely identifies their layout,
and holds their prototype.


JSValue::put takes a PropertySlot& argument, so it can fill in details
about where it put a value, for the sake of caching.

  • VM/CodeGenerator.cpp: (KJS::CodeGenerator::CodeGenerator): Avoid calling removeDirect if we can, since it disables inline caching in the global object. This can probably improve in the future.
  • kjs/JSGlobalObject.cpp: Nixed reset(), since it complicates caching, and wasn't really necessary.
  • kjs/JSObject.cpp: Tweaked getter / setter behavior not to rely on the IsGetterSetter flag, since the flag was buggy. This is necessary in order to avoid accidentally accessing a getter / setter as a normal property.


Also changed getter / setter creation to honor ReadOnly, matching Mozilla.


  • kjs/PropertyMap.cpp: Nixed clear(), since it complicates caching and isn't necessary.
  • kjs/Shell.cpp: Moved SamplingTool dumping outside the loop. This allows you to aggregate sampling of multiple files (or the same file repeatedly), which helped me track down regressions.
  • kjs/ustring.h: Moved IdentifierRepHash here to share it.

WebCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.

Updated for JavaScriptCore changes. Mostly mechanical addition of StructureIDs
to WebCore classes, and PutPropertySlot& arguments to put functions.

(WebCore::JSCSSStyleDeclaration::customPut): Be sure to play nice with
inline caching for global properties, so global assignment can be optimized.

  • ForwardingHeaders/kjs/StructureID.h: Added.
  • bindings/js/JSDOMBinding.h: (WebCore::DOMObject::DOMObject):
  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::put):
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWindowCustom.h: (WebCore::JSDOMWindow::customPut):
  • bindings/js/JSDOMWindowShell.cpp: (WebCore::JSDOMWindowShell::JSDOMWindowShell): (WebCore::JSDOMWindowShell::put):
  • bindings/js/JSDOMWindowShell.h:
  • bindings/js/JSEventTargetBase.h: (WebCore::JSEventTargetBase::put):
  • bindings/js/JSEventTargetNode.h: (WebCore::JSEventTargetNode::put):
  • bindings/js/JSHTMLAppletElementCustom.cpp: (WebCore::JSHTMLAppletElement::customPut):
  • bindings/js/JSHTMLEmbedElementCustom.cpp: (WebCore::JSHTMLEmbedElement::customPut):
  • bindings/js/JSHTMLInputElementBase.cpp: (WebCore::JSHTMLInputElementBase::put):
  • bindings/js/JSHTMLInputElementBase.h:
  • bindings/js/JSHTMLObjectElementCustom.cpp: (WebCore::JSHTMLObjectElement::customPut):
  • bindings/js/JSHistoryCustom.cpp: (WebCore::JSHistory::customPut):
  • bindings/js/JSInspectedObjectWrapper.cpp: (WebCore::JSInspectedObjectWrapper::wrap): (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
  • bindings/js/JSInspectedObjectWrapper.h:
  • bindings/js/JSInspectorCallbackWrapper.cpp: (WebCore::JSInspectorCallbackWrapper::wrap): (WebCore::JSInspectorCallbackWrapper::JSInspectorCallbackWrapper):
  • bindings/js/JSInspectorCallbackWrapper.h:
  • bindings/js/JSLocationCustom.cpp: (WebCore::JSLocation::customPut):
  • bindings/js/JSPluginElementFunctions.cpp: (WebCore::runtimeObjectCustomPut):
  • bindings/js/JSPluginElementFunctions.h:
  • bindings/js/JSQuarantinedObjectWrapper.cpp: (WebCore::JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper): (WebCore::JSQuarantinedObjectWrapper::put):
  • bindings/js/JSQuarantinedObjectWrapper.h:
  • bindings/js/JSStorageCustom.cpp: (WebCore::JSStorage::customPut):
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject setValue:forKey:]):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/NP_jsobject.cpp: (_NPN_SetProperty):
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::setMember):
  • bridge/objc/objc_class.mm: (KJS::Bindings::ObjcClass::fallbackObject):
  • bridge/objc/objc_runtime.h:
  • bridge/objc/objc_runtime.mm: (ObjcFallbackObjectImp::ObjcFallbackObjectImp): (ObjcFallbackObjectImp::put):
  • bridge/runtime.cpp: (KJS::Bindings::Instance::createRuntimeObject):
  • bridge/runtime_array.cpp: (RuntimeArray::put):
  • bridge/runtime_array.h:
  • bridge/runtime_object.cpp: (RuntimeObjectImp::RuntimeObjectImp): (RuntimeObjectImp::put):
  • bridge/runtime_object.h:

LayoutTests:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


Tests for things I broke along the way.


  • fast/dom/getter-on-window-object2-expected.txt:
  • fast/js/pic: Added.
  • fast/js/pic/cached-deleted-properties-expected.txt: Added.
  • fast/js/pic/cached-deleted-properties.html: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto-expected.txt: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto.html: Added.
  • fast/js/pic/cached-getter-setter-expected.txt: Added.
  • fast/js/pic/cached-getter-setter.html: Added.
  • fast/js/pic/cached-prototype-setter-expected.txt: Added.
  • fast/js/pic/cached-prototype-setter.html: Added.
  • fast/js/pic/cached-single-entry-transition-expected.txt: Added.
  • fast/js/pic/cached-single-entry-transition.html: Added.
  • fast/js/pic/get-empty-string-expected.txt: Added.
  • fast/js/pic/get-empty-string.html: Added.
  • fast/js/pic/get-set-proxy-object-expected.txt: Added.
  • fast/js/pic/get-set-proxy-object.html: Added.
  • fast/js/pic/rehash-poisons-structure-expected.txt: Added.
  • fast/js/pic/rehash-poisons-structure.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CodeBlock.cpp

    r35810 r36016  
    3838namespace KJS {
    3939
    40 #if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
     40#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
    4141
    4242static UString escapeQuotes(const UString& str)
     
    6666    if (r < 0)
    6767        return (UString("lr") + UString::from(-r)).UTF8String();
     68       
     69    if (r == missingThisObjectMarker())
     70        return "<null>";
    6871
    6972    return (UString("tr") + UString::from(r)).UTF8String();
     
    9699{
    97100    return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
     101}
     102
     103static UString pointerToSourceString(void* p)
     104{
     105    char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
     106    snprintf(buffer, sizeof(buffer), "%p", p);
     107    return buffer;
    98108}
    99109
     
    147157}
    148158
     159static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
     160{
     161    int r0 = (++it)->u.operand;
     162    int r1 = (++it)->u.operand;
     163    int id0 = (++it)->u.operand;
     164    printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
     165    it += 4;
     166}
     167
     168static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
     169{
     170    int r0 = (++it)->u.operand;
     171    int id0 = (++it)->u.operand;
     172    int r1 = (++it)->u.operand;
     173    printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
     174    it += 2;
     175}
     176
     177void CodeBlock::printStructureID(const char* name, const Instruction* vPC, int operand) const
     178{
     179    printf("  [%4d] %s: %s\n", vPC - instructions.begin(), name, pointerToSourceString(vPC[operand].u.structureID).UTF8String().c_str());
     180}
     181
     182void CodeBlock::printStructureIDs(const Instruction* vPC) const
     183{
     184    Machine* machine = globalData->machine;
     185
     186    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id)) {
     187        printStructureID("get_by_id", vPC, 4);
     188        return;
     189    }
     190    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
     191        printStructureID("get_by_id_self", vPC, 4);
     192        return;
     193    }
     194    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
     195        printf("  [%4d] %s: %s, %s\n", vPC - instructions.begin(), "get_by_id_proto", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str());
     196        return;
     197    }
     198    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
     199        printf("  [%4d] %s: %s, %s\n", vPC - instructions.begin(), "get_by_id_chain", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureIDChain).UTF8String().c_str());
     200        return;
     201    }
     202    if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id)) {
     203        printStructureID("put_by_id", vPC, 4);
     204        return;
     205    }
     206    if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
     207        printStructureID("put_by_id_replace", vPC, 4);
     208        return;
     209    }
     210
     211    // These instructions doesn't ref StructureIDs.
     212    ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
     213}
     214
    149215void CodeBlock::dump(ExecState* exec) const
    150216{
     
    201267    }
    202268
     269    if (structureIDInstructions.size()) {
     270        printf("\nStructureIDs:\n");
     271        size_t i = 0;
     272        do {
     273            printStructureIDs(&instructions[structureIDInstructions[i]]);
     274            ++i;
     275        } while (i < structureIDInstructions.size());
     276    }
     277
    203278    if (exceptionHandlers.size()) {
    204279        printf("\nException Handlers:\n");
    205280        unsigned i = 0;
    206281        do {
    207             printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i+1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
     282            printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
    208283            ++i;
    209284        } while (i < exceptionHandlers.size());
     
    211286   
    212287    if (immediateSwitchJumpTables.size()) {
    213         printf("immediate switch jump tables:\n");
     288        printf("Immediate Switch Jump Tables:\n");
    214289        unsigned i = 0;
    215290        do {
    216             printf("\t{\n");
     291            printf("  %1d = {\n", i);
    217292            int entry = 0;
    218293            Vector<int32_t>::const_iterator end = immediateSwitchJumpTables[i].branchOffsets.end();
    219             for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry)
    220                 if (*iter)
    221                     printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
    222             printf("\t}\n");
     294            for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
     295                if (!*iter)
     296                    continue;
     297                printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
     298            }
     299            printf("      }\n");
    223300            ++i;
    224301        } while (i < immediateSwitchJumpTables.size());
     
    226303   
    227304    if (characterSwitchJumpTables.size()) {
    228         printf("\ncharacter switch jump tables:\n");
     305        printf("\nCharacter Switch Jump Tables:\n");
    229306        unsigned i = 0;
    230307        do {
    231             printf("\t{\n");
     308            printf("  %1d = {\n", i);
    232309            int entry = 0;
    233310            Vector<int32_t>::const_iterator end = characterSwitchJumpTables[i].branchOffsets.end();
    234311            for (Vector<int32_t>::const_iterator iter = characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
     312                if (!*iter)
     313                    continue;
    235314                ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
    236                 UChar ch = static_cast<UChar>(i + characterSwitchJumpTables[i].min);
     315                UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
    237316                printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
    238317            }
    239             printf("\t}\n");
     318            printf("      }\n");
    240319            ++i;
    241320        } while (i < characterSwitchJumpTables.size());
     
    243322   
    244323    if (stringSwitchJumpTables.size()) {
    245         printf("\nstring switch jump tables:\n");
     324        printf("\nString Switch Jump Tables:\n");
    246325        unsigned i = 0;
    247326        do {
    248             printf("\t{\n");
     327            printf("  %1d = {\n", i);
    249328            StringJumpTable::const_iterator end = stringSwitchJumpTables[i].end();
    250329            for (StringJumpTable::const_iterator iter = stringSwitchJumpTables[i].begin(); iter != end; ++iter)
    251330                printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second);
    252             printf("\t}\n");
     331            printf("      }\n");
    253332            ++i;
    254333        } while (i < stringSwitchJumpTables.size());
     
    423502            int index = (++it)->u.operand;
    424503            int skipLevels = (++it)->u.operand;
    425             printf("[%4d] get_scoped_var\t\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
     504            printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
    426505            break;
    427506        }
     
    430509            int skipLevels = (++it)->u.operand;
    431510            int r0 = (++it)->u.operand;
    432             printf("[%4d] put_scoped_var\t\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
     511            printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
    433512            break;
    434513        }
     
    454533        }
    455534        case op_get_by_id: {
    456             int r0 = (++it)->u.operand;
    457             int r1 = (++it)->u.operand;
    458             int id0 = (++it)->u.operand;
    459             printf("[%4d] get_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
     535            printGetByIdOp(location, it, identifiers, "get_by_id");
     536            break;
     537        }
     538        case op_get_by_id_self: {
     539            printGetByIdOp(location, it, identifiers, "get_by_id_self");
     540            break;
     541        }
     542        case op_get_by_id_proto: {
     543            printGetByIdOp(location, it, identifiers, "get_by_id_proto");
     544            break;
     545        }
     546        case op_get_by_id_chain: {
     547            printGetByIdOp(location, it, identifiers, "get_by_id_chain");
     548            break;
     549        }
     550        case op_get_by_id_generic: {
     551            printGetByIdOp(location, it, identifiers, "get_by_id_generic");
    460552            break;
    461553        }
    462554        case op_put_by_id: {
    463             int r0 = (++it)->u.operand;
    464             int id0 = (++it)->u.operand;
    465             int r1 = (++it)->u.operand;
    466             printf("[%4d] put_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
     555            printPutByIdOp(location, it, identifiers, "put_by_id");
     556            break;
     557        }
     558        case op_put_by_id_replace: {
     559            printPutByIdOp(location, it, identifiers, "put_by_id_replace");
     560            break;
     561        }
     562        case op_put_by_id_generic: {
     563            printPutByIdOp(location, it, identifiers, "put_by_id_generic");
    467564            break;
    468565        }
     
    549646            int r1 = (++it)->u.operand;
    550647            int offset = (++it)->u.operand;
    551             printf("[%4d] loop_if_less %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
     648            printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
    552649            break;
    553650        }
     
    698795}
    699796
    700 #endif // !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
     797#endif // !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
     798
     799CodeBlock::~CodeBlock()
     800{
     801    Vector<size_t>::const_iterator end = structureIDInstructions.end();
     802    for (Vector<size_t>::const_iterator it = structureIDInstructions.begin(); it != end; ++it)
     803        derefStructureIDs(&instructions[*it]);
     804}
     805
     806void CodeBlock::derefStructureIDs(Instruction* vPC) const
     807{
     808    Machine* machine = globalData->machine;
     809
     810    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
     811        vPC[4].u.structureID->deref();
     812        return;
     813    }
     814    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
     815        vPC[4].u.structureID->deref();
     816        vPC[5].u.structureID->deref();
     817        return;
     818    }
     819    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
     820        vPC[4].u.structureID->deref();
     821        vPC[5].u.structureIDChain->deref();
     822        return;
     823    }
     824    if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
     825        vPC[4].u.structureID->deref();
     826        return;
     827    }
     828   
     829    // These instructions don't ref their StructureIDs.
     830    ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
     831}
     832
     833void CodeBlock::refStructureIDs(Instruction* vPC) const
     834{
     835    Machine* machine = globalData->machine;
     836
     837    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
     838        vPC[4].u.structureID->ref();
     839        return;
     840    }
     841    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
     842        vPC[4].u.structureID->ref();
     843        vPC[5].u.structureID->ref();
     844        return;
     845    }
     846    if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
     847        vPC[4].u.structureID->ref();
     848        vPC[5].u.structureIDChain->ref();
     849        return;
     850    }
     851    if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
     852        vPC[4].u.structureID->ref();
     853        return;
     854    }
     855   
     856    // These instructions don't ref their StructureIDs.
     857    ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
     858}
    701859
    702860void CodeBlock::mark()
Note: See TracChangeset for help on using the changeset viewer.