📄 jitpropertyaccess.cpp
字号:
/* * Copyright (C) 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "JIT.h"#if ENABLE(JIT)#include "CodeBlock.h"#include "JITInlineMethods.h"#include "JSArray.h"#include "JSFunction.h"#include "Interpreter.h"#include "ResultType.h"#include "SamplingTool.h"#ifndef NDEBUG#include <stdio.h>#endifusing namespace std;namespace JSC {#if !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned){ // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched. // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label // to jump back to if one of these trampolies finds a match. emitGetVirtualRegister(baseVReg, regT0); emitPutJITStubArg(regT0, 1); emitPutJITStubArgConstant(ident, 2); emitCTICall(JITStubs::cti_op_get_by_id_generic); emitPutVirtualRegister(resultVReg);}void JIT::compileGetByIdSlowCase(int, int, Identifier*, Vector<SlowCaseEntry>::iterator&, unsigned){ ASSERT_NOT_REACHED();}void JIT::compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned){ // In order to be able to patch both the Structure, and the object offset, we store one pointer, // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code // such that the Structure & offset are always at the same distance from this. emitGetVirtualRegisters(baseVReg, regT0, valueVReg, regT1); emitPutJITStubArgConstant(ident, 2); emitPutJITStubArg(regT0, 1); emitPutJITStubArg(regT1, 3); emitCTICall(JITStubs::cti_op_put_by_id_generic);}void JIT::compilePutByIdSlowCase(int, Identifier*, int, Vector<SlowCaseEntry>::iterator&, unsigned){ ASSERT_NOT_REACHED();}#elsevoid JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsigned propertyAccessInstructionIndex){ // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched. // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label // to jump back to if one of these trampolies finds a match. emitGetVirtualRegister(baseVReg, regT0); emitJumpSlowCaseIfNotJSCell(regT0, baseVReg); Label hotPathBegin(this); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; DataLabelPtr structureToCompare; Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, FIELD_OFFSET(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); addSlowCase(structureCheck); ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetGetByIdStructure); ASSERT(differenceBetween(hotPathBegin, structureCheck) == patchOffsetGetByIdBranchToSlowCase); loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0); DataLabel32 displacementLabel = loadPtrWithAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0); ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetGetByIdPropertyMapOffset); Label putResult(this); ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult); emitPutVirtualRegister(resultVReg);}void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex){ // As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset // so that we only need track one pointer into the slow case code - we track a pointer to the location // of the call (which we can use to look up the patch information), but should a array-length or // prototype access trampoline fail we want to bail out back to here. To do so we can subtract back // the distance from the call to the head of the slow case. linkSlowCaseIfNotJSCell(iter, baseVReg); linkSlowCase(iter);#ifndef NDEBUG Label coldPathBegin(this);#endif emitPutJITStubArg(regT0, 1); emitPutJITStubArgConstant(ident, 2); Call call = emitCTICall(JITStubs::cti_op_get_by_id); emitPutVirtualRegister(resultVReg); ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall); // Track the location of the call; this will be used to recover patch information. m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;}void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsigned propertyAccessInstructionIndex){ // In order to be able to patch both the Structure, and the object offset, we store one pointer, // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code // such that the Structure & offset are always at the same distance from this. emitGetVirtualRegisters(baseVReg, regT0, valueVReg, regT1); // Jump to a slow case if either the base object is an immediate, or if the Structure does not match. emitJumpSlowCaseIfNotJSCell(regT0, baseVReg); Label hotPathBegin(this); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over. DataLabelPtr structureToCompare; addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, FIELD_OFFSET(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)))); ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetPutByIdStructure); // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used. loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0); DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchGetByIdDefaultOffset)); ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetPutByIdPropertyMapOffset);}void JIT::compilePutByIdSlowCase(int baseVReg, Identifier* ident, int, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex){ linkSlowCaseIfNotJSCell(iter, baseVReg); linkSlowCase(iter); emitPutJITStubArgConstant(ident, 2); emitPutJITStubArg(regT0, 1); emitPutJITStubArg(regT1, 3); Call call = emitCTICall(JITStubs::cti_op_put_by_id); // Track the location of the call; this will be used to recover patch information. m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;}static JSObject* resizePropertyStorage(JSObject* baseObject, int32_t oldSize, int32_t newSize){ baseObject->allocatePropertyStorage(oldSize, newSize); return baseObject;}static inline bool transitionWillNeedStorageRealloc(Structure* oldStructure, Structure* newStructure){ return oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();}void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ProcessorReturnAddress returnAddress){ JumpList failureCases; // Check eax is an object of the right Structure. failureCases.append(emitJumpIfNotJSCell(regT0)); failureCases.append(branchPtr(NotEqual, Address(regT0, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(oldStructure))); JumpList successCases; // ecx = baseObject loadPtr(Address(regT0, FIELD_OFFSET(JSCell, m_structure)), regT2); // proto(ecx) = baseObject->structure()->prototype() failureCases.append(branch32(NotEqual, Address(regT2, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type)), Imm32(ObjectType))); loadPtr(Address(regT2, FIELD_OFFSET(Structure, m_prototype)), regT2); // ecx = baseObject->m_structure for (RefPtr<Structure>* it = chain->head(); *it; ++it) { // null check the prototype successCases.append(branchPtr(Equal, regT2, ImmPtr(JSValuePtr::encode(jsNull())))); // Check the structure id failureCases.append(branchPtr(NotEqual, Address(regT2, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(it->get()))); loadPtr(Address(regT2, FIELD_OFFSET(JSCell, m_structure)), regT2); failureCases.append(branch32(NotEqual, Address(regT2, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type)), Imm32(ObjectType))); loadPtr(Address(regT2, FIELD_OFFSET(Structure, m_prototype)), regT2); } successCases.link(this); Call callTarget; // emit a call only if storage realloc is needed bool willNeedStorageRealloc = transitionWillNeedStorageRealloc(oldStructure, newStructure); if (willNeedStorageRealloc) { pop(X86::ebx);#if PLATFORM(X86_64) move(Imm32(newStructure->propertyStorageCapacity()), regT1); move(Imm32(oldStructure->propertyStorageCapacity()), X86::esi); move(regT0, X86::edi);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -