⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jitstubs.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * 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. * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of *     its contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "JITStubs.h"#if ENABLE(JIT)#include "Arguments.h"#include "CallFrame.h"#include "CodeBlock.h"#include "Collector.h"#include "Debugger.h"#include "ExceptionHelpers.h"#include "GlobalEvalFunction.h"#include "JIT.h"#include "JSActivation.h"#include "JSArray.h"#include "JSByteArray.h"#include "JSFunction.h"#include "JSNotAnObject.h"#include "JSPropertyNameIterator.h"#include "JSStaticScopeObject.h"#include "JSString.h"#include "ObjectPrototype.h"#include "Operations.h"#include "Parser.h"#include "Profiler.h"#include "RegExpObject.h"#include "RegExpPrototype.h"#include "Register.h"#include "SamplingTool.h"#include <stdio.h>using namespace std;namespace JSC {#if ENABLE(OPCODE_SAMPLING)    #define CTI_SAMPLER ARG_globalData->interpreter->sampler()#else    #define CTI_SAMPLER 0#endifJITStubs::JITStubs(JSGlobalData* globalData)    : m_ctiArrayLengthTrampoline(0)    , m_ctiStringLengthTrampoline(0)    , m_ctiVirtualCallPreLink(0)    , m_ctiVirtualCallLink(0)    , m_ctiVirtualCall(0){    JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiArrayLengthTrampoline, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall);}#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)NEVER_INLINE void JITStubs::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValuePtr baseValue, const PutPropertySlot& slot){    // The interpreter checks for recursion here; I do not believe this can occur in CTI.    if (!baseValue.isCell())        return;    // Uncacheable: give up.    if (!slot.isCacheable()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_put_by_id_generic));        return;    }        JSCell* baseCell = asCell(baseValue);    Structure* structure = baseCell->structure();    if (structure->isDictionary()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_put_by_id_generic));        return;    }    // If baseCell != base, then baseCell must be a proxy for another object.    if (baseCell != slot.base()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_put_by_id_generic));        return;    }    StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress);    // Cache hit: Specialize instruction and ref Structures.    // Structure transition, cache transition info    if (slot.type() == PutPropertySlot::NewProperty) {        StructureChain* prototypeChain = structure->prototypeChain(callFrame);        stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);        JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress);        return;    }        stubInfo->initPutByIdReplace(structure);#if USE(CTI_REPATCH_PIC)    JIT::patchPutByIdReplace(stubInfo, structure, slot.cachedOffset(), returnAddress);#else    JIT::compilePutByIdReplace(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);#endif}NEVER_INLINE void JITStubs::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot& slot){    // FIXME: Write a test that proves we need to check for recursion here just    // like the interpreter does, then add a check for recursion.    // FIXME: Cache property access for immediates.    if (!baseValue.isCell()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_get_by_id_generic));        return;    }        JSGlobalData* globalData = &callFrame->globalData();    if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {#if USE(CTI_REPATCH_PIC)        JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);#else        ctiPatchCallByReturnAddress(returnAddress, globalData->jitStubs.ctiArrayLengthTrampoline());#endif        return;    }        if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {        // The tradeoff of compiling an patched inline string length access routine does not seem        // to pay off, so we currently only do this for arrays.        ctiPatchCallByReturnAddress(returnAddress, globalData->jitStubs.ctiStringLengthTrampoline());        return;    }    // Uncacheable: give up.    if (!slot.isCacheable()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_get_by_id_generic));        return;    }    JSCell* baseCell = asCell(baseValue);    Structure* structure = baseCell->structure();    if (structure->isDictionary()) {        ctiPatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(JITStubs::cti_op_get_by_id_generic));        return;    }    // In the interpreter the last structure is trapped here; in CTI we use the    // *_second method to achieve a similar (but not quite the same) effect.    StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress);    // Cache hit: Specialize instruction and ref Structures.    if (slot.slotBase() == baseValue) {        // set this up, so derefStructures can do it's job.        stubInfo->initGetByIdSelf(structure);        #if USE(CTI_REPATCH_PIC)        JIT::patchGetByIdSelf(stubInfo, structure, slot.cachedOffset(), returnAddress);#else        JIT::compileGetByIdSelf(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);#endif        return;    }    if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {        ASSERT(slot.slotBase().isObject());        JSObject* slotBaseObject = asObject(slot.slotBase());        // 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->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));                stubInfo->initGetByIdProto(structure, slotBaseObject->structure());        JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), slot.cachedOffset(), returnAddress);        return;    }    size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);    if (!count) {        stubInfo->opcodeID = op_get_by_id_generic;        return;    }    StructureChain* prototypeChain = structure->prototypeChain(callFrame);    stubInfo->initGetByIdChain(structure, prototypeChain);    JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress);}#endif#if USE(JIT_STUB_ARGUMENT_VA_LIST)#define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args)#else // JIT_STUB_ARGUMENT_REGISTER or JIT_STUB_ARGUMENT_STACK#define SETUP_VA_LISTL_ARGS#endif#ifndef NDEBUGextern "C" {static void jscGeneratedNativeCode() {    // When executing a CTI function (which might do an allocation), we hack the return address    // to pretend to be executing this function, to keep stack logging tools from blowing out    // memory.}}struct StackHack {    ALWAYS_INLINE StackHack(void** location)     {         returnAddressLocation = location;        savedReturnAddress = *returnAddressLocation;        ctiSetReturnAddress(returnAddressLocation, reinterpret_cast<void*>(jscGeneratedNativeCode));    }    ALWAYS_INLINE ~StackHack()     {         ctiSetReturnAddress(returnAddressLocation, savedReturnAddress);    }    void** returnAddressLocation;    void* savedReturnAddress;};#define BEGIN_STUB_FUNCTION() SETUP_VA_LISTL_ARGS; StackHack stackHack(&STUB_RETURN_ADDRESS_SLOT)#define STUB_SET_RETURN_ADDRESS(address) stackHack.savedReturnAddress = address#define STUB_RETURN_ADDRESS stackHack.savedReturnAddress#else#define BEGIN_STUB_FUNCTION() SETUP_VA_LISTL_ARGS#define STUB_SET_RETURN_ADDRESS(address) ctiSetReturnAddress(&STUB_RETURN_ADDRESS_SLOT, address);#define STUB_RETURN_ADDRESS STUB_RETURN_ADDRESS_SLOT#endif// The reason this is not inlined is to avoid having to do a PIC branch// to get the address of the ctiVMThrowTrampoline function. It's also// good to keep the code size down by leaving as much of the exception// handling code out of line as possible.static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot){    ASSERT(globalData->exception);    globalData->exceptionLocation = exceptionLocation;    ctiSetReturnAddress(&returnAddressSlot, reinterpret_cast<void*>(ctiVMThrowTrampoline));}static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot){    globalData->exception = createStackOverflowError(callFrame);    returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot);}#define VM_THROW_EXCEPTION() \    do { \        VM_THROW_EXCEPTION_AT_END(); \        return 0; \    } while (0)#define VM_THROW_EXCEPTION_2() \    do { \        VM_THROW_EXCEPTION_AT_END(); \        RETURN_PAIR(0, 0); \    } while (0)#define VM_THROW_EXCEPTION_AT_END() \    returnToThrowTrampoline(ARG_globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS)#define CHECK_FOR_EXCEPTION() \    do { \        if (UNLIKELY(ARG_globalData->exception != noValue())) \            VM_THROW_EXCEPTION(); \    } while (0)#define CHECK_FOR_EXCEPTION_AT_END() \    do { \        if (UNLIKELY(ARG_globalData->exception != noValue())) \            VM_THROW_EXCEPTION_AT_END(); \    } while (0)#define CHECK_FOR_EXCEPTION_VOID() \    do { \        if (UNLIKELY(ARG_globalData->exception != noValue())) { \            VM_THROW_EXCEPTION_AT_END(); \            return; \        } \    } while (0)JSObject* JITStubs::cti_op_convert_this(STUB_ARGS){    BEGIN_STUB_FUNCTION();    JSValuePtr v1 = ARG_src1;    CallFrame* callFrame = ARG_callFrame;    JSObject* result = v1.toThisObject(callFrame);    CHECK_FOR_EXCEPTION_AT_END();    return result;}void JITStubs::cti_op_end(STUB_ARGS){    BEGIN_STUB_FUNCTION();    ScopeChainNode* scopeChain = ARG_callFrame->scopeChain();    ASSERT(scopeChain->refCount > 1);    scopeChain->deref();}JSValueEncodedAsPointer* JITStubs::cti_op_add(STUB_ARGS){    BEGIN_STUB_FUNCTION();    JSValuePtr v1 = ARG_src1;    JSValuePtr v2 = ARG_src2;    double left;    double right = 0.0;    bool rightIsNumber = v2.getNumber(right);    if (rightIsNumber && v1.getNumber(left))        return JSValuePtr::encode(jsNumber(ARG_globalData, left + right));        CallFrame* callFrame = ARG_callFrame;    bool leftIsString = v1.isString();    if (leftIsString && v2.isString()) {        RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());        if (UNLIKELY(!value)) {            throwOutOfMemoryError(callFrame);            VM_THROW_EXCEPTION();        }        return JSValuePtr::encode(jsString(ARG_globalData, value.release()));    }    if (rightIsNumber & leftIsString) {        RefPtr<UString::Rep> value = v2.isInt32Fast() ?            concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) :            concatenate(asString(v1)->value().rep(), right);        if (UNLIKELY(!value)) {            throwOutOfMemoryError(callFrame);            VM_THROW_EXCEPTION();        }        return JSValuePtr::encode(jsString(ARG_globalData, value.release()));    }    // All other cases are pretty uncommon    JSValuePtr result = jsAddSlowCase(callFrame, v1, v2);    CHECK_FOR_EXCEPTION_AT_END();    return JSValuePtr::encode(result);}JSValueEncodedAsPointer* JITStubs::cti_op_pre_inc(STUB_ARGS){    BEGIN_STUB_FUNCTION();    JSValuePtr v = ARG_src1;    CallFrame* callFrame = ARG_callFrame;    JSValuePtr result = jsNumber(ARG_globalData, v.toNumber(callFrame) + 1);    CHECK_FOR_EXCEPTION_AT_END();    return JSValuePtr::encode(result);}int JITStubs::cti_timeout_check(STUB_ARGS){    BEGIN_STUB_FUNCTION();    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -