diff options
Diffstat (limited to 'Source/JavaScriptCore/jit/JITStubs.cpp')
-rw-r--r-- | Source/JavaScriptCore/jit/JITStubs.cpp | 201 |
1 files changed, 20 insertions, 181 deletions
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index ba8c76cfb..5ddb98dee 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -864,7 +864,10 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co } // put_by_id_transition checks the prototype chain for setters. - normalizePrototypeChain(callFrame, baseCell); + if (normalizePrototypeChain(callFrame, baseCell) == InvalidPrototypeChain) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } StructureChain* prototypeChain = structure->prototypeChain(callFrame); ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); @@ -937,7 +940,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); - + JSObject* slotBaseObject = asObject(slot.slotBase()); size_t offset = slot.cachedOffset(); @@ -958,7 +961,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co PropertyOffset offset = slot.cachedOffset(); size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); - if (!count) { + if (count == InvalidPrototypeChain) { stubInfo->accessType = access_get_by_id_generic; return; } @@ -1512,178 +1515,6 @@ DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) return base; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - Identifier& ident = stackFrame.args[1].identifier(); - - CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); - MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); - StructureStubInfo& stubInfo = codeBlock->getStubInfo(STUB_RETURN_ADDRESS); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); - CHECK_FOR_EXCEPTION(); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return JSValue::encode(result); - - if (!methodCallLinkInfo.seenOnce()) { - methodCallLinkInfo.setSeen(); - return JSValue::encode(result); - } - - // If we successfully got something, then the base from which it is being accessed must - // be an object. (Assertion to ensure asObject() call below is safe, which comes after - // an isCacheable() chceck. - ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); - - // Check that: - // * We're dealing with a JSCell, - // * the property is cachable, - // * it's not a dictionary - // * there is a function cached. - Structure* structure; - JSCell* specific; - JSObject* slotBaseObject; - if (baseValue.isCell() - && slot.isCacheableValue() - && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() - && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) - && specific - ) { - - JSObject* callee = asObject(specific); - - // Since we're accessing a prototype in a loop, it's a good bet that it - // should not be treated as a dictionary. - if (slotBaseObject->structure()->isDictionary()) - slotBaseObject->flattenDictionaryObject(callFrame->globalData()); - - // The result fetched should always be the callee! - ASSERT(result == JSValue(callee)); - - // Check to see if the function is on the object's prototype. Patch up the code to optimize. - if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { - JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, stubInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); - return JSValue::encode(result); - } - - // Check to see if the function is on the object itself. - // Since we generate the method-check to check both the structure and a prototype-structure (since this - // is the common case) we have a problem - we need to patch the prototype structure check to do something - // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler - // for now. For now it performs a check on a special object on the global object only used for this - // purpose. The object is in no way exposed, and as such the check will always pass. - if (slot.slotBase() == baseValue) { - JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, stubInfo, callee, structure, callFrame->scope()->globalObject()->methodCallDummy(), STUB_RETURN_ADDRESS); - return JSValue::encode(result); - } - } - - // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); - return JSValue::encode(result); -} - -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_update) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - Identifier& ident = stackFrame.args[1].identifier(); - - CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); - MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); - StructureStubInfo& stubInfo = codeBlock->getStubInfo(STUB_RETURN_ADDRESS); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); - CHECK_FOR_EXCEPTION(); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return JSValue::encode(result); - - ASSERT(methodCallLinkInfo.seenOnce()); - - // If we successfully got something, then the base from which it is being accessed must - // be an object. (Assertion to ensure asObject() call below is safe, which comes after - // an isCacheable() chceck. - ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); - - // Check that: - // * We're dealing with a JSCell, - // * the property is cachable, - // * it's not a dictionary - // * there is a function cached. - Structure* structure; - JSCell* specific; - JSObject* slotBaseObject; - if (!(baseValue.isCell() - && slot.isCacheableValue() - && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() - && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) - && specific - ) - || (slot.slotBase() != structure->prototypeForLookup(callFrame) - && slot.slotBase() != baseValue)) { - // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); - return JSValue::encode(result); - } - - // Now check if the situation has changed sufficiently that we should bail out of - // doing method_check optimizations entirely, or if it changed only slightly, in - // which case we can just repatch. - - JSValue proto = structure->prototypeForLookup(callFrame); - - bool previousWasProto = methodCallLinkInfo.cachedPrototype.get() != codeBlock->globalObject()->methodCallDummy(); - bool currentIsProto = slot.slotBase() == proto; - - JSObject* callee = asObject(specific); - - if (previousWasProto != currentIsProto - || !structure->transitivelyTransitionedFrom(methodCallLinkInfo.cachedStructure.get()) - || (previousWasProto && !slotBaseObject->structure()->transitivelyTransitionedFrom(methodCallLinkInfo.cachedPrototypeStructure.get())) - || specific != methodCallLinkInfo.cachedFunction.get()) { - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); - return JSValue::encode(result); - } - - // It makes sense to simply repatch the method_check. - - // Since we're accessing a prototype in a loop, it's a good bet that it - // should not be treated as a dictionary. - if (slotBaseObject->structure()->isDictionary()) - slotBaseObject->flattenDictionaryObject(callFrame->globalData()); - - // The result fetched should always be the callee! - ASSERT(result == JSValue(callee)); - - // Check to see if the function is on the object's prototype. Patch up the code to optimize. - if (slot.slotBase() == proto) { - JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, stubInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); - return JSValue::encode(result); - } - - ASSERT(slot.slotBase() == baseValue); - - // Since we generate the method-check to check both the structure and a prototype-structure (since this - // is the common case) we have a problem - we need to patch the prototype structure check to do something - // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler - // for now. For now it performs a check on a special object on the global object only used for this - // purpose. The object is in no way exposed, and as such the check will always pass. - JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, stubInfo, callee, structure, callFrame->scope()->globalObject()->methodCallDummy(), STUB_RETURN_ADDRESS); - return JSValue::encode(result); -} - DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1873,7 +1704,13 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } - } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { + } else { + size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); + if (count == InvalidPrototypeChain) { + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + return JSValue::encode(result); + } + ASSERT(!baseValue.asCell()->structure()->isDictionary()); int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex); @@ -1885,8 +1722,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } - } else - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + } return JSValue::encode(result); } @@ -2308,7 +2144,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_push_activation) { STUB_INIT_STACK_FRAME(stackFrame); - JSActivation* activation = JSActivation::create(stackFrame.callFrame->globalData(), stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable())); + JSActivation* activation = JSActivation::create(stackFrame.callFrame->globalData(), stackFrame.callFrame, stackFrame.callFrame->codeBlock()); stackFrame.callFrame->setScope(activation); return activation; } @@ -3500,13 +3336,16 @@ DEFINE_STUB_FUNCTION(void, op_put_getter_setter) baseObj->putDirectAccessor(callFrame, stackFrame.args[1].identifier(), accessor, Accessor); } -DEFINE_STUB_FUNCTION(void, op_throw_reference_error) +DEFINE_STUB_FUNCTION(void, op_throw_static_error) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; String message = stackFrame.args[0].jsValue().toString(callFrame)->value(callFrame); - stackFrame.globalData->exception = createReferenceError(callFrame, message); + if (stackFrame.args[1].asInt32) + stackFrame.globalData->exception = createReferenceError(callFrame, message); + else + stackFrame.globalData->exception = createTypeError(callFrame, message); VM_THROW_EXCEPTION_AT_END(); } |