diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/jit/JITOpcodes32_64.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/jit/JITOpcodes32_64.cpp')
-rw-r--r-- | Source/JavaScriptCore/jit/JITOpcodes32_64.cpp | 773 |
1 files changed, 317 insertions, 456 deletions
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index c326ff3e0..29e8880aa 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2012-2016 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> * * Redistribution and use in source and binary forms, with or without @@ -32,17 +32,14 @@ #include "CCallHelpers.h" #include "Debugger.h" -#include "Exception.h" #include "JITInlines.h" #include "JSArray.h" #include "JSCell.h" -#include "JSEnvironmentRecord.h" #include "JSFunction.h" -#include "JSPropertyNameEnumerator.h" +#include "JSPropertyNameIterator.h" +#include "JSVariableObject.h" #include "LinkBuffer.h" -#include "MaxFrameExtentForSlowPathCall.h" #include "SlowPathCall.h" -#include "TypeProfilerLog.h" #include "VirtualRegister.h" namespace JSC { @@ -51,24 +48,41 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func) { Call nativeCall; - emitFunctionPrologue(); - emitPutToCallFrameHeader(0, JSStack::CodeBlock); + emitPutImmediateToCallFrameHeader(0, JSStack::CodeBlock); storePtr(callFrameRegister, &m_vm->topCallFrame); #if CPU(X86) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetCallerFrameFromCallFrameHeaderPtr(regT0); + emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT0); + emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain); + + peek(regT1); + emitPutReturnPCToCallFrameHeader(regT1); + // Calling convention: f(ecx, edx, ...); // Host function signature: f(ExecState*); move(callFrameRegister, X86Registers::ecx); - subPtr(TrustedImm32(8), stackPointerRegister); // Align stack for call. - storePtr(X86Registers::ecx, Address(stackPointerRegister)); + subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call. + + move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. // call the function nativeCall = call(); - addPtr(TrustedImm32(8), stackPointerRegister); + addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); #elif CPU(ARM) || CPU(SH4) || CPU(MIPS) + // Load caller frame's scope chain into this callframe so that whatever we call can get to its global data. + emitGetCallerFrameFromCallFrameHeaderPtr(regT2); + emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT2); + emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain); + + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutReturnPCToCallFrameHeader(regT3); + #if CPU(MIPS) // Allocate stack space for (unused) 16 bytes (8-byte aligned) for 4 arguments. subPtr(TrustedImm32(16), stackPointerRegister); @@ -79,6 +93,7 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func) move(callFrameRegister, argumentGPR0); emitGetFromCallFrameHeaderPtr(JSStack::Callee, argumentGPR1); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. loadPtr(Address(argumentGPR1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); // call the function @@ -92,25 +107,28 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func) restoreReturnAddressBeforeReturn(regT3); #else #error "JIT not supported on this platform." - abortWithReason(JITNotSupported); + breakpoint(); #endif // CPU(X86) // Check for an exception - Jump sawException = branch32(NotEqual, AbsoluteAddress(vm->addressOfException()), TrustedImm32(0)); + Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(vm->addressOfException()) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); - emitFunctionEpilogue(); // Return. ret(); // Handle an exception sawException.link(this); + // Grab the return address. + preserveReturnAddressAfterCall(regT1); + + move(TrustedImmPtr(&vm->exceptionLocation), regT2); + storePtr(regT1, regT2); storePtr(callFrameRegister, &m_vm->topCallFrame); #if CPU(X86) - addPtr(TrustedImm32(-4), stackPointerRegister); - move(callFrameRegister, X86Registers::ecx); - push(X86Registers::ecx); + addPtr(TrustedImm32(-12), stackPointerRegister); + push(callFrameRegister); #else move(callFrameRegister, argumentGPR0); #endif @@ -118,13 +136,13 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func) call(regT3); #if CPU(X86) - addPtr(TrustedImm32(8), stackPointerRegister); + addPtr(TrustedImm32(16), stackPointerRegister); #endif jumpToExceptionHandler(); // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - LinkBuffer patchBuffer(*m_vm, *this, GLOBAL_THUNK_ID); + LinkBuffer patchBuffer(*m_vm, this, GLOBAL_THUNK_ID); patchBuffer.link(nativeCall, FunctionPtr(func)); return FINALIZE_CODE(patchBuffer, ("JIT CTI native call")); @@ -143,12 +161,21 @@ void JIT::emit_op_mov(Instruction* currentInstruction) } } +void JIT::emit_op_captured_mov(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + emitNotifyWrite(regT1, regT0, regT2, currentInstruction[3].u.watchpointSet); + emitStore(dst, regT1, regT0); +} + void JIT::emit_op_end(Instruction* currentInstruction) { ASSERT(returnValueGPR != callFrameRegister); - emitLoad(currentInstruction[1].u.operand, regT1, returnValueGPR); - emitRestoreCalleeSaves(); - emitFunctionEpilogue(); + emitLoad(currentInstruction[1].u.operand, regT1, regT0); + restoreReturnAddressBeforeReturn(Address(callFrameRegister, CallFrame::returnPCOffset())); ret(); } @@ -164,9 +191,9 @@ void JIT::emit_op_new_object(Instruction* currentInstruction) size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize); - RegisterID resultReg = returnValueGPR; + RegisterID resultReg = regT0; RegisterID allocatorReg = regT1; - RegisterID scratchReg = regT3; + RegisterID scratchReg = regT2; move(TrustedImmPtr(allocator), allocatorReg); emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg); @@ -182,31 +209,18 @@ void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCas emitStoreCell(dst, returnValueGPR); } -void JIT::emit_op_overrides_has_instance(Instruction* currentInstruction) +void JIT::emit_op_check_has_instance(Instruction* currentInstruction) { - int dst = currentInstruction[1].u.operand; - int constructor = currentInstruction[2].u.operand; - int hasInstanceValue = currentInstruction[3].u.operand; - - emitLoadPayload(hasInstanceValue, regT0); - // We don't jump if we know what Symbol.hasInstance would do. - Jump hasInstanceValueNotCell = emitJumpIfNotJSCell(hasInstanceValue); - Jump customhasInstanceValue = branchPtr(NotEqual, regT0, TrustedImmPtr(m_codeBlock->globalObject()->functionProtoHasInstanceSymbolFunction())); - - // We know that constructor is an object from the way bytecode is emitted for instanceof expressions. - emitLoadPayload(constructor, regT0); - - // Check that constructor 'ImplementsDefaultHasInstance' i.e. the object is not a C-API user nor a bound function. - test8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance), regT0); - Jump done = jump(); + int baseVal = currentInstruction[3].u.operand; - hasInstanceValueNotCell.link(this); - customhasInstanceValue.link(this); - move(TrustedImm32(1), regT0); - - done.link(this); - emitStoreBool(dst, regT0); + emitLoadPayload(baseVal, regT0); + // Check that baseVal is a cell. + emitJumpSlowCaseIfNotJSCell(baseVal); + + // Check that baseVal 'ImplementsHasInstance'. + loadPtr(Address(regT0, JSCell::structureOffset()), regT0); + addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); } void JIT::emit_op_instanceof(Instruction* currentInstruction) @@ -220,12 +234,13 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitLoadPayload(value, regT2); emitLoadPayload(proto, regT1); - // Check that proto are cells. baseVal must be a cell - this is checked by the get_by_id for Symbol.hasInstance. + // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. emitJumpSlowCaseIfNotJSCell(value); emitJumpSlowCaseIfNotJSCell(proto); // Check that prototype is an object - addSlowCase(emitJumpIfCellNotObject(regT1)); + loadPtr(Address(regT1, JSCell::structureOffset()), regT3); + addSlowCase(emitJumpIfNotObject(regT3)); // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. @@ -235,7 +250,7 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN! // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. - loadPtr(Address(regT2, JSCell::structureIDOffset()), regT2); + loadPtr(Address(regT2, JSCell::structureOffset()), regT2); load32(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); Jump isInstance = branchPtr(Equal, regT2, regT1); branchTest32(NonZero, regT2).linkTo(loop, this); @@ -248,41 +263,35 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) emitStoreBool(dst, regT0); } -void JIT::emit_op_instanceof_custom(Instruction*) -{ - // This always goes to slow path since we expect it to be rare. - addSlowCase(jump()); -} - -void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { int dst = currentInstruction[1].u.operand; int value = currentInstruction[2].u.operand; - int proto = currentInstruction[3].u.operand; + int baseVal = currentInstruction[3].u.operand; - linkSlowCaseIfNotJSCell(iter, value); - linkSlowCaseIfNotJSCell(iter, proto); + linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCase(iter); emitLoad(value, regT1, regT0); - emitLoad(proto, regT3, regT2); - callOperation(operationInstanceOf, dst, regT1, regT0, regT3, regT2); + emitLoad(baseVal, regT3, regT2); + callOperation(operationCheckHasInstance, dst, regT1, regT0, regT3, regT2); + + emitJumpSlowToHot(jump(), currentInstruction[4].u.operand); } -void JIT::emitSlow_op_instanceof_custom(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { int dst = currentInstruction[1].u.operand; int value = currentInstruction[2].u.operand; - int constructor = currentInstruction[3].u.operand; - int hasInstanceValue = currentInstruction[4].u.operand; + int proto = currentInstruction[3].u.operand; + linkSlowCaseIfNotJSCell(iter, value); + linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); emitLoad(value, regT1, regT0); - emitLoadPayload(constructor, regT2); - emitLoad(hasInstanceValue, regT4, regT3); - callOperation(operationInstanceOfCustom, regT1, regT0, regT2, regT4, regT3); - emitStoreBool(dst, returnValueGPR); + emitLoad(proto, regT3, regT2); + callOperation(operationInstanceOf, dst, regT1, regT0, regT3, regT2); } void JIT::emit_op_is_undefined(Instruction* currentInstruction) @@ -297,12 +306,12 @@ void JIT::emit_op_is_undefined(Instruction* currentInstruction) Jump done = jump(); isCell.link(this); - Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); + loadPtr(Address(regT0, JSCell::structureOffset()), regT1); + Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); move(TrustedImm32(0), regT0); Jump notMasqueradesAsUndefined = jump(); isMasqueradesAsUndefined.link(this); - loadPtr(Address(regT0, JSCell::structureIDOffset()), regT1); move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); loadPtr(Address(regT1, Structure::globalObjectOffset()), regT1); compare32(Equal, regT0, regT1, regT0); @@ -341,7 +350,8 @@ void JIT::emit_op_is_string(Instruction* currentInstruction) emitLoad(value, regT1, regT0); Jump isNotCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - compare8(Equal, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType), regT0); + loadPtr(Address(regT0, JSCell::structureOffset()), regT1); + compare8(Equal, Address(regT1, Structure::typeInfoTypeOffset()), TrustedImm32(StringType), regT0); Jump done = jump(); isNotCell.link(this); @@ -351,22 +361,25 @@ void JIT::emit_op_is_string(Instruction* currentInstruction) emitStoreBool(dst, regT0); } -void JIT::emit_op_is_object(Instruction* currentInstruction) +void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) { - int dst = currentInstruction[1].u.operand; - int value = currentInstruction[2].u.operand; - - emitLoad(value, regT1, regT0); - Jump isNotCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - - compare8(AboveOrEqual, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType), regT0); - Jump done = jump(); + int activation = currentInstruction[1].u.operand; + Jump activationNotCreated = branch32(Equal, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag)); + emitLoadPayload(activation, regT0); + callOperation(operationTearOffActivation, regT0); + activationNotCreated.link(this); +} - isNotCell.link(this); - move(TrustedImm32(0), regT0); +void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction) +{ + VirtualRegister arguments = VirtualRegister(currentInstruction[1].u.operand); + int activation = currentInstruction[2].u.operand; - done.link(this); - emitStoreBool(dst, regT0); + Jump argsNotCreated = branch32(Equal, tagFor(unmodifiedArgumentsRegister(arguments).offset()), TrustedImm32(JSValue::EmptyValueTag)); + emitLoadPayload(unmodifiedArgumentsRegister(VirtualRegister(arguments)).offset(), regT0); + emitLoadPayload(activation, regT1); + callOperation(operationTearOffArguments, regT0, regT1); + argsNotCreated.link(this); } void JIT::emit_op_to_primitive(Instruction* currentInstruction) @@ -377,7 +390,7 @@ void JIT::emit_op_to_primitive(Instruction* currentInstruction) emitLoad(src, regT1, regT0); Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - addSlowCase(emitJumpIfCellObject(regT0)); + addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); isImm.link(this); if (dst != src) @@ -497,8 +510,9 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - Jump isNotMasqueradesAsUndefined = branchTest8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); - loadPtr(Address(regT0, JSCell::structureIDOffset()), regT2); + // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + Jump isNotMasqueradesAsUndefined = branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); addJump(branchPtr(Equal, Address(regT2, Structure::globalObjectOffset()), regT0), target); Jump masqueradesGlobalObjectIsForeign = jump(); @@ -522,8 +536,9 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - addJump(branchTest8(Zero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target); - loadPtr(Address(regT0, JSCell::structureIDOffset()), regT2); + // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target); move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); addJump(branchPtr(NotEqual, Address(regT2, Structure::globalObjectOffset()), regT0), target); Jump wasNotImmediate = jump(); @@ -577,8 +592,8 @@ void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>: genericCase.append(getSlowCase(iter)); // tags not equal linkSlowCase(iter); // tags equal and JSCell - genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); - genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); + genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); + genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); // String case. callOperation(operationCompareStringEq, regT0, regT2); @@ -621,8 +636,8 @@ void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry> genericCase.append(getSlowCase(iter)); // tags not equal linkSlowCase(iter); // tags equal and JSCell - genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); - genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); + genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); + genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); // String case. callOperation(operationCompareStringEq, regT0, regT2); @@ -650,12 +665,12 @@ void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqTy addSlowCase(branch32(NotEqual, regT1, regT3)); addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag))); - // Jump to a slow case if both are strings or symbols (non object). + // Jump to a slow case if both are strings. Jump notCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - Jump firstIsObject = emitJumpIfCellObject(regT0); - addSlowCase(emitJumpIfCellNotObject(regT2)); + Jump firstNotString = branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())); + addSlowCase(branchPtr(Equal, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()))); notCell.link(this); - firstIsObject.link(this); + firstNotString.link(this); // Simply compare the payloads. if (type == OpStrictEq) @@ -704,12 +719,12 @@ void JIT::emit_op_eq_null(Instruction* currentInstruction) emitLoad(src, regT1, regT0); Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); move(TrustedImm32(0), regT1); Jump wasNotMasqueradesAsUndefined = jump(); isMasqueradesAsUndefined.link(this); - loadPtr(Address(regT0, JSCell::structureIDOffset()), regT2); move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2); compare32(Equal, regT0, regT2, regT1); @@ -735,12 +750,12 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction) emitLoad(src, regT1, regT0); Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); - Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT0, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); move(TrustedImm32(1), regT1); Jump wasNotMasqueradesAsUndefined = jump(); isMasqueradesAsUndefined.link(this); - loadPtr(Address(regT0, JSCell::structureIDOffset()), regT2); move(TrustedImmPtr(m_codeBlock->globalObject()), regT0); loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2); compare32(NotEqual, regT0, regT2, regT1); @@ -761,116 +776,165 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction) void JIT::emit_op_throw(Instruction* currentInstruction) { ASSERT(regT0 == returnValueGPR); - copyCalleeSavesToVMCalleeSavesBuffer(); emitLoad(currentInstruction[1].u.operand, regT1, regT0); callOperationNoExceptionCheck(operationThrow, regT1, regT0); jumpToExceptionHandler(); } -void JIT::emit_op_push_with_scope(Instruction* currentInstruction) +void JIT::emit_op_get_pnames(Instruction* currentInstruction) { - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_push_with_scope); - slowPathCall.call(); + int dst = currentInstruction[1].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int breakTarget = currentInstruction[5].u.operand; + + JumpList isNotObject; + + emitLoad(base, regT1, regT0); + if (!m_codeBlock->isKnownNotImmediate(base)) + isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); + if (VirtualRegister(base) != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) { + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + isNotObject.append(emitJumpIfNotObject(regT2)); + } + + // We could inline the case where you have a valid cache, but + // this call doesn't seem to be hot. + Label isObject(this); + callOperation(operationGetPNames, regT0); + emitStoreCell(dst, returnValueGPR); + load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); + store32(TrustedImm32(Int32Tag), intTagFor(i)); + store32(TrustedImm32(0), intPayloadFor(i)); + store32(TrustedImm32(Int32Tag), intTagFor(size)); + store32(regT3, payloadFor(size)); + Jump end = jump(); + + isNotObject.link(this); + addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget); + addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget); + callOperation(operationToObject, base, regT1, regT0); + jump().linkTo(isObject, this); + + end.link(this); } -void JIT::emit_op_to_number(Instruction* currentInstruction) +void JIT::emit_op_next_pname(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; - int src = currentInstruction[2].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int it = currentInstruction[5].u.operand; + int target = currentInstruction[6].u.operand; - emitLoad(src, regT1, regT0); + JumpList callHasProperty; - Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag)); - addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::LowestTag))); - isInt32.link(this); + Label begin(this); + load32(intPayloadFor(i), regT0); + Jump end = branch32(Equal, regT0, intPayloadFor(size)); - if (src != dst) - emitStore(dst, regT1, regT0); + // Grab key @ i + loadPtr(payloadFor(it), regT1); + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); + load32(BaseIndex(regT2, regT0, TimesEight), regT2); + store32(TrustedImm32(JSValue::CellTag), tagFor(dst)); + store32(regT2, payloadFor(dst)); + + // Increment i + add32(TrustedImm32(1), regT0); + store32(regT0, intPayloadFor(i)); + + // Verify that i is valid: + loadPtr(payloadFor(base), regT0); + + // Test base's structure + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); + + // Test base's prototype chain + loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); + loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); + addJump(branchTestPtr(Zero, Address(regT3)), target); + + Label checkPrototype(this); + callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag))); + loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); + loadPtr(Address(regT2, JSCell::structureOffset()), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); + addPtr(TrustedImm32(sizeof(Structure*)), regT3); + branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); + + // Continue loop. + addJump(jump(), target); + + // Slow case: Ask the object if i is valid. + callHasProperty.link(this); + loadPtr(addressFor(dst), regT1); + callOperation(operationHasProperty, regT0, regT1); + + // Test for valid key. + addJump(branchTest32(NonZero, regT0), target); + jump().linkTo(begin, this); + + // End of loop. + end.link(this); } -void JIT::emitSlow_op_to_number(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emit_op_push_with_scope(Instruction* currentInstruction) { - linkSlowCase(iter); + emitLoad(currentInstruction[1].u.operand, regT1, regT0); + callOperation(operationPushWithScope, regT1, regT0); +} - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_number); - slowPathCall.call(); +void JIT::emit_op_pop_scope(Instruction*) +{ + callOperation(operationPopScope); } -void JIT::emit_op_to_string(Instruction* currentInstruction) +void JIT::emit_op_to_number(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; int src = currentInstruction[2].u.operand; emitLoad(src, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); - addSlowCase(branch8(NotEqual, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType))); + Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag)); + addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::LowestTag))); + isInt32.link(this); if (src != dst) emitStore(dst, regT1, regT0); } -void JIT::emitSlow_op_to_string(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emitSlow_op_to_number(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - linkSlowCase(iter); // Not JSCell. - linkSlowCase(iter); // Not JSString. + linkSlowCase(iter); - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_string); + JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_number); slowPathCall.call(); } -void JIT::emit_op_catch(Instruction* currentInstruction) +void JIT::emit_op_push_name_scope(Instruction* currentInstruction) { - restoreCalleeSavesFromVMCalleeSavesBuffer(); + emitLoad(currentInstruction[2].u.operand, regT1, regT0); + callOperation(operationPushNameScope, &m_codeBlock->identifier(currentInstruction[1].u.operand), regT1, regT0, currentInstruction[3].u.operand); +} +void JIT::emit_op_catch(Instruction* currentInstruction) +{ move(TrustedImmPtr(m_vm), regT3); // operationThrow returns the callFrame for the handler. - load32(Address(regT3, VM::callFrameForCatchOffset()), callFrameRegister); - storePtr(TrustedImmPtr(nullptr), Address(regT3, VM::callFrameForCatchOffset())); - - addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister); - - callOperationNoExceptionCheck(operationCheckIfExceptionIsUncatchableAndNotifyProfiler); - Jump isCatchableException = branchTest32(Zero, returnValueGPR); - jumpToExceptionHandler(); - isCatchableException.link(this); - - move(TrustedImmPtr(m_vm), regT3); - + load32(Address(regT3, VM::callFrameForThrowOffset()), callFrameRegister); // Now store the exception returned by operationThrow. - load32(Address(regT3, VM::exceptionOffset()), regT2); - move(TrustedImm32(JSValue::CellTag), regT1); - - store32(TrustedImm32(0), Address(regT3, VM::exceptionOffset())); + load32(Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); + load32(Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); + store32(TrustedImm32(JSValue().payload()), Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + store32(TrustedImm32(JSValue().tag()), Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); unsigned exception = currentInstruction[1].u.operand; - emitStore(exception, regT1, regT2); - - load32(Address(regT2, Exception::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); - load32(Address(regT2, Exception::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); - - unsigned thrownValue = currentInstruction[2].u.operand; - emitStore(thrownValue, regT1, regT0); -} - -void JIT::emit_op_assert(Instruction* currentInstruction) -{ - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_assert); - slowPathCall.call(); -} - -void JIT::emit_op_create_lexical_environment(Instruction* currentInstruction) -{ - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_lexical_environment); - slowPathCall.call(); -} - -void JIT::emit_op_get_parent_scope(Instruction* currentInstruction) -{ - int currentScope = currentInstruction[2].u.operand; - emitLoadPayload(currentScope, regT0); - loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0); - emitStoreCell(currentInstruction[1].u.operand, regT0); + emitStore(exception, regT1, regT0); } void JIT::emit_op_switch_imm(Instruction* currentInstruction) @@ -882,7 +946,7 @@ void JIT::emit_op_switch_imm(Instruction* currentInstruction) // create jump table for switch destinations, track this switch statement. SimpleJumpTable* jumpTable = &m_codeBlock->switchJumpTable(tableIndex); m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate)); - jumpTable->ensureCTITable(); + jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); emitLoad(scrutinee, regT1, regT0); callOperation(operationSwitchImmWithUnknownKeyType, regT1, regT0, tableIndex); @@ -898,7 +962,7 @@ void JIT::emit_op_switch_char(Instruction* currentInstruction) // create jump table for switch destinations, track this switch statement. SimpleJumpTable* jumpTable = &m_codeBlock->switchJumpTable(tableIndex); m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character)); - jumpTable->ensureCTITable(); + jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); emitLoad(scrutinee, regT1, regT0); callOperation(operationSwitchCharWithUnknownKeyType, regT1, regT0, tableIndex); @@ -949,48 +1013,77 @@ void JIT::emit_op_enter(Instruction* currentInstruction) slowPathCall.call(); } -void JIT::emit_op_get_scope(Instruction* currentInstruction) +void JIT::emit_op_create_activation(Instruction* currentInstruction) +{ + int activation = currentInstruction[1].u.operand; + + Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag)); + callOperation(operationCreateActivation, 0); + emitStoreCell(activation, returnValueGPR); + activationCreated.link(this); +} + +void JIT::emit_op_create_arguments(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + + Jump argsCreated = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag)); + callOperation(operationCreateArguments); + emitStoreCell(dst, returnValueGPR); + emitStoreCell(unmodifiedArgumentsRegister(VirtualRegister(dst)).offset(), returnValueGPR); + argsCreated.link(this); +} + +void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; + + emitStore(dst, JSValue()); +} + +void JIT::emit_op_get_callee(Instruction* currentInstruction) +{ + int result = currentInstruction[1].u.operand; + WriteBarrierBase<JSCell>* cachedFunction = ¤tInstruction[2].u.jsCell; emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0); - loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT0); - emitStoreCell(dst, regT0); + + loadPtr(cachedFunction, regT2); + addSlowCase(branchPtr(NotEqual, regT0, regT2)); + + move(TrustedImm32(JSValue::CellTag), regT1); + emitStore(result, regT1, regT0); +} + +void JIT::emitSlow_op_get_callee(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + + JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_callee); + slowPathCall.call(); } void JIT::emit_op_create_this(Instruction* currentInstruction) { int callee = currentInstruction[2].u.operand; - WriteBarrierBase<JSCell>* cachedFunction = ¤tInstruction[4].u.jsCell; RegisterID calleeReg = regT0; - RegisterID rareDataReg = regT4; RegisterID resultReg = regT0; RegisterID allocatorReg = regT1; RegisterID structureReg = regT2; - RegisterID cachedFunctionReg = regT4; RegisterID scratchReg = regT3; emitLoadPayload(callee, calleeReg); - loadPtr(Address(calleeReg, JSFunction::offsetOfRareData()), rareDataReg); - addSlowCase(branchTestPtr(Zero, rareDataReg)); - loadPtr(Address(rareDataReg, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg); - loadPtr(Address(rareDataReg, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg); + loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg); + loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg); addSlowCase(branchTestPtr(Zero, allocatorReg)); - loadPtr(cachedFunction, cachedFunctionReg); - Jump hasSeenMultipleCallees = branchPtr(Equal, cachedFunctionReg, TrustedImmPtr(JSCell::seenMultipleCalleeObjects())); - addSlowCase(branchPtr(NotEqual, calleeReg, cachedFunctionReg)); - hasSeenMultipleCallees.link(this); - emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg); emitStoreCell(currentInstruction[1].u.operand, resultReg); } void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - linkSlowCase(iter); // doesn't have rare data linkSlowCase(iter); // doesn't have an allocation profile linkSlowCase(iter); // allocation failed - linkSlowCase(iter); // cached function didn't match JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_this); slowPathCall.call(); @@ -1004,8 +1097,8 @@ void JIT::emit_op_to_this(Instruction* currentInstruction) emitLoad(thisRegister, regT3, regT2); addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag))); - addSlowCase(branch8(NotEqual, Address(regT2, JSCell::typeInfoTypeOffset()), TrustedImm32(FinalObjectType))); - loadPtr(Address(regT2, JSCell::structureIDOffset()), regT0); + loadPtr(Address(regT2, JSCell::structureOffset()), regT0); + addSlowCase(branch8(NotEqual, Address(regT0, Structure::typeInfoTypeOffset()), TrustedImm32(FinalObjectType))); loadPtr(cachedStructure, regT2); addSlowCase(branchPtr(NotEqual, regT0, regT2)); } @@ -1019,19 +1112,6 @@ void JIT::emitSlow_op_to_this(Instruction* currentInstruction, Vector<SlowCaseEn slowPathCall.call(); } -void JIT::emit_op_check_tdz(Instruction* currentInstruction) -{ - emitLoadTag(currentInstruction[1].u.operand, regT0); - addSlowCase(branch32(Equal, regT0, TrustedImm32(JSValue::EmptyValueTag))); -} - -void JIT::emitSlow_op_check_tdz(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - linkSlowCase(iter); - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_throw_tdz_error); - slowPathCall.call(); -} - void JIT::emit_op_profile_will_call(Instruction* currentInstruction) { load32(m_vm->enabledProfilerAddress(), regT0); @@ -1050,282 +1130,63 @@ void JIT::emit_op_profile_did_call(Instruction* currentInstruction) profilerDone.link(this); } -void JIT::emit_op_has_structure_property(Instruction* currentInstruction) +void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; - int base = currentInstruction[2].u.operand; - int enumerator = currentInstruction[4].u.operand; - - emitLoadPayload(base, regT0); - emitJumpSlowCaseIfNotJSCell(base); - - emitLoadPayload(enumerator, regT1); - - load32(Address(regT0, JSCell::structureIDOffset()), regT0); - addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset()))); - - move(TrustedImm32(1), regT0); - emitStoreBool(dst, regT0); + int argumentsRegister = currentInstruction[2].u.operand; + addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag))); + load32(payloadFor(JSStack::ArgumentCount), regT0); + sub32(TrustedImm32(1), regT0); + emitStoreInt32(dst, regT0); } -void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode) -{ - Instruction* currentInstruction = m_codeBlock->instructions().begin() + byValInfo->bytecodeIndex; - - PatchableJump badType; - - // FIXME: Add support for other types like TypedArrays and Arguments. - // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034. - JumpList slowCases = emitLoadForArrayMode(currentInstruction, arrayMode, badType); - move(TrustedImm32(1), regT0); - Jump done = jump(); - - LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock); - - patchBuffer.link(badType, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath)); - patchBuffer.link(slowCases, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath)); - - patchBuffer.link(done, byValInfo->badTypeJump.labelAtOffset(byValInfo->badTypeJumpToDone)); - - byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB( - m_codeBlock, patchBuffer, - ("Baseline has_indexed_property stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.value())); - - MacroAssembler::repatchJump(byValInfo->badTypeJump, CodeLocationLabel(byValInfo->stubRoutine->code().code())); - MacroAssembler::repatchCall(CodeLocationCall(MacroAssemblerCodePtr(returnAddress)), FunctionPtr(operationHasIndexedPropertyGeneric)); -} - -void JIT::emit_op_has_indexed_property(Instruction* currentInstruction) +void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { + linkSlowCase(iter); int dst = currentInstruction[1].u.operand; int base = currentInstruction[2].u.operand; - int property = currentInstruction[3].u.operand; - ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - ByValInfo* byValInfo = m_codeBlock->addByValInfo(); - - emitLoadPayload(base, regT0); - emitJumpSlowCaseIfNotJSCell(base); - - emitLoadPayload(property, regT1); - - // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter. - // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if - // number was signed since m_vectorLength is always less than intmax (since the total allocation - // size is always less than 4Gb). As such zero extending will have been correct (and extending the value - // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign - // extending since it makes it easier to re-tag the value in the slow case. - zeroExtend32ToPtr(regT1, regT1); - - emitArrayProfilingSiteWithCell(regT0, regT2, profile); - and32(TrustedImm32(IndexingShapeMask), regT2); - - JITArrayMode mode = chooseArrayMode(profile); - PatchableJump badType; - - // FIXME: Add support for other types like TypedArrays and Arguments. - // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034. - JumpList slowCases = emitLoadForArrayMode(currentInstruction, mode, badType); - move(TrustedImm32(1), regT0); - - addSlowCase(badType); - addSlowCase(slowCases); - - Label done = label(); - - emitStoreBool(dst, regT0); - - Label nextHotPath = label(); - - m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, PatchableJump(), badType, mode, profile, done, nextHotPath)); + callOperation(operationGetArgumentsLength, dst, base); } -void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; - int base = currentInstruction[2].u.operand; + int argumentsRegister = currentInstruction[2].u.operand; int property = currentInstruction[3].u.operand; - ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo; - - linkSlowCaseIfNotJSCell(iter, base); // base cell check - linkSlowCase(iter); // base array check - linkSlowCase(iter); // vector length check - linkSlowCase(iter); // empty value - - Label slowPath = label(); - - emitLoad(base, regT1, regT0); - emitLoad(property, regT3, regT2); - Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, byValInfo); - - m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; - m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call; - m_byValInstructionIndex++; -} - -void JIT::emit_op_get_direct_pname(Instruction* currentInstruction) -{ - int dst = currentInstruction[1].u.operand; - int base = currentInstruction[2].u.operand; - int index = currentInstruction[4].u.operand; - int enumerator = currentInstruction[5].u.operand; - - // Check that base is a cell - emitLoadPayload(base, regT0); - emitJumpSlowCaseIfNotJSCell(base); - - // Check the structure - emitLoadPayload(enumerator, regT1); - load32(Address(regT0, JSCell::structureIDOffset()), regT2); - addSlowCase(branch32(NotEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset()))); - - // Compute the offset - emitLoadPayload(index, regT2); - // If index is less than the enumerator's cached inline storage, then it's an inline access - Jump outOfLineAccess = branch32(AboveOrEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset())); - addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0); - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); - - Jump done = jump(); - - // Otherwise it's out of line - outOfLineAccess.link(this); - loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0); - addSlowCase(branchIfNotToSpace(regT0)); - sub32(Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT2); - neg32(regT2); - int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue); - load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); - load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); + addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag))); + emitLoad(property, regT1, regT2); + addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); + add32(TrustedImm32(1), regT2); + // regT2 now contains the integer index of the argument we want, including this + load32(payloadFor(JSStack::ArgumentCount), regT3); + addSlowCase(branch32(AboveOrEqual, regT2, regT3)); - done.link(this); + loadPtr(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT0); + loadPtr(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT1); emitValueProfilingSite(); emitStore(dst, regT1, regT0); } -void JIT::emitSlow_op_get_direct_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - int base = currentInstruction[2].u.operand; - linkSlowCaseIfNotJSCell(iter, base); - linkSlowCase(iter); - linkSlowCase(iter); - - JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_direct_pname); - slowPathCall.call(); -} - -void JIT::emit_op_enumerator_structure_pname(Instruction* currentInstruction) -{ - int dst = currentInstruction[1].u.operand; - int enumerator = currentInstruction[2].u.operand; - int index = currentInstruction[3].u.operand; - - emitLoadPayload(index, regT0); - emitLoadPayload(enumerator, regT1); - Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endStructurePropertyIndexOffset())); - - move(TrustedImm32(JSValue::NullTag), regT2); - move(TrustedImm32(0), regT0); - - Jump done = jump(); - inBounds.link(this); - - loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1); - loadPtr(BaseIndex(regT1, regT0, timesPtr()), regT0); - move(TrustedImm32(JSValue::CellTag), regT2); - - done.link(this); - emitStore(dst, regT2, regT0); -} - -void JIT::emit_op_enumerator_generic_pname(Instruction* currentInstruction) +void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { int dst = currentInstruction[1].u.operand; - int enumerator = currentInstruction[2].u.operand; - int index = currentInstruction[3].u.operand; - - emitLoadPayload(index, regT0); - emitLoadPayload(enumerator, regT1); - Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endGenericPropertyIndexOffset())); + int arguments = currentInstruction[2].u.operand; + int property = currentInstruction[3].u.operand; - move(TrustedImm32(JSValue::NullTag), regT2); - move(TrustedImm32(0), regT0); + linkSlowCase(iter); + Jump skipArgumentsCreation = jump(); - Jump done = jump(); - inBounds.link(this); + linkSlowCase(iter); + linkSlowCase(iter); - loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1); - loadPtr(BaseIndex(regT1, regT0, timesPtr()), regT0); - move(TrustedImm32(JSValue::CellTag), regT2); + callOperation(operationCreateArguments); + emitStoreCell(arguments, returnValueGPR); + emitStoreCell(unmodifiedArgumentsRegister(VirtualRegister(arguments)).offset(), returnValueGPR); - done.link(this); - emitStore(dst, regT2, regT0); -} - -void JIT::emit_op_profile_type(Instruction* currentInstruction) -{ - TypeLocation* cachedTypeLocation = currentInstruction[2].u.location; - int valueToProfile = currentInstruction[1].u.operand; - - // Load payload in T0. Load tag in T3. - emitLoadPayload(valueToProfile, regT0); - emitLoadTag(valueToProfile, regT3); - - JumpList jumpToEnd; - - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::EmptyValueTag))); - - // Compile in a predictive type check, if possible, to see if we can skip writing to the log. - // These typechecks are inlined to match those of the 32-bit JSValue type checks. - if (cachedTypeLocation->m_lastSeenType == TypeUndefined) - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::UndefinedTag))); - else if (cachedTypeLocation->m_lastSeenType == TypeNull) - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::NullTag))); - else if (cachedTypeLocation->m_lastSeenType == TypeBoolean) - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::BooleanTag))); - else if (cachedTypeLocation->m_lastSeenType == TypeMachineInt) - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::Int32Tag))); - else if (cachedTypeLocation->m_lastSeenType == TypeNumber) { - jumpToEnd.append(branch32(Below, regT3, TrustedImm32(JSValue::LowestTag))); - jumpToEnd.append(branch32(Equal, regT3, TrustedImm32(JSValue::Int32Tag))); - } else if (cachedTypeLocation->m_lastSeenType == TypeString) { - Jump isNotCell = branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)); - jumpToEnd.append(branch8(Equal, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType))); - isNotCell.link(this); - } - - // Load the type profiling log into T2. - TypeProfilerLog* cachedTypeProfilerLog = m_vm->typeProfilerLog(); - move(TrustedImmPtr(cachedTypeProfilerLog), regT2); - - // Load the next log entry into T1. - loadPtr(Address(regT2, TypeProfilerLog::currentLogEntryOffset()), regT1); - - // Store the JSValue onto the log entry. - store32(regT0, Address(regT1, TypeProfilerLog::LogEntry::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - store32(regT3, Address(regT1, TypeProfilerLog::LogEntry::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - - // Store the structureID of the cell if argument is a cell, otherwise, store 0 on the log entry. - Jump notCell = branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)); - load32(Address(regT0, JSCell::structureIDOffset()), regT0); - store32(regT0, Address(regT1, TypeProfilerLog::LogEntry::structureIDOffset())); - Jump skipNotCell = jump(); - notCell.link(this); - store32(TrustedImm32(0), Address(regT1, TypeProfilerLog::LogEntry::structureIDOffset())); - skipNotCell.link(this); - - // Store the typeLocation on the log entry. - move(TrustedImmPtr(cachedTypeLocation), regT0); - store32(regT0, Address(regT1, TypeProfilerLog::LogEntry::locationOffset())); - - // Increment the current log entry. - addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), regT1); - store32(regT1, Address(regT2, TypeProfilerLog::currentLogEntryOffset())); - jumpToEnd.append(branchPtr(NotEqual, regT1, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr()))); - // Clear the log if we're at the end of the log. - callOperation(operationProcessTypeProfilerLog); - - jumpToEnd.link(this); + skipArgumentsCreation.link(this); + emitLoad(arguments, regT1, regT0); + emitLoad(property, regT3, regT2); + callOperation(WithProfile, operationGetByValGeneric, dst, regT1, regT0, regT3, regT2); } } // namespace JSC |