1692e5dbf12901edacf14812a6fae25462920af42Steve Block/* 2692e5dbf12901edacf14812a6fae25462920af42Steve Block * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3692e5dbf12901edacf14812a6fae25462920af42Steve Block * 4692e5dbf12901edacf14812a6fae25462920af42Steve Block * Redistribution and use in source and binary forms, with or without 5692e5dbf12901edacf14812a6fae25462920af42Steve Block * modification, are permitted provided that the following conditions 6692e5dbf12901edacf14812a6fae25462920af42Steve Block * are met: 7692e5dbf12901edacf14812a6fae25462920af42Steve Block * 1. Redistributions of source code must retain the above copyright 8692e5dbf12901edacf14812a6fae25462920af42Steve Block * notice, this list of conditions and the following disclaimer. 9692e5dbf12901edacf14812a6fae25462920af42Steve Block * 2. Redistributions in binary form must reproduce the above copyright 10692e5dbf12901edacf14812a6fae25462920af42Steve Block * notice, this list of conditions and the following disclaimer in the 11692e5dbf12901edacf14812a6fae25462920af42Steve Block * documentation and/or other materials provided with the distribution. 12692e5dbf12901edacf14812a6fae25462920af42Steve Block * 13692e5dbf12901edacf14812a6fae25462920af42Steve Block * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14692e5dbf12901edacf14812a6fae25462920af42Steve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15692e5dbf12901edacf14812a6fae25462920af42Steve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16692e5dbf12901edacf14812a6fae25462920af42Steve Block * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17692e5dbf12901edacf14812a6fae25462920af42Steve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18692e5dbf12901edacf14812a6fae25462920af42Steve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19692e5dbf12901edacf14812a6fae25462920af42Steve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20692e5dbf12901edacf14812a6fae25462920af42Steve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21692e5dbf12901edacf14812a6fae25462920af42Steve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22692e5dbf12901edacf14812a6fae25462920af42Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23692e5dbf12901edacf14812a6fae25462920af42Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24692e5dbf12901edacf14812a6fae25462920af42Steve Block */ 25692e5dbf12901edacf14812a6fae25462920af42Steve Block 26692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "config.h" 27692e5dbf12901edacf14812a6fae25462920af42Steve Block 28e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#if ENABLE(JIT) 29692e5dbf12901edacf14812a6fae25462920af42Steve Block#if USE(JSVALUE32_64) 30692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JIT.h" 31692e5dbf12901edacf14812a6fae25462920af42Steve Block 32692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "CodeBlock.h" 33692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JITInlineMethods.h" 34692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JITStubCall.h" 35692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JSArray.h" 36692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JSFunction.h" 37692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "JSPropertyNameIterator.h" 38692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "Interpreter.h" 39692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "LinkBuffer.h" 40692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "RepatchBuffer.h" 41692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "ResultType.h" 42692e5dbf12901edacf14812a6fae25462920af42Steve Block#include "SamplingTool.h" 43692e5dbf12901edacf14812a6fae25462920af42Steve Block 44692e5dbf12901edacf14812a6fae25462920af42Steve Block#ifndef NDEBUG 45692e5dbf12901edacf14812a6fae25462920af42Steve Block#include <stdio.h> 46692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 47692e5dbf12901edacf14812a6fae25462920af42Steve Block 48692e5dbf12901edacf14812a6fae25462920af42Steve Blockusing namespace std; 49692e5dbf12901edacf14812a6fae25462920af42Steve Block 50692e5dbf12901edacf14812a6fae25462920af42Steve Blocknamespace JSC { 51692e5dbf12901edacf14812a6fae25462920af42Steve Block 52692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_by_index(Instruction* currentInstruction) 53692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 54692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 55692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 56692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned value = currentInstruction[3].u.operand; 57692e5dbf12901edacf14812a6fae25462920af42Steve Block 58692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_by_index); 59692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 60692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(Imm32(property)); 61692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(value); 62692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(); 63692e5dbf12901edacf14812a6fae25462920af42Steve Block} 64692e5dbf12901edacf14812a6fae25462920af42Steve Block 65692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_getter(Instruction* currentInstruction) 66692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 67692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 68692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 69692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned function = currentInstruction[3].u.operand; 70692e5dbf12901edacf14812a6fae25462920af42Steve Block 71692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_getter); 72692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 732bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property))); 74692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(function); 75692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(); 76692e5dbf12901edacf14812a6fae25462920af42Steve Block} 77692e5dbf12901edacf14812a6fae25462920af42Steve Block 78692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_setter(Instruction* currentInstruction) 79692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 80692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 81692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 82692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned function = currentInstruction[3].u.operand; 83692e5dbf12901edacf14812a6fae25462920af42Steve Block 84692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_setter); 85692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 862bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property))); 87692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(function); 88692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(); 89692e5dbf12901edacf14812a6fae25462920af42Steve Block} 90692e5dbf12901edacf14812a6fae25462920af42Steve Block 91692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_del_by_id(Instruction* currentInstruction) 92692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 93692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 94692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 95692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 96692e5dbf12901edacf14812a6fae25462920af42Steve Block 97692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_del_by_id); 98692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 992bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property))); 100692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(dst); 101692e5dbf12901edacf14812a6fae25462920af42Steve Block} 102692e5dbf12901edacf14812a6fae25462920af42Steve Block 103692e5dbf12901edacf14812a6fae25462920af42Steve Block 104692e5dbf12901edacf14812a6fae25462920af42Steve Block#if !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 105692e5dbf12901edacf14812a6fae25462920af42Steve Block 106692e5dbf12901edacf14812a6fae25462920af42Steve Block/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ 107692e5dbf12901edacf14812a6fae25462920af42Steve Block 108692e5dbf12901edacf14812a6fae25462920af42Steve Block// Treat these as nops - the call will be handed as a regular get_by_id/op_call pair. 109692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_method_check(Instruction*) {} 110692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&) { ASSERT_NOT_REACHED(); } 111692e5dbf12901edacf14812a6fae25462920af42Steve Block#if ENABLE(JIT_OPTIMIZE_METHOD_CALLS) 112692e5dbf12901edacf14812a6fae25462920af42Steve Block#error "JIT_OPTIMIZE_METHOD_CALLS requires JIT_OPTIMIZE_PROPERTY_ACCESS" 113692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 114692e5dbf12901edacf14812a6fae25462920af42Steve Block 115692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_get_by_val(Instruction* currentInstruction) 116692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 117692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 118692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 119692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 120692e5dbf12901edacf14812a6fae25462920af42Steve Block 121692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_get_by_val); 122692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 123692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(property); 124692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(dst); 125692e5dbf12901edacf14812a6fae25462920af42Steve Block} 126692e5dbf12901edacf14812a6fae25462920af42Steve Block 127692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&) 128692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 129692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT_NOT_REACHED(); 130692e5dbf12901edacf14812a6fae25462920af42Steve Block} 131692e5dbf12901edacf14812a6fae25462920af42Steve Block 132692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_by_val(Instruction* currentInstruction) 133692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 134692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 135692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 136692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned value = currentInstruction[3].u.operand; 137692e5dbf12901edacf14812a6fae25462920af42Steve Block 138692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_by_val); 139692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 140692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(property); 141692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(value); 142692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(); 143692e5dbf12901edacf14812a6fae25462920af42Steve Block} 144692e5dbf12901edacf14812a6fae25462920af42Steve Block 145692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&) 146692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 147692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT_NOT_REACHED(); 148692e5dbf12901edacf14812a6fae25462920af42Steve Block} 149692e5dbf12901edacf14812a6fae25462920af42Steve Block 150692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_get_by_id(Instruction* currentInstruction) 151692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 152692e5dbf12901edacf14812a6fae25462920af42Steve Block int dst = currentInstruction[1].u.operand; 153692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[2].u.operand; 154692e5dbf12901edacf14812a6fae25462920af42Steve Block int ident = currentInstruction[3].u.operand; 155692e5dbf12901edacf14812a6fae25462920af42Steve Block 156692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_get_by_id_generic); 157692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 1582bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident)))); 159692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(dst); 160692e5dbf12901edacf14812a6fae25462920af42Steve Block 161692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 162692e5dbf12901edacf14812a6fae25462920af42Steve Block} 163692e5dbf12901edacf14812a6fae25462920af42Steve Block 164692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&) 165692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 166692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 167692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT_NOT_REACHED(); 168692e5dbf12901edacf14812a6fae25462920af42Steve Block} 169692e5dbf12901edacf14812a6fae25462920af42Steve Block 170692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_by_id(Instruction* currentInstruction) 171692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 172692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[1].u.operand; 173692e5dbf12901edacf14812a6fae25462920af42Steve Block int ident = currentInstruction[2].u.operand; 174692e5dbf12901edacf14812a6fae25462920af42Steve Block int value = currentInstruction[3].u.operand; 175692e5dbf12901edacf14812a6fae25462920af42Steve Block 176692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_by_id_generic); 177692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 1782bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident)))); 179692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(value); 180692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(); 181692e5dbf12901edacf14812a6fae25462920af42Steve Block 182692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 183692e5dbf12901edacf14812a6fae25462920af42Steve Block} 184692e5dbf12901edacf14812a6fae25462920af42Steve Block 185692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&) 186692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 187692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 188692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT_NOT_REACHED(); 189692e5dbf12901edacf14812a6fae25462920af42Steve Block} 190692e5dbf12901edacf14812a6fae25462920af42Steve Block 191692e5dbf12901edacf14812a6fae25462920af42Steve Block#else // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 192692e5dbf12901edacf14812a6fae25462920af42Steve Block 193692e5dbf12901edacf14812a6fae25462920af42Steve Block/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ 194692e5dbf12901edacf14812a6fae25462920af42Steve Block 195692e5dbf12901edacf14812a6fae25462920af42Steve Block#if ENABLE(JIT_OPTIMIZE_METHOD_CALLS) 196692e5dbf12901edacf14812a6fae25462920af42Steve Block 197692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_method_check(Instruction* currentInstruction) 198692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 199692e5dbf12901edacf14812a6fae25462920af42Steve Block // Assert that the following instruction is a get_by_id. 200692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id); 201692e5dbf12901edacf14812a6fae25462920af42Steve Block 202692e5dbf12901edacf14812a6fae25462920af42Steve Block currentInstruction += OPCODE_LENGTH(op_method_check); 203692e5dbf12901edacf14812a6fae25462920af42Steve Block 204692e5dbf12901edacf14812a6fae25462920af42Steve Block // Do the method check - check the object & its prototype's structure inline (this is the common case). 205692e5dbf12901edacf14812a6fae25462920af42Steve Block m_methodCallCompilationInfo.append(MethodCallCompilationInfo(m_propertyAccessInstructionIndex)); 206692e5dbf12901edacf14812a6fae25462920af42Steve Block MethodCallCompilationInfo& info = m_methodCallCompilationInfo.last(); 207692e5dbf12901edacf14812a6fae25462920af42Steve Block 208692e5dbf12901edacf14812a6fae25462920af42Steve Block int dst = currentInstruction[1].u.operand; 209692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[2].u.operand; 210692e5dbf12901edacf14812a6fae25462920af42Steve Block 211692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad(base, regT1, regT0); 212692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT1); 213692e5dbf12901edacf14812a6fae25462920af42Steve Block 214692e5dbf12901edacf14812a6fae25462920af42Steve Block BEGIN_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); 215692e5dbf12901edacf14812a6fae25462920af42Steve Block 2162bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), info.structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); 2172bde8e466a4451c7319e3a072d118917957d6554Steve Block DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(TrustedImmPtr(0), regT2); 2182bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT2, JSCell::structureOffset()), protoStructureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); 219692e5dbf12901edacf14812a6fae25462920af42Steve Block 220692e5dbf12901edacf14812a6fae25462920af42Steve Block // This will be relinked to load the function without doing a load. 2212bde8e466a4451c7319e3a072d118917957d6554Steve Block DataLabelPtr putFunction = moveWithPatch(TrustedImmPtr(0), regT0); 222692e5dbf12901edacf14812a6fae25462920af42Steve Block 223692e5dbf12901edacf14812a6fae25462920af42Steve Block END_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); 224692e5dbf12901edacf14812a6fae25462920af42Steve Block 2252bde8e466a4451c7319e3a072d118917957d6554Steve Block move(TrustedImm32(JSValue::CellTag), regT1); 226692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump match = jump(); 227692e5dbf12901edacf14812a6fae25462920af42Steve Block 22881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoObj), patchOffsetMethodCheckProtoObj); 22981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoStructureToCompare), patchOffsetMethodCheckProtoStruct); 23081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, putFunction), patchOffsetMethodCheckPutFunction); 231692e5dbf12901edacf14812a6fae25462920af42Steve Block 232692e5dbf12901edacf14812a6fae25462920af42Steve Block // Link the failure cases here. 233692e5dbf12901edacf14812a6fae25462920af42Steve Block structureCheck.link(this); 234692e5dbf12901edacf14812a6fae25462920af42Steve Block protoStructureCheck.link(this); 235692e5dbf12901edacf14812a6fae25462920af42Steve Block 236692e5dbf12901edacf14812a6fae25462920af42Steve Block // Do a regular(ish) get_by_id (the slow case will be link to 237692e5dbf12901edacf14812a6fae25462920af42Steve Block // cti_op_get_by_id_method_check instead of cti_op_get_by_id. 238692e5dbf12901edacf14812a6fae25462920af42Steve Block compileGetByIdHotPath(); 239692e5dbf12901edacf14812a6fae25462920af42Steve Block 240692e5dbf12901edacf14812a6fae25462920af42Steve Block match.link(this); 241692e5dbf12901edacf14812a6fae25462920af42Steve Block emitStore(dst, regT1, regT0); 242e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block map(m_bytecodeOffset + OPCODE_LENGTH(op_method_check), dst, regT1, regT0); 243692e5dbf12901edacf14812a6fae25462920af42Steve Block 244692e5dbf12901edacf14812a6fae25462920af42Steve Block // We've already generated the following get_by_id, so make sure it's skipped over. 245e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); 246692e5dbf12901edacf14812a6fae25462920af42Steve Block} 247692e5dbf12901edacf14812a6fae25462920af42Steve Block 248692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 249692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 250692e5dbf12901edacf14812a6fae25462920af42Steve Block currentInstruction += OPCODE_LENGTH(op_method_check); 251692e5dbf12901edacf14812a6fae25462920af42Steve Block 252692e5dbf12901edacf14812a6fae25462920af42Steve Block int dst = currentInstruction[1].u.operand; 253692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[2].u.operand; 254692e5dbf12901edacf14812a6fae25462920af42Steve Block int ident = currentInstruction[3].u.operand; 255692e5dbf12901edacf14812a6fae25462920af42Steve Block 256692e5dbf12901edacf14812a6fae25462920af42Steve Block compileGetByIdSlowCase(dst, base, &(m_codeBlock->identifier(ident)), iter, true); 257692e5dbf12901edacf14812a6fae25462920af42Steve Block 258692e5dbf12901edacf14812a6fae25462920af42Steve Block // We've already generated the following get_by_id, so make sure it's skipped over. 259e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); 260692e5dbf12901edacf14812a6fae25462920af42Steve Block} 261692e5dbf12901edacf14812a6fae25462920af42Steve Block 262692e5dbf12901edacf14812a6fae25462920af42Steve Block#else //!ENABLE(JIT_OPTIMIZE_METHOD_CALLS) 263692e5dbf12901edacf14812a6fae25462920af42Steve Block 264692e5dbf12901edacf14812a6fae25462920af42Steve Block// Treat these as nops - the call will be handed as a regular get_by_id/op_call pair. 265692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_method_check(Instruction*) {} 266692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&) { ASSERT_NOT_REACHED(); } 267692e5dbf12901edacf14812a6fae25462920af42Steve Block 268692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 269692e5dbf12901edacf14812a6fae25462920af42Steve Block 270e78cbe89e6f337f2f1fe40315be88f742b547151Steve BlockJIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool) 2716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{ 2726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen JSInterfaceJIT jit; 2736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen JumpList failures; 2742bde8e466a4451c7319e3a072d118917957d6554Steve Block failures.append(jit.branchPtr(NotEqual, Address(regT0), TrustedImmPtr(globalData->jsStringVPtr))); 2756c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen failures.append(jit.branchTest32(NonZero, Address(regT0, OBJECT_OFFSETOF(JSString, m_fiberCount)))); 2766c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2776c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // Load string length to regT1, and start the process of loading the data pointer into regT0 2786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.load32(Address(regT0, ThunkHelpers::jsStringLengthOffset()), regT1); 2796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.loadPtr(Address(regT0, ThunkHelpers::jsStringValueOffset()), regT0); 2806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.loadPtr(Address(regT0, ThunkHelpers::stringImplDataOffset()), regT0); 2816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large 2836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen failures.append(jit.branch32(AboveOrEqual, regT2, regT1)); 2846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2856c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // Load the character 2866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.load16(BaseIndex(regT0, regT2, TimesTwo, 0), regT0); 2876c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2882bde8e466a4451c7319e3a072d118917957d6554Steve Block failures.append(jit.branch32(AboveOrEqual, regT0, TrustedImm32(0x100))); 2892bde8e466a4451c7319e3a072d118917957d6554Steve Block jit.move(TrustedImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1); 2906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0); 2912bde8e466a4451c7319e3a072d118917957d6554Steve Block jit.move(TrustedImm32(JSValue::CellTag), regT1); // We null check regT0 on return so this is safe 2926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.ret(); 2936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen failures.link(&jit); 2952bde8e466a4451c7319e3a072d118917957d6554Steve Block jit.move(TrustedImm32(0), regT0); 2966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen jit.ret(); 2976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 298dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(&jit, pool, 0); 299e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return patchBuffer.finalizeCode().m_code; 3006c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen} 3016c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 302692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_get_by_val(Instruction* currentInstruction) 303692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 304692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 305692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 306692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 307692e5dbf12901edacf14812a6fae25462920af42Steve Block 308692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad2(base, regT1, regT0, property, regT3, regT2); 309692e5dbf12901edacf14812a6fae25462920af42Steve Block 3102bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag))); 311692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT1); 3122bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr))); 313692e5dbf12901edacf14812a6fae25462920af42Steve Block 3142bde8e466a4451c7319e3a072d118917957d6554Steve Block loadPtr(Address(regT0, JSArray::storageOffset()), regT3); 3152bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset()))); 316692e5dbf12901edacf14812a6fae25462920af42Steve Block 317dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag 318dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload 3192bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag))); 320692e5dbf12901edacf14812a6fae25462920af42Steve Block 321692e5dbf12901edacf14812a6fae25462920af42Steve Block emitStore(dst, regT1, regT0); 322e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0); 323692e5dbf12901edacf14812a6fae25462920af42Steve Block} 324692e5dbf12901edacf14812a6fae25462920af42Steve Block 325692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 326692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 327692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 328692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 329692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 330692e5dbf12901edacf14812a6fae25462920af42Steve Block 331692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // property int32 check 332692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, base); // base cell check 3336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 3346c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen Jump nonCell = jump(); 335692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // base array check 3362bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump notString = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)); 337e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block emitNakedCall(m_globalData->getCTIStub(stringGetByValStubGenerator)); 3386c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen Jump failed = branchTestPtr(Zero, regT0); 3396c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen emitStore(dst, regT1, regT0); 3406c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val)); 3416c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen failed.link(this); 3426c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen notString.link(this); 3436c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen nonCell.link(this); 3446c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 345692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // vector length check 346692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // empty value 347692e5dbf12901edacf14812a6fae25462920af42Steve Block 348692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_get_by_val); 349692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 350692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(property); 351692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(dst); 352692e5dbf12901edacf14812a6fae25462920af42Steve Block} 353692e5dbf12901edacf14812a6fae25462920af42Steve Block 354692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_by_val(Instruction* currentInstruction) 355692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 356692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 357692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 358692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned value = currentInstruction[3].u.operand; 359692e5dbf12901edacf14812a6fae25462920af42Steve Block 360692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad2(base, regT1, regT0, property, regT3, regT2); 361692e5dbf12901edacf14812a6fae25462920af42Steve Block 3622bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag))); 363692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT1); 3642bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr))); 3652bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset()))); 366692e5dbf12901edacf14812a6fae25462920af42Steve Block 3672bde8e466a4451c7319e3a072d118917957d6554Steve Block loadPtr(Address(regT0, JSArray::storageOffset()), regT3); 368692e5dbf12901edacf14812a6fae25462920af42Steve Block 3692bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); 370692e5dbf12901edacf14812a6fae25462920af42Steve Block 371692e5dbf12901edacf14812a6fae25462920af42Steve Block Label storeResult(this); 372692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad(value, regT1, regT0); 373dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload 374dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag 375692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump end = jump(); 376692e5dbf12901edacf14812a6fae25462920af42Steve Block 377692e5dbf12901edacf14812a6fae25462920af42Steve Block empty.link(this); 3782bde8e466a4451c7319e3a072d118917957d6554Steve Block add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); 379dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this); 380692e5dbf12901edacf14812a6fae25462920af42Steve Block 3812bde8e466a4451c7319e3a072d118917957d6554Steve Block add32(TrustedImm32(1), regT2, regT0); 382dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))); 383692e5dbf12901edacf14812a6fae25462920af42Steve Block jump().linkTo(storeResult, this); 384692e5dbf12901edacf14812a6fae25462920af42Steve Block 385692e5dbf12901edacf14812a6fae25462920af42Steve Block end.link(this); 386692e5dbf12901edacf14812a6fae25462920af42Steve Block} 387692e5dbf12901edacf14812a6fae25462920af42Steve Block 388692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 389692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 390692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[1].u.operand; 391692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[2].u.operand; 392692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned value = currentInstruction[3].u.operand; 393692e5dbf12901edacf14812a6fae25462920af42Steve Block 394692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // property int32 check 395692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, base); // base cell check 396692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // base not array check 397692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); // in vector check 398692e5dbf12901edacf14812a6fae25462920af42Steve Block 399692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubPutByValCall(this, cti_op_put_by_val); 400692e5dbf12901edacf14812a6fae25462920af42Steve Block stubPutByValCall.addArgument(base); 401692e5dbf12901edacf14812a6fae25462920af42Steve Block stubPutByValCall.addArgument(property); 402692e5dbf12901edacf14812a6fae25462920af42Steve Block stubPutByValCall.addArgument(value); 403692e5dbf12901edacf14812a6fae25462920af42Steve Block stubPutByValCall.call(); 404692e5dbf12901edacf14812a6fae25462920af42Steve Block} 405692e5dbf12901edacf14812a6fae25462920af42Steve Block 406692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_get_by_id(Instruction* currentInstruction) 407692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 408692e5dbf12901edacf14812a6fae25462920af42Steve Block int dst = currentInstruction[1].u.operand; 409692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[2].u.operand; 410692e5dbf12901edacf14812a6fae25462920af42Steve Block 411692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad(base, regT1, regT0); 412692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT1); 413692e5dbf12901edacf14812a6fae25462920af42Steve Block compileGetByIdHotPath(); 414692e5dbf12901edacf14812a6fae25462920af42Steve Block emitStore(dst, regT1, regT0); 415e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0); 416692e5dbf12901edacf14812a6fae25462920af42Steve Block} 417692e5dbf12901edacf14812a6fae25462920af42Steve Block 418692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::compileGetByIdHotPath() 419692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 420692e5dbf12901edacf14812a6fae25462920af42Steve Block // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched. 421692e5dbf12901edacf14812a6fae25462920af42Steve Block // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump 422692e5dbf12901edacf14812a6fae25462920af42Steve Block // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label 423692e5dbf12901edacf14812a6fae25462920af42Steve Block // to jump back to if one of these trampolies finds a match. 424692e5dbf12901edacf14812a6fae25462920af42Steve Block 425692e5dbf12901edacf14812a6fae25462920af42Steve Block BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); 426692e5dbf12901edacf14812a6fae25462920af42Steve Block 427692e5dbf12901edacf14812a6fae25462920af42Steve Block Label hotPathBegin(this); 428692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; 429692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 430692e5dbf12901edacf14812a6fae25462920af42Steve Block 431692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabelPtr structureToCompare; 4322bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); 433692e5dbf12901edacf14812a6fae25462920af42Steve Block addSlowCase(structureCheck); 43481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetGetByIdStructure); 43581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureCheck), patchOffsetGetByIdBranchToSlowCase); 436692e5dbf12901edacf14812a6fae25462920af42Steve Block 43781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT2); 438692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabel32 displacementLabel1 = loadPtrWithAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT0); // payload 43981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel1), patchOffsetGetByIdPropertyMapOffset1); 440692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabel32 displacementLabel2 = loadPtrWithAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT1); // tag 44181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel2), patchOffsetGetByIdPropertyMapOffset2); 442692e5dbf12901edacf14812a6fae25462920af42Steve Block 443692e5dbf12901edacf14812a6fae25462920af42Steve Block Label putResult(this); 44481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, putResult), patchOffsetGetByIdPutResult); 445692e5dbf12901edacf14812a6fae25462920af42Steve Block 446692e5dbf12901edacf14812a6fae25462920af42Steve Block END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); 447692e5dbf12901edacf14812a6fae25462920af42Steve Block} 448692e5dbf12901edacf14812a6fae25462920af42Steve Block 449692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 450692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 451692e5dbf12901edacf14812a6fae25462920af42Steve Block int dst = currentInstruction[1].u.operand; 452692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[2].u.operand; 453692e5dbf12901edacf14812a6fae25462920af42Steve Block int ident = currentInstruction[3].u.operand; 454692e5dbf12901edacf14812a6fae25462920af42Steve Block 455692e5dbf12901edacf14812a6fae25462920af42Steve Block compileGetByIdSlowCase(dst, base, &(m_codeBlock->identifier(ident)), iter); 456692e5dbf12901edacf14812a6fae25462920af42Steve Block} 457692e5dbf12901edacf14812a6fae25462920af42Steve Block 458692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::compileGetByIdSlowCase(int dst, int base, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck) 459692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 460692e5dbf12901edacf14812a6fae25462920af42Steve Block // As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset 461692e5dbf12901edacf14812a6fae25462920af42Steve Block // so that we only need track one pointer into the slow case code - we track a pointer to the location 462692e5dbf12901edacf14812a6fae25462920af42Steve Block // of the call (which we can use to look up the patch information), but should a array-length or 463692e5dbf12901edacf14812a6fae25462920af42Steve Block // prototype access trampoline fail we want to bail out back to here. To do so we can subtract back 464692e5dbf12901edacf14812a6fae25462920af42Steve Block // the distance from the call to the head of the slow case. 465692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, base); 466692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); 467692e5dbf12901edacf14812a6fae25462920af42Steve Block 468692e5dbf12901edacf14812a6fae25462920af42Steve Block BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); 469692e5dbf12901edacf14812a6fae25462920af42Steve Block 470692e5dbf12901edacf14812a6fae25462920af42Steve Block#ifndef NDEBUG 471692e5dbf12901edacf14812a6fae25462920af42Steve Block Label coldPathBegin(this); 472692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 473692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, isMethodCheck ? cti_op_get_by_id_method_check : cti_op_get_by_id); 474692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(regT1, regT0); 4752bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(ident)); 476692e5dbf12901edacf14812a6fae25462920af42Steve Block Call call = stubCall.call(dst); 477692e5dbf12901edacf14812a6fae25462920af42Steve Block 4782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch END_UNINTERRUPTED_SEQUENCE_FOR_PUT(sequenceGetByIdSlowCase, dst); 479692e5dbf12901edacf14812a6fae25462920af42Steve Block 48081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(coldPathBegin, call), patchOffsetGetByIdSlowCaseCall); 481692e5dbf12901edacf14812a6fae25462920af42Steve Block 482692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the location of the call; this will be used to recover patch information. 483692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].callReturnLocation = call; 484692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 485692e5dbf12901edacf14812a6fae25462920af42Steve Block} 486692e5dbf12901edacf14812a6fae25462920af42Steve Block 487692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_put_by_id(Instruction* currentInstruction) 488692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 489692e5dbf12901edacf14812a6fae25462920af42Steve Block // In order to be able to patch both the Structure, and the object offset, we store one pointer, 490692e5dbf12901edacf14812a6fae25462920af42Steve Block // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code 491692e5dbf12901edacf14812a6fae25462920af42Steve Block // such that the Structure & offset are always at the same distance from this. 492692e5dbf12901edacf14812a6fae25462920af42Steve Block 493692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[1].u.operand; 494692e5dbf12901edacf14812a6fae25462920af42Steve Block int value = currentInstruction[3].u.operand; 495692e5dbf12901edacf14812a6fae25462920af42Steve Block 496692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad2(base, regT1, regT0, value, regT3, regT2); 497692e5dbf12901edacf14812a6fae25462920af42Steve Block 498692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT1); 499692e5dbf12901edacf14812a6fae25462920af42Steve Block 500692e5dbf12901edacf14812a6fae25462920af42Steve Block BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById); 501692e5dbf12901edacf14812a6fae25462920af42Steve Block 502692e5dbf12901edacf14812a6fae25462920af42Steve Block Label hotPathBegin(this); 503692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; 504692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 505692e5dbf12901edacf14812a6fae25462920af42Steve Block 506692e5dbf12901edacf14812a6fae25462920af42Steve Block // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over. 507692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabelPtr structureToCompare; 5082bde8e466a4451c7319e3a072d118917957d6554Steve Block addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)))); 50981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure); 510692e5dbf12901edacf14812a6fae25462920af42Steve Block 51181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT0); 512692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT0, patchGetByIdDefaultOffset)); // payload 513692e5dbf12901edacf14812a6fae25462920af42Steve Block DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT0, patchGetByIdDefaultOffset)); // tag 514692e5dbf12901edacf14812a6fae25462920af42Steve Block 515692e5dbf12901edacf14812a6fae25462920af42Steve Block END_UNINTERRUPTED_SEQUENCE(sequencePutById); 516692e5dbf12901edacf14812a6fae25462920af42Steve Block 51781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel1), patchOffsetPutByIdPropertyMapOffset1); 51881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel2), patchOffsetPutByIdPropertyMapOffset2); 519692e5dbf12901edacf14812a6fae25462920af42Steve Block} 520692e5dbf12901edacf14812a6fae25462920af42Steve Block 521692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 522692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 523692e5dbf12901edacf14812a6fae25462920af42Steve Block int base = currentInstruction[1].u.operand; 524692e5dbf12901edacf14812a6fae25462920af42Steve Block int ident = currentInstruction[2].u.operand; 525e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke int direct = currentInstruction[8].u.operand; 526e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 527692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, base); 528692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); 529692e5dbf12901edacf14812a6fae25462920af42Steve Block 530e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id); 531692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(regT1, regT0); 5322bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident)))); 533692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(regT3, regT2); 534692e5dbf12901edacf14812a6fae25462920af42Steve Block Call call = stubCall.call(); 535692e5dbf12901edacf14812a6fae25462920af42Steve Block 536692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the location of the call; this will be used to recover patch information. 537692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].callReturnLocation = call; 538692e5dbf12901edacf14812a6fae25462920af42Steve Block m_propertyAccessInstructionIndex++; 539692e5dbf12901edacf14812a6fae25462920af42Steve Block} 540692e5dbf12901edacf14812a6fae25462920af42Steve Block 541692e5dbf12901edacf14812a6fae25462920af42Steve Block// Compile a store into an object's property storage. May overwrite base. 542692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, Structure* structure, size_t cachedOffset) 543692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 544692e5dbf12901edacf14812a6fae25462920af42Steve Block int offset = cachedOffset; 545692e5dbf12901edacf14812a6fae25462920af42Steve Block if (structure->isUsingInlineStorage()) 54681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch offset += JSObject::offsetOfInlineStorage() / sizeof(Register); 547692e5dbf12901edacf14812a6fae25462920af42Steve Block else 54881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), base); 549692e5dbf12901edacf14812a6fae25462920af42Steve Block emitStore(offset, valueTag, valuePayload, base); 550692e5dbf12901edacf14812a6fae25462920af42Steve Block} 551692e5dbf12901edacf14812a6fae25462920af42Steve Block 552692e5dbf12901edacf14812a6fae25462920af42Steve Block// Compile a load from an object's property storage. May overwrite base. 553692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset) 554692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 555692e5dbf12901edacf14812a6fae25462920af42Steve Block int offset = cachedOffset; 55681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (structure->isUsingInlineStorage()) { 55781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch offset += JSObject::offsetOfInlineStorage() / sizeof(Register); 55881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch emitLoad(offset, resultTag, resultPayload, base); 55981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } else { 56081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch RegisterID temp = resultPayload; 56181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), temp); 56281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch emitLoad(offset, resultTag, resultPayload, temp); 56381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } 564692e5dbf12901edacf14812a6fae25462920af42Steve Block} 565692e5dbf12901edacf14812a6fae25462920af42Steve Block 56681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset) 567692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 56881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch load32(reinterpret_cast<char*>(&base->m_propertyStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), resultPayload); 56981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch load32(reinterpret_cast<char*>(&base->m_propertyStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag), resultTag); 570692e5dbf12901edacf14812a6fae25462920af42Steve Block} 571692e5dbf12901edacf14812a6fae25462920af42Steve Block 572dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochvoid JIT::testPrototype(JSValue prototype, JumpList& failureCases) 573692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 574dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch if (prototype.isNull()) 575692e5dbf12901edacf14812a6fae25462920af42Steve Block return; 576692e5dbf12901edacf14812a6fae25462920af42Steve Block 577dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch // We have a special case for X86_64 here because X86 instructions that take immediate values 578dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit 579dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch // values. In the non X86_64 case, the generated code is slightly more efficient because it uses 580dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch // two less instructions and doesn't require any scratch registers. 581dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if CPU(X86_64) 5822bde8e466a4451c7319e3a072d118917957d6554Steve Block move(TrustedImmPtr(prototype.asCell()->structure()), regT3); 5832bde8e466a4451c7319e3a072d118917957d6554Steve Block failureCases.append(branchPtr(NotEqual, AbsoluteAddress(prototype.asCell()->addressOfStructure()), regT3)); 584dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#else 5852bde8e466a4451c7319e3a072d118917957d6554Steve Block failureCases.append(branchPtr(NotEqual, AbsoluteAddress(prototype.asCell()->addressOfStructure()), TrustedImmPtr(prototype.asCell()->structure()))); 586dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#endif 587692e5dbf12901edacf14812a6fae25462920af42Steve Block} 588692e5dbf12901edacf14812a6fae25462920af42Steve Block 5895ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) 590692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 591692e5dbf12901edacf14812a6fae25462920af42Steve Block // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag. The value can be found on the stack. 592692e5dbf12901edacf14812a6fae25462920af42Steve Block 593692e5dbf12901edacf14812a6fae25462920af42Steve Block JumpList failureCases; 5942bde8e466a4451c7319e3a072d118917957d6554Steve Block failureCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); 5952bde8e466a4451c7319e3a072d118917957d6554Steve Block failureCases.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(oldStructure))); 596dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch testPrototype(oldStructure->storedPrototype(), failureCases); 597692e5dbf12901edacf14812a6fae25462920af42Steve Block 598e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!direct) { 599e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // Verify that nothing in the prototype chain has a setter for this property. 6002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) 601dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch testPrototype((*it)->storedPrototype(), failureCases); 602e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 603e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 604692e5dbf12901edacf14812a6fae25462920af42Steve Block // Reallocate property storage if needed. 605692e5dbf12901edacf14812a6fae25462920af42Steve Block Call callTarget; 606692e5dbf12901edacf14812a6fae25462920af42Steve Block bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity(); 607692e5dbf12901edacf14812a6fae25462920af42Steve Block if (willNeedStorageRealloc) { 608692e5dbf12901edacf14812a6fae25462920af42Steve Block // This trampoline was called to like a JIT stub; before we can can call again we need to 609692e5dbf12901edacf14812a6fae25462920af42Steve Block // remove the return address from the stack, to prevent the stack from becoming misaligned. 610692e5dbf12901edacf14812a6fae25462920af42Steve Block preserveReturnAddressAfterCall(regT3); 611692e5dbf12901edacf14812a6fae25462920af42Steve Block 612692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_put_by_id_transition_realloc); 613692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.skipArgument(); // base 614692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.skipArgument(); // ident 615692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.skipArgument(); // value 6162bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity())); 6172bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImm32(newStructure->propertyStorageCapacity())); 618692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(regT0); 619692e5dbf12901edacf14812a6fae25462920af42Steve Block 620692e5dbf12901edacf14812a6fae25462920af42Steve Block restoreReturnAddressBeforeReturn(regT3); 621692e5dbf12901edacf14812a6fae25462920af42Steve Block } 6222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 6232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch storePtrWithWriteBarrier(TrustedImmPtr(newStructure), regT0, Address(regT0, JSCell::structureOffset())); 624692e5dbf12901edacf14812a6fae25462920af42Steve Block 6252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if CPU(MIPS) || CPU(SH4) 6265abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick // For MIPS, we don't add sizeof(void*) to the stack offset. 6275abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3); 6285abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2); 6295abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#else 63006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3); 63106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2); 6325abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#endif 633692e5dbf12901edacf14812a6fae25462920af42Steve Block 634692e5dbf12901edacf14812a6fae25462920af42Steve Block // Write the value 635692e5dbf12901edacf14812a6fae25462920af42Steve Block compilePutDirectOffset(regT0, regT2, regT3, newStructure, cachedOffset); 636692e5dbf12901edacf14812a6fae25462920af42Steve Block 637692e5dbf12901edacf14812a6fae25462920af42Steve Block ret(); 638692e5dbf12901edacf14812a6fae25462920af42Steve Block 639692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(!failureCases.empty()); 640692e5dbf12901edacf14812a6fae25462920af42Steve Block failureCases.link(this); 641692e5dbf12901edacf14812a6fae25462920af42Steve Block restoreArgumentReferenceForTrampoline(); 642692e5dbf12901edacf14812a6fae25462920af42Steve Block Call failureCall = tailRecursiveCall(); 643692e5dbf12901edacf14812a6fae25462920af42Steve Block 644dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 6455ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 646e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); 647692e5dbf12901edacf14812a6fae25462920af42Steve Block 648692e5dbf12901edacf14812a6fae25462920af42Steve Block if (willNeedStorageRealloc) { 649692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(m_calls.size() == 1); 650692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(m_calls[0].from, FunctionPtr(cti_op_put_by_id_transition_realloc)); 651692e5dbf12901edacf14812a6fae25462920af42Steve Block } 652692e5dbf12901edacf14812a6fae25462920af42Steve Block 653692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 6545ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen stubInfo->stubRoutine = entryLabel; 655692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 656692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel); 657692e5dbf12901edacf14812a6fae25462920af42Steve Block} 658692e5dbf12901edacf14812a6fae25462920af42Steve Block 659692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) 660692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 661692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(codeBlock); 662692e5dbf12901edacf14812a6fae25462920af42Steve Block 663692e5dbf12901edacf14812a6fae25462920af42Steve Block // We don't want to patch more than once - in future go to cti_op_get_by_id_generic. 664692e5dbf12901edacf14812a6fae25462920af42Steve Block // Should probably go to JITStubs::cti_op_get_by_id_fail, but that doesn't do anything interesting right now. 665692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); 666692e5dbf12901edacf14812a6fae25462920af42Steve Block 667692e5dbf12901edacf14812a6fae25462920af42Steve Block int offset = sizeof(JSValue) * cachedOffset; 66881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 669692e5dbf12901edacf14812a6fae25462920af42Steve Block // Patch the offset into the propoerty map to load from, then patch the Structure to look for. 670692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure), structure); 67106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload 67206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag 673692e5dbf12901edacf14812a6fae25462920af42Steve Block} 674692e5dbf12901edacf14812a6fae25462920af42Steve Block 6752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid JIT::patchMethodCallProto(JSGlobalData& globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) 676692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 677692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(codeBlock); 678692e5dbf12901edacf14812a6fae25462920af42Steve Block 679692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(!methodCallLinkInfo.cachedStructure); 6802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch methodCallLinkInfo.cachedStructure.set(globalData, codeBlock->ownerExecutable(), structure); 681692e5dbf12901edacf14812a6fae25462920af42Steve Block Structure* prototypeStructure = proto->structure(); 6822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch methodCallLinkInfo.cachedPrototypeStructure.set(globalData, codeBlock->ownerExecutable(), prototypeStructure); 683692e5dbf12901edacf14812a6fae25462920af42Steve Block 684692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(methodCallLinkInfo.structureLabel, structure); 685692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), proto); 686692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoStruct), prototypeStructure); 687692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction), callee); 688692e5dbf12901edacf14812a6fae25462920af42Steve Block 689692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id)); 690692e5dbf12901edacf14812a6fae25462920af42Steve Block} 691692e5dbf12901edacf14812a6fae25462920af42Steve Block 692e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkevoid JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct) 693692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 694692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(codeBlock); 695692e5dbf12901edacf14812a6fae25462920af42Steve Block 696692e5dbf12901edacf14812a6fae25462920af42Steve Block // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. 697692e5dbf12901edacf14812a6fae25462920af42Steve Block // Should probably go to cti_op_put_by_id_fail, but that doesn't do anything interesting right now. 698e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 699692e5dbf12901edacf14812a6fae25462920af42Steve Block 700692e5dbf12901edacf14812a6fae25462920af42Steve Block int offset = sizeof(JSValue) * cachedOffset; 70181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 702692e5dbf12901edacf14812a6fae25462920af42Steve Block // Patch the offset into the propoerty map to load from, then patch the Structure to look for. 703692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure), structure); 70406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload 70506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag 706692e5dbf12901edacf14812a6fae25462920af42Steve Block} 707692e5dbf12901edacf14812a6fae25462920af42Steve Block 7085ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) 709692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 7105ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress); 7115ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 712692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 713692e5dbf12901edacf14812a6fae25462920af42Steve Block 714692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check for array 7152bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump failureCases1 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)); 716692e5dbf12901edacf14812a6fae25462920af42Steve Block 717692e5dbf12901edacf14812a6fae25462920af42Steve Block // Checks out okay! - get the length from the storage 7182bde8e466a4451c7319e3a072d118917957d6554Steve Block loadPtr(Address(regT0, JSArray::storageOffset()), regT2); 719dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2); 720692e5dbf12901edacf14812a6fae25462920af42Steve Block 7212bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump failureCases2 = branch32(Above, regT2, TrustedImm32(INT_MAX)); 722692e5dbf12901edacf14812a6fae25462920af42Steve Block move(regT2, regT0); 7232bde8e466a4451c7319e3a072d118917957d6554Steve Block move(TrustedImm32(JSValue::Int32Tag), regT1); 724692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 725692e5dbf12901edacf14812a6fae25462920af42Steve Block 726dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 7275ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 728692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 729692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); 730692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases1, slowCaseBegin); 731692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases2, slowCaseBegin); 732692e5dbf12901edacf14812a6fae25462920af42Steve Block 733692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 734692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 735692e5dbf12901edacf14812a6fae25462920af42Steve Block 736692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the stub we have created so that it will be deleted later. 737692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 7385ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen stubInfo->stubRoutine = entryLabel; 7395ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 740692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 741692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 742692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 743692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 744692e5dbf12901edacf14812a6fae25462920af42Steve Block 745692e5dbf12901edacf14812a6fae25462920af42Steve Block // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. 746692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail)); 747692e5dbf12901edacf14812a6fae25462920af42Steve Block} 748692e5dbf12901edacf14812a6fae25462920af42Steve Block 7495ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) 750692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 751692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 752692e5dbf12901edacf14812a6fae25462920af42Steve Block 753692e5dbf12901edacf14812a6fae25462920af42Steve Block // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is 754692e5dbf12901edacf14812a6fae25462920af42Steve Block // referencing the prototype object - let's speculatively load it's table nice and early!) 755692e5dbf12901edacf14812a6fae25462920af42Steve Block JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); 756692e5dbf12901edacf14812a6fae25462920af42Steve Block 757692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump failureCases1 = checkStructure(regT0, structure); 758692e5dbf12901edacf14812a6fae25462920af42Steve Block 759692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check the prototype object's Structure had not changed. 7602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const void* prototypeStructureAddress = protoObject->addressOfStructure(); 761692e5dbf12901edacf14812a6fae25462920af42Steve Block#if CPU(X86_64) 7622bde8e466a4451c7319e3a072d118917957d6554Steve Block move(TrustedImmPtr(prototypeStructure), regT3); 763692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); 764692e5dbf12901edacf14812a6fae25462920af42Steve Block#else 7652bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), TrustedImmPtr(prototypeStructure)); 766692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 767dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool needsStubLink = false; 768dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Checks out okay! 769dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (slot.cachedPropertyType() == PropertySlot::Getter) { 770dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 77181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset); 772dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_getter_stub); 773dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT1); 774dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 7752bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 776dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 777dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (slot.cachedPropertyType() == PropertySlot::Custom) { 778dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 779dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_custom_stub); 7802bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(protoObject)); 7812bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress())); 7822bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident))); 7832bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 784dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 785dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 78681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); 787692e5dbf12901edacf14812a6fae25462920af42Steve Block 788692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 789692e5dbf12901edacf14812a6fae25462920af42Steve Block 790dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 7915ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 792692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 793692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); 794692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases1, slowCaseBegin); 795692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases2, slowCaseBegin); 796692e5dbf12901edacf14812a6fae25462920af42Steve Block 797692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 798692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 799dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 800dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (needsStubLink) { 801dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { 802dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (iter->to) 803dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block patchBuffer.link(iter->from, FunctionPtr(iter->to)); 804dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 805dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 806dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 807692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the stub we have created so that it will be deleted later. 808692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 8095ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen stubInfo->stubRoutine = entryLabel; 810692e5dbf12901edacf14812a6fae25462920af42Steve Block 811692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 812692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 813692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 814692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 815692e5dbf12901edacf14812a6fae25462920af42Steve Block 816692e5dbf12901edacf14812a6fae25462920af42Steve Block // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. 817692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); 818692e5dbf12901edacf14812a6fae25462920af42Steve Block} 819692e5dbf12901edacf14812a6fae25462920af42Steve Block 820692e5dbf12901edacf14812a6fae25462920af42Steve Block 8215ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) 822692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 823692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 824692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump failureCase = checkStructure(regT0, structure); 825dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool needsStubLink = false; 826dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (slot.cachedPropertyType() == PropertySlot::Getter) { 827dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 82881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(regT0, regT2, regT1, structure, cachedOffset); 829dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_getter_stub); 830dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT1); 831dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 8322bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 833dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 834dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (slot.cachedPropertyType() == PropertySlot::Custom) { 835dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 836dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_custom_stub); 837dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 8382bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress())); 8392bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident))); 8402bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 841dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 842dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 843dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block compileGetDirectOffset(regT0, regT1, regT0, structure, cachedOffset); 844dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 845692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 846692e5dbf12901edacf14812a6fae25462920af42Steve Block 847dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 848dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (needsStubLink) { 849dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { 850dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (iter->to) 851dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block patchBuffer.link(iter->from, FunctionPtr(iter->to)); 852dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 853dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 854692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 855692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel lastProtoBegin = polymorphicStructures->list[currentIndex - 1].stubRoutine; 856692e5dbf12901edacf14812a6fae25462920af42Steve Block if (!lastProtoBegin) 857692e5dbf12901edacf14812a6fae25462920af42Steve Block lastProtoBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); 858692e5dbf12901edacf14812a6fae25462920af42Steve Block 859692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCase, lastProtoBegin); 860692e5dbf12901edacf14812a6fae25462920af42Steve Block 861692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 862692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 863dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 864692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 8652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 8662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure); 867692e5dbf12901edacf14812a6fae25462920af42Steve Block 868692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 869692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 870692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 871692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 872692e5dbf12901edacf14812a6fae25462920af42Steve Block} 873692e5dbf12901edacf14812a6fae25462920af42Steve Block 8745ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) 875692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 876692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 877692e5dbf12901edacf14812a6fae25462920af42Steve Block 878692e5dbf12901edacf14812a6fae25462920af42Steve Block // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is 879692e5dbf12901edacf14812a6fae25462920af42Steve Block // referencing the prototype object - let's speculatively load it's table nice and early!) 880692e5dbf12901edacf14812a6fae25462920af42Steve Block JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); 881692e5dbf12901edacf14812a6fae25462920af42Steve Block 882692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check eax is an object of the right Structure. 883692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump failureCases1 = checkStructure(regT0, structure); 884692e5dbf12901edacf14812a6fae25462920af42Steve Block 885692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check the prototype object's Structure had not changed. 8862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const void* prototypeStructureAddress = protoObject->addressOfStructure(); 887692e5dbf12901edacf14812a6fae25462920af42Steve Block#if CPU(X86_64) 8882bde8e466a4451c7319e3a072d118917957d6554Steve Block move(TrustedImmPtr(prototypeStructure), regT3); 889692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); 890692e5dbf12901edacf14812a6fae25462920af42Steve Block#else 8912bde8e466a4451c7319e3a072d118917957d6554Steve Block Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), TrustedImmPtr(prototypeStructure)); 892692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif 893692e5dbf12901edacf14812a6fae25462920af42Steve Block 894dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool needsStubLink = false; 895dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (slot.cachedPropertyType() == PropertySlot::Getter) { 896dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 89781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset); 898dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_getter_stub); 899dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT1); 900dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 9012bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 902dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 903dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (slot.cachedPropertyType() == PropertySlot::Custom) { 904dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 905dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_custom_stub); 9062bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(protoObject)); 9072bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress())); 9082bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident))); 9092bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 910dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 911dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 91281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); 913692e5dbf12901edacf14812a6fae25462920af42Steve Block 914692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 915692e5dbf12901edacf14812a6fae25462920af42Steve Block 916dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 917dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (needsStubLink) { 918dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { 919dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (iter->to) 920dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block patchBuffer.link(iter->from, FunctionPtr(iter->to)); 921dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 922dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 923692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 924692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine; 925692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases1, lastProtoBegin); 926692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(failureCases2, lastProtoBegin); 927692e5dbf12901edacf14812a6fae25462920af42Steve Block 928692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 929692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 930692e5dbf12901edacf14812a6fae25462920af42Steve Block 931692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 9322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 9332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, prototypeStructure); 934692e5dbf12901edacf14812a6fae25462920af42Steve Block 935692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 936692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 937692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 938692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 939692e5dbf12901edacf14812a6fae25462920af42Steve Block} 940692e5dbf12901edacf14812a6fae25462920af42Steve Block 9415ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) 942692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 943692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 944692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(count); 945692e5dbf12901edacf14812a6fae25462920af42Steve Block 946692e5dbf12901edacf14812a6fae25462920af42Steve Block JumpList bucketsOfFail; 947692e5dbf12901edacf14812a6fae25462920af42Steve Block 948692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check eax is an object of the right Structure. 949692e5dbf12901edacf14812a6fae25462920af42Steve Block bucketsOfFail.append(checkStructure(regT0, structure)); 950692e5dbf12901edacf14812a6fae25462920af42Steve Block 951692e5dbf12901edacf14812a6fae25462920af42Steve Block Structure* currStructure = structure; 9522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WriteBarrier<Structure>* it = chain->head(); 953692e5dbf12901edacf14812a6fae25462920af42Steve Block JSObject* protoObject = 0; 954dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch for (unsigned i = 0; i < count; ++i, ++it) { 955692e5dbf12901edacf14812a6fae25462920af42Steve Block protoObject = asObject(currStructure->prototypeForLookup(callFrame)); 956dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch currStructure = it->get(); 957dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch testPrototype(protoObject, bucketsOfFail); 958692e5dbf12901edacf14812a6fae25462920af42Steve Block } 959692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(protoObject); 960692e5dbf12901edacf14812a6fae25462920af42Steve Block 961dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool needsStubLink = false; 962dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (slot.cachedPropertyType() == PropertySlot::Getter) { 963dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 96481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset); 965dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_getter_stub); 966dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT1); 967dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 9682bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 969dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 970dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (slot.cachedPropertyType() == PropertySlot::Custom) { 971dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 972dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_custom_stub); 9732bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(protoObject)); 9742bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress())); 9752bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident))); 9762bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 977dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 978dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 97981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); 980dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 981692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 982692e5dbf12901edacf14812a6fae25462920af42Steve Block 983dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 984dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (needsStubLink) { 985dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { 986dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (iter->to) 987dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block patchBuffer.link(iter->from, FunctionPtr(iter->to)); 988dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 989dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 990692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 991692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine; 992692e5dbf12901edacf14812a6fae25462920af42Steve Block 993692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(bucketsOfFail, lastProtoBegin); 994692e5dbf12901edacf14812a6fae25462920af42Steve Block 995692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 996692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 997692e5dbf12901edacf14812a6fae25462920af42Steve Block 998692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 999692e5dbf12901edacf14812a6fae25462920af42Steve Block 1000692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the stub we have created so that it will be deleted later. 10012bde8e466a4451c7319e3a072d118917957d6554Steve Block prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, chain); 1002692e5dbf12901edacf14812a6fae25462920af42Steve Block 1003692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 1004692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 1005692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 1006692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 1007692e5dbf12901edacf14812a6fae25462920af42Steve Block} 1008692e5dbf12901edacf14812a6fae25462920af42Steve Block 10095ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) 1010692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 1011692e5dbf12901edacf14812a6fae25462920af42Steve Block // regT0 holds a JSCell* 1012692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(count); 1013692e5dbf12901edacf14812a6fae25462920af42Steve Block 1014692e5dbf12901edacf14812a6fae25462920af42Steve Block JumpList bucketsOfFail; 1015692e5dbf12901edacf14812a6fae25462920af42Steve Block 1016692e5dbf12901edacf14812a6fae25462920af42Steve Block // Check eax is an object of the right Structure. 1017692e5dbf12901edacf14812a6fae25462920af42Steve Block bucketsOfFail.append(checkStructure(regT0, structure)); 1018692e5dbf12901edacf14812a6fae25462920af42Steve Block 1019692e5dbf12901edacf14812a6fae25462920af42Steve Block Structure* currStructure = structure; 10202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WriteBarrier<Structure>* it = chain->head(); 1021692e5dbf12901edacf14812a6fae25462920af42Steve Block JSObject* protoObject = 0; 1022dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch for (unsigned i = 0; i < count; ++i, ++it) { 1023692e5dbf12901edacf14812a6fae25462920af42Steve Block protoObject = asObject(currStructure->prototypeForLookup(callFrame)); 1024dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch currStructure = it->get(); 1025dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch testPrototype(protoObject, bucketsOfFail); 1026692e5dbf12901edacf14812a6fae25462920af42Steve Block } 1027692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(protoObject); 1028692e5dbf12901edacf14812a6fae25462920af42Steve Block 1029dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool needsStubLink = false; 1030dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (slot.cachedPropertyType() == PropertySlot::Getter) { 1031dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 103281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset); 1033dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_getter_stub); 1034dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT1); 1035dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.addArgument(regT0); 10362bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 1037dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 1038dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (slot.cachedPropertyType() == PropertySlot::Custom) { 1039dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block needsStubLink = true; 1040dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block JITStubCall stubCall(this, cti_op_get_by_id_custom_stub); 10412bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(protoObject)); 10422bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress())); 10432bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident))); 10442bde8e466a4451c7319e3a072d118917957d6554Steve Block stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress())); 1045dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stubCall.call(); 1046dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 104781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); 1048692e5dbf12901edacf14812a6fae25462920af42Steve Block Jump success = jump(); 1049692e5dbf12901edacf14812a6fae25462920af42Steve Block 1050dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); 1051dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (needsStubLink) { 1052dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { 1053dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (iter->to) 1054dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block patchBuffer.link(iter->from, FunctionPtr(iter->to)); 1055dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 1056dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 1057692e5dbf12901edacf14812a6fae25462920af42Steve Block // Use the patch information to link the failure cases back to the original slow case routine. 1058692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(bucketsOfFail, stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall)); 1059692e5dbf12901edacf14812a6fae25462920af42Steve Block 1060692e5dbf12901edacf14812a6fae25462920af42Steve Block // On success return back to the hot patch code, at a point it will perform the store to dest for us. 1061692e5dbf12901edacf14812a6fae25462920af42Steve Block patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); 1062692e5dbf12901edacf14812a6fae25462920af42Steve Block 1063692e5dbf12901edacf14812a6fae25462920af42Steve Block // Track the stub we have created so that it will be deleted later. 1064692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); 10655ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen stubInfo->stubRoutine = entryLabel; 10665ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 1067692e5dbf12901edacf14812a6fae25462920af42Steve Block // Finally patch the jump to slow case back in the hot path to jump here instead. 1068692e5dbf12901edacf14812a6fae25462920af42Steve Block CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); 1069692e5dbf12901edacf14812a6fae25462920af42Steve Block RepatchBuffer repatchBuffer(m_codeBlock); 1070692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relink(jumpLocation, entryLabel); 1071692e5dbf12901edacf14812a6fae25462920af42Steve Block 1072692e5dbf12901edacf14812a6fae25462920af42Steve Block // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. 1073692e5dbf12901edacf14812a6fae25462920af42Steve Block repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); 1074692e5dbf12901edacf14812a6fae25462920af42Steve Block} 1075692e5dbf12901edacf14812a6fae25462920af42Steve Block 1076692e5dbf12901edacf14812a6fae25462920af42Steve Block/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ 1077692e5dbf12901edacf14812a6fae25462920af42Steve Block 1078692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1079692e5dbf12901edacf14812a6fae25462920af42Steve Block 108081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset) 1081692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 1082692e5dbf12901edacf14812a6fae25462920af42Steve Block ASSERT(sizeof(JSValue) == 8); 1083692e5dbf12901edacf14812a6fae25462920af42Steve Block 108481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), base); 1085692e5dbf12901edacf14812a6fae25462920af42Steve Block loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); 1086692e5dbf12901edacf14812a6fae25462920af42Steve Block loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); 1087692e5dbf12901edacf14812a6fae25462920af42Steve Block} 1088692e5dbf12901edacf14812a6fae25462920af42Steve Block 1089692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emit_op_get_by_pname(Instruction* currentInstruction) 1090692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 1091692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 1092692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 1093692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 1094692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned expected = currentInstruction[4].u.operand; 1095692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned iter = currentInstruction[5].u.operand; 1096692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned i = currentInstruction[6].u.operand; 1097692e5dbf12901edacf14812a6fae25462920af42Steve Block 1098692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoad2(property, regT1, regT0, base, regT3, regT2); 1099692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(property, regT1); 1100692e5dbf12901edacf14812a6fae25462920af42Steve Block addSlowCase(branchPtr(NotEqual, regT0, payloadFor(expected))); 1101692e5dbf12901edacf14812a6fae25462920af42Steve Block // Property registers are now available as the property is known 1102692e5dbf12901edacf14812a6fae25462920af42Steve Block emitJumpSlowCaseIfNotJSCell(base, regT3); 1103692e5dbf12901edacf14812a6fae25462920af42Steve Block emitLoadPayload(iter, regT1); 1104692e5dbf12901edacf14812a6fae25462920af42Steve Block 1105692e5dbf12901edacf14812a6fae25462920af42Steve Block // Test base's structure 11062bde8e466a4451c7319e3a072d118917957d6554Steve Block loadPtr(Address(regT2, JSCell::structureOffset()), regT0); 1107692e5dbf12901edacf14812a6fae25462920af42Steve Block addSlowCase(branchPtr(NotEqual, regT0, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))); 1108692e5dbf12901edacf14812a6fae25462920af42Steve Block load32(addressFor(i), regT3); 11092bde8e466a4451c7319e3a072d118917957d6554Steve Block sub32(TrustedImm32(1), regT3); 1110692e5dbf12901edacf14812a6fae25462920af42Steve Block addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots)))); 111181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch compileGetDirectOffset(regT2, regT1, regT0, regT3); 1112692e5dbf12901edacf14812a6fae25462920af42Steve Block 1113692e5dbf12901edacf14812a6fae25462920af42Steve Block emitStore(dst, regT1, regT0); 1114e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_pname), dst, regT1, regT0); 1115692e5dbf12901edacf14812a6fae25462920af42Steve Block} 1116692e5dbf12901edacf14812a6fae25462920af42Steve Block 1117692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1118692e5dbf12901edacf14812a6fae25462920af42Steve Block{ 1119692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned dst = currentInstruction[1].u.operand; 1120692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned base = currentInstruction[2].u.operand; 1121692e5dbf12901edacf14812a6fae25462920af42Steve Block unsigned property = currentInstruction[3].u.operand; 1122692e5dbf12901edacf14812a6fae25462920af42Steve Block 1123692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, property); 1124692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); 1125692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCaseIfNotJSCell(iter, base); 1126692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); 1127692e5dbf12901edacf14812a6fae25462920af42Steve Block linkSlowCase(iter); 1128692e5dbf12901edacf14812a6fae25462920af42Steve Block 1129692e5dbf12901edacf14812a6fae25462920af42Steve Block JITStubCall stubCall(this, cti_op_get_by_val); 1130692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(base); 1131692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.addArgument(property); 1132692e5dbf12901edacf14812a6fae25462920af42Steve Block stubCall.call(dst); 1133692e5dbf12901edacf14812a6fae25462920af42Steve Block} 1134692e5dbf12901edacf14812a6fae25462920af42Steve Block 1135692e5dbf12901edacf14812a6fae25462920af42Steve Block} // namespace JSC 1136692e5dbf12901edacf14812a6fae25462920af42Steve Block 1137e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#endif // USE(JSVALUE32_64) 1138692e5dbf12901edacf14812a6fae25462920af42Steve Block#endif // ENABLE(JIT) 1139