Changeset 36016 in webkit for trunk/JavaScriptCore/VM/Machine.cpp


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/Machine.cpp

    r36006 r36016  
    475475{
    476476    if (newCodeBlock->needsFullScopeChain) {
    477         JSActivation* activation = new (exec) JSActivation(functionBodyNode, r);
     477        JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
    478478        r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
    479479
     
    540540    void* storage = fastMalloc(sizeof(CollectorBlock));
    541541
    542     JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
     542    JSArray* jsArray = new (storage) JSArray(JSArray::DummyConstruct);
    543543    m_jsArrayVptr = jsArray->vptr();
    544544    static_cast<JSCell*>(jsArray)->~JSCell();
     
    626626#endif
    627627
    628 #if !defined(NDEBUG) || HAVE(SAMPLING_TOOL)
     628#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
    629629
    630630bool Machine::isOpcode(Opcode opcode)
     
    889889    for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
    890890        const Identifier& ident = (*it).first;
    891         if (!variableObject->hasProperty(exec, ident))
    892             variableObject->put(exec, ident, jsUndefined());
     891        if (!variableObject->hasProperty(exec, ident)) {
     892            PutPropertySlot slot;
     893            variableObject->put(exec, ident, jsUndefined(), slot);
     894        }
    893895    }
    894896
    895897    const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
    896898    Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
    897     for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
    898         variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
     899    for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
     900        PutPropertySlot slot;
     901        variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
     902    }
    899903
    900904    size_t oldSize = m_registerFile.size();
     
    10861090    Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
    10871091    JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
    1088     JSObject* scope = new (exec) JSStaticScopeObject(property, value, DontDelete);
     1092    JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
    10891093    r[dst] = scope;
    10901094    return scopeChain->push(scope);
     1095}
     1096
     1097StructureIDChain* cachePrototypeChain(StructureID* structureID)
     1098{
     1099    RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSCell*>(structureID->prototype())->structureID());
     1100    structureID->setCachedPrototypeChain(chain.release());
     1101    return structureID->cachedPrototypeChain();
     1102}
     1103
     1104NEVER_INLINE void Machine::tryCachePutByID(CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
     1105{
     1106    // Recursive invocation may already have specialized this instruction.
     1107    if (vPC[0].u.opcode != getOpcode(op_put_by_id))
     1108        return;
     1109
     1110    if (JSImmediate::isImmediate(baseValue))
     1111        return;
     1112
     1113    // Uncacheable: give up.
     1114    if (!slot.isCacheable()) {
     1115        vPC[0] = getOpcode(op_put_by_id_generic);
     1116        return;
     1117    }
     1118
     1119    // FIXME: Cache new property transitions, too.
     1120    if (slot.type() == PutPropertySlot::NewProperty) {
     1121        vPC[0] = getOpcode(op_put_by_id_generic);
     1122        return;
     1123    }
     1124   
     1125    JSCell* baseCell = static_cast<JSCell*>(baseValue);
     1126    StructureID* structureID = baseCell->structureID();
     1127
     1128    // FIXME: Remove this !structureID check once all objects have StructureIDs.
     1129    if (!structureID) {
     1130        vPC[0] = getOpcode(op_put_by_id_generic);
     1131        return;
     1132    }
     1133
     1134    if (structureID->isDictionary()) {
     1135        vPC[0] = getOpcode(op_put_by_id_generic);
     1136        return;
     1137    }
     1138
     1139    // Cache miss: record StructureID to compare against next time.
     1140    StructureID* lastStructureID = vPC[4].u.structureID;
     1141    if (structureID != lastStructureID) {
     1142        // First miss: record StructureID to compare against next time.
     1143        if (!lastStructureID) {
     1144            vPC[4] = structureID;
     1145            return;
     1146        }
     1147
     1148        // Second miss: give up.
     1149        vPC[0] = getOpcode(op_put_by_id_generic);
     1150        return;
     1151    }
     1152
     1153    // Cache hit: Specialize instruction and ref StructureIDs.
     1154
     1155    // If baseCell != slotBase, then baseCell must be a proxy for another object.
     1156    if (baseCell != slot.slotBase()) {
     1157        vPC[0] = getOpcode(op_put_by_id_generic);
     1158        return;
     1159    }
     1160    vPC[0] = getOpcode(op_put_by_id_replace);
     1161    vPC[5] = slot.cachedOffset();
     1162    codeBlock->refStructureIDs(vPC);
     1163}
     1164
     1165NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
     1166{
     1167    codeBlock->derefStructureIDs(vPC);
     1168    vPC[0] = getOpcode(op_put_by_id);
     1169    vPC[4] = 0;
     1170}
     1171
     1172NEVER_INLINE void Machine::tryCacheGetByID(CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PropertySlot& slot)
     1173{
     1174    // Recursive invocation may already have specialized this instruction.
     1175    if (vPC[0].u.opcode != getOpcode(op_get_by_id))
     1176        return;
     1177
     1178    // Uncacheable: give up.
     1179    if (!slot.isCacheable()) {
     1180        vPC[0] = getOpcode(op_get_by_id_generic);
     1181        return;
     1182    }
     1183
     1184    // FIXME: Cache property access for immediates.
     1185    if (JSImmediate::isImmediate(baseValue)) {
     1186        vPC[0] = getOpcode(op_get_by_id_generic);
     1187        return;
     1188    }
     1189
     1190    JSCell* baseCell = static_cast<JSCell*>(baseValue);
     1191    StructureID* structureID = baseCell->structureID();
     1192
     1193    // FIXME: Remove this !structureID check once all JSCells have StructureIDs.
     1194    if (!structureID) {
     1195        vPC[0] = getOpcode(op_get_by_id_generic);
     1196        return;
     1197    }
     1198
     1199    if (structureID->isDictionary()) {
     1200        vPC[0] = getOpcode(op_get_by_id_generic);
     1201        return;
     1202    }
     1203
     1204    // Cache miss
     1205    StructureID* lastStructureID = vPC[4].u.structureID;
     1206    if (structureID != lastStructureID) {
     1207        // First miss: record StructureID to compare against next time.
     1208        if (!lastStructureID) {
     1209            vPC[4] = structureID;
     1210            return;
     1211        }
     1212
     1213        // Second miss: give up.
     1214        vPC[0] = getOpcode(op_get_by_id_generic);
     1215        return;
     1216    }
     1217
     1218    // Cache hit: Specialize instruction and ref StructureIDs.
     1219
     1220    JSValue* slotBase = slot.slotBase();
     1221    if (slotBase == baseCell) {
     1222        vPC[0] = getOpcode(op_get_by_id_self);
     1223        vPC[5] = slot.cachedOffset();
     1224
     1225        codeBlock->refStructureIDs(vPC);
     1226        return;
     1227    }
     1228
     1229    if (slotBase == structureID->prototype()) {
     1230        ASSERT(!JSImmediate::isImmediate(slotBase));
     1231
     1232        vPC[0] = getOpcode(op_get_by_id_proto);
     1233        vPC[5] = static_cast<JSCell*>(slotBase)->structureID();
     1234        vPC[6] = slot.cachedOffset();
     1235
     1236        codeBlock->refStructureIDs(vPC);
     1237        return;
     1238    }
     1239
     1240    size_t count = 0;
     1241    while (baseCell != slotBase) {
     1242        baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
     1243        // If we didn't find slotBase in baseCell's prototype chain, then baseCell
     1244        // must be a proxy for another object.
     1245        if (baseCell == jsNull()) {
     1246            vPC[0] = getOpcode(op_get_by_id_generic);
     1247            return;
     1248        }
     1249        ++count;
     1250    }
     1251
     1252    StructureIDChain* chain = structureID->cachedPrototypeChain();
     1253    if (!chain)
     1254        chain = cachePrototypeChain(structureID);
     1255
     1256    vPC[0] = getOpcode(op_get_by_id_chain);
     1257    vPC[4] = structureID;
     1258    vPC[5] = chain;
     1259    vPC[6] = count;
     1260    vPC[7] = slot.cachedOffset();
     1261    codeBlock->refStructureIDs(vPC);
     1262}
     1263
     1264NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
     1265{
     1266    codeBlock->derefStructureIDs(vPC);
     1267    vPC[0] = getOpcode(op_get_by_id);
     1268    vPC[4] = 0;
    10911269}
    10921270
     
    12441422        JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
    12451423        if (JSImmediate::areBothImmediateNumbers(src1, src2))
    1246             r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
     1424            r[dst] = jsBoolean(src1 != src2);
    12471425        else {
    12481426            JSValue* result = jsBoolean(!equal(exec, src1, src2));
     
    19352113    }
    19362114    BEGIN_OPCODE(op_get_by_id) {
    1937         /* get_by_id dst(r) base(r) property(id)
    1938 
    1939            Converts register base to Object, gets the property
    1940            named by identifier property from the object, and puts the
    1941            result in register dst.
    1942         */
    1943         int dst = (++vPC)->u.operand;
    1944         int base = (++vPC)->u.operand;
    1945         int property = (++vPC)->u.operand;
     2115        /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
     2116
     2117           Generic property access: Gets the property named by identifier
     2118           property from the value base, and puts the result in register dst.
     2119        */
     2120        int dst = vPC[1].u.operand;
     2121        int base = vPC[2].u.operand;
     2122        int property = vPC[3].u.operand;
    19462123
    19472124        Identifier& ident = codeBlock->identifiers[property];
    1948         JSValue* result = r[base].jsValue(exec)->get(exec, ident);
     2125        JSValue* baseValue = r[base].jsValue(exec);
     2126        PropertySlot slot(baseValue);
     2127        JSValue* result = baseValue->get(exec, ident, slot);
    19492128        VM_CHECK_EXCEPTION();
     2129
     2130        tryCacheGetByID(codeBlock, vPC, baseValue, slot);
     2131
    19502132        r[dst] = result;
    1951         ++vPC;
     2133        vPC += 8;
     2134        NEXT_OPCODE;
     2135    }
     2136    BEGIN_OPCODE(op_get_by_id_self) {
     2137        /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
     2138
     2139           Cached property access: Attempts to get a cached property from the
     2140           value base. If the cache misses, op_get_by_id_self reverts to
     2141           op_get_by_id.
     2142        */
     2143        int base = vPC[2].u.operand;
     2144        JSValue* baseValue = r[base].jsValue(exec);
     2145
     2146        if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
     2147            JSCell* baseCell = static_cast<JSCell*>(baseValue);
     2148            StructureID* structureID = vPC[4].u.structureID;
     2149
     2150            if (LIKELY(baseCell->structureID() == structureID)) {
     2151                ASSERT(baseCell->isObject());
     2152                JSObject* baseObject = static_cast<JSObject*>(baseCell);
     2153                int dst = vPC[1].u.operand;
     2154                int offset = vPC[5].u.operand;
     2155
     2156                ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
     2157                r[dst] = baseObject->getDirectOffset(offset);
     2158
     2159                vPC += 8;
     2160                NEXT_OPCODE;
     2161            }
     2162        }
     2163
     2164        uncacheGetByID(codeBlock, vPC);
     2165        NEXT_OPCODE;
     2166    }
     2167    BEGIN_OPCODE(op_get_by_id_proto) {
     2168        /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
     2169
     2170           Cached property access: Attempts to get a cached property from the
     2171           value base's prototype. If the cache misses, op_get_by_id_proto
     2172           reverts to op_get_by_id.
     2173        */
     2174        int base = vPC[2].u.operand;
     2175        JSValue* baseValue = r[base].jsValue(exec);
     2176
     2177        if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
     2178            JSCell* baseCell = static_cast<JSCell*>(baseValue);
     2179            StructureID* structureID = vPC[4].u.structureID;
     2180
     2181            if (LIKELY(baseCell->structureID() == structureID)) {
     2182                ASSERT(structureID->prototype()->isObject());
     2183                JSObject* protoObject = static_cast<JSObject*>(structureID->prototype());
     2184                StructureID* protoStructureID = vPC[5].u.structureID;
     2185
     2186                if (LIKELY(protoObject->structureID() == protoStructureID)) {
     2187                    int dst = vPC[1].u.operand;
     2188                    int offset = vPC[6].u.operand;
     2189
     2190                    ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
     2191                    r[dst] = protoObject->getDirectOffset(offset);
     2192
     2193                    vPC += 8;
     2194                    NEXT_OPCODE;
     2195                }
     2196            }
     2197        }
     2198
     2199        uncacheGetByID(codeBlock, vPC);
     2200        NEXT_OPCODE;
     2201    }
     2202    BEGIN_OPCODE(op_get_by_id_chain) {
     2203        /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
     2204
     2205           Cached property access: Attempts to get a cached property from the
     2206           value base's prototype chain. If the cache misses, op_get_by_id_proto
     2207           reverts to op_get_by_id.
     2208        */
     2209        int base = vPC[2].u.operand;
     2210        JSValue* baseValue = r[base].jsValue(exec);
     2211
     2212        if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
     2213            JSCell* baseCell = static_cast<JSCell*>(baseValue);
     2214            StructureID* structureID = vPC[4].u.structureID;
     2215
     2216            if (LIKELY(baseCell->structureID() == structureID)) {
     2217                RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
     2218                size_t count = vPC[6].u.operand;
     2219                RefPtr<StructureID>* end = it + count;
     2220
     2221                while (1) {
     2222                    baseCell = static_cast<JSCell*>(baseCell->structureID()->prototype());
     2223                    if (UNLIKELY(baseCell->structureID() != (*it).get()))
     2224                        break;
     2225
     2226                    if (++it == end) {
     2227                        ASSERT(baseCell->isObject());
     2228                        JSObject* baseObject = static_cast<JSObject*>(baseCell);
     2229                        int dst = vPC[1].u.operand;
     2230                        int offset = vPC[7].u.operand;
     2231
     2232                        ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
     2233                        r[dst] = baseObject->getDirectOffset(offset);
     2234
     2235                        vPC += 8;
     2236                        NEXT_OPCODE;
     2237                    }
     2238                }
     2239            }
     2240        }
     2241
     2242        uncacheGetByID(codeBlock, vPC);
     2243        NEXT_OPCODE;
     2244    }
     2245    BEGIN_OPCODE(op_get_by_id_generic) {
     2246        /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
     2247
     2248           Generic property access: Gets the property named by identifier
     2249           property from the value base, and puts the result in register dst.
     2250        */
     2251        int dst = vPC[1].u.operand;
     2252        int base = vPC[2].u.operand;
     2253        int property = vPC[3].u.operand;
     2254
     2255        Identifier& ident = codeBlock->identifiers[property];
     2256        JSValue* baseValue = r[base].jsValue(exec);
     2257        PropertySlot slot(baseValue);
     2258        JSValue* result = baseValue->get(exec, ident, slot);
     2259        VM_CHECK_EXCEPTION();
     2260
     2261        r[dst] = result;
     2262        vPC += 8;
    19522263        NEXT_OPCODE;
    19532264    }
    19542265    BEGIN_OPCODE(op_put_by_id) {
    1955         /* put_by_id base(r) property(id) value(r)
     2266        /* put_by_id base(r) property(id) value(r) nop(n) nop(n)
    19562267
    19572268           Sets register value on register base as the property named
     
    19612272           the register file.
    19622273        */
    1963         int base = (++vPC)->u.operand;
    1964         int property = (++vPC)->u.operand;
    1965         int value = (++vPC)->u.operand;
    1966 
     2274
     2275        int base = vPC[1].u.operand;
     2276        int property = vPC[2].u.operand;
     2277        int value = vPC[3].u.operand;
     2278
     2279        JSValue* baseValue = r[base].jsValue(exec);
     2280
     2281        PutPropertySlot slot;
    19672282        Identifier& ident = codeBlock->identifiers[property];
    1968         r[base].jsValue(exec)->put(exec, ident, r[value].jsValue(exec));
    1969 
     2283        baseValue->put(exec, ident, r[value].jsValue(exec), slot);
    19702284        VM_CHECK_EXCEPTION();
    1971         ++vPC;
     2285
     2286        tryCachePutByID(codeBlock, vPC, baseValue, slot);
     2287
     2288        vPC += 6;
     2289        NEXT_OPCODE;
     2290    }
     2291    BEGIN_OPCODE(op_put_by_id_replace) {
     2292        /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n)
     2293
     2294           Sets register value on register base as the property named
     2295           by identifier property. Base is converted to object first.
     2296
     2297           Unlike many opcodes, this one does not write any output to
     2298           the register file.
     2299        */
     2300        int base = vPC[1].u.operand;
     2301        JSValue* baseValue = r[base].jsValue(exec);
     2302
     2303        if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
     2304            JSCell* baseCell = static_cast<JSCell*>(baseValue);
     2305            StructureID* structureID = vPC[4].u.structureID;
     2306
     2307            if (LIKELY(baseCell->structureID() == structureID)) {
     2308                ASSERT(baseCell->isObject());
     2309                JSObject* baseObject = static_cast<JSObject*>(baseCell);
     2310                int value = vPC[3].u.operand;
     2311                unsigned offset = vPC[5].u.operand;
     2312               
     2313                ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
     2314                baseObject->putDirectOffset(offset, r[value].jsValue(exec));
     2315
     2316                vPC += 6;
     2317                NEXT_OPCODE;
     2318            }
     2319        }
     2320
     2321        uncachePutByID(codeBlock, vPC);
     2322        NEXT_OPCODE;
     2323    }
     2324    BEGIN_OPCODE(op_put_by_id_generic) {
     2325        /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n)
     2326
     2327           Sets register value on register base as the property named
     2328           by identifier property. Base is converted to object first.
     2329
     2330           Unlike many opcodes, this one does not write any output to
     2331           the register file.
     2332        */
     2333        int base = vPC[1].u.operand;
     2334        int property = vPC[2].u.operand;
     2335        int value = vPC[3].u.operand;
     2336
     2337        JSValue* baseValue = r[base].jsValue(exec);
     2338
     2339        PutPropertySlot slot;
     2340        Identifier& ident = codeBlock->identifiers[property];
     2341        baseValue->put(exec, ident, r[value].jsValue(exec), slot);
     2342        VM_CHECK_EXCEPTION();
     2343
     2344        vPC += 6;
    19722345        NEXT_OPCODE;
    19732346    }
     
    20652438        } else {
    20662439            Identifier property(exec, subscript->toString(exec));
    2067             if (!exec->hadException()) // Don't put to an object if toString threw an exception.
    2068                 baseValue->put(exec, property, r[value].jsValue(exec));
     2440            if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
     2441                PutPropertySlot slot;
     2442                baseValue->put(exec, property, r[value].jsValue(exec), slot);
     2443            }
    20692444        }
    20702445
     
    29343309    if (!activation) {
    29353310        CodeBlock* codeBlock = &function->m_body->generatedByteCode();
    2936         activation = new (exec) JSActivation(function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
     3311        activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
    29373312        callFrame[RegisterFile::OptionalCalleeActivation] = activation;
    29383313    }
Note: See TracChangeset for help on using the changeset viewer.