2 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Intel Corporation. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "DFGSpeculativeJIT.h"
32 #include "ArrayPrototype.h"
33 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
34 #include "DFGSlowPathGenerator.h"
35 #include "JSActivation.h"
36 #include "ObjectPrototype.h"
37 #include "Operations.h"
39 namespace JSC
{ namespace DFG
{
43 GPRReg
SpeculativeJIT::fillInteger(Edge edge
, DataFormat
& returnFormat
)
45 ASSERT(!needsTypeCheck(edge
, SpecInt32
));
47 VirtualRegister virtualRegister
= edge
->virtualRegister();
48 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
50 if (info
.registerFormat() == DataFormatNone
) {
51 GPRReg gpr
= allocate();
53 if (edge
->hasConstant()) {
54 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
55 if (isInt32Constant(edge
.node()))
56 m_jit
.move(MacroAssembler::Imm32(valueOfInt32Constant(edge
.node())), gpr
);
57 else if (isNumberConstant(edge
.node()))
58 RELEASE_ASSERT_NOT_REACHED();
60 ASSERT(isJSConstant(edge
.node()));
61 JSValue jsValue
= valueOfJSConstant(edge
.node());
62 m_jit
.move(MacroAssembler::Imm32(jsValue
.payload()), gpr
);
65 ASSERT(info
.spillFormat() == DataFormatJS
|| info
.spillFormat() == DataFormatJSInteger
|| info
.spillFormat() == DataFormatInteger
);
66 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
67 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), gpr
);
70 info
.fillInteger(*m_stream
, gpr
);
71 returnFormat
= DataFormatInteger
;
75 switch (info
.registerFormat()) {
77 // Should have filled, above.
78 case DataFormatJSDouble
:
79 case DataFormatDouble
:
82 case DataFormatJSCell
:
83 case DataFormatBoolean
:
84 case DataFormatJSBoolean
:
85 case DataFormatStorage
:
86 // Should only be calling this function if we know this operand to be integer.
87 RELEASE_ASSERT_NOT_REACHED();
89 case DataFormatJSInteger
: {
90 GPRReg tagGPR
= info
.tagGPR();
91 GPRReg payloadGPR
= info
.payloadGPR();
93 m_jit
.jitAssertIsJSInt32(tagGPR
);
94 m_gprs
.unlock(tagGPR
);
95 m_gprs
.lock(payloadGPR
);
96 m_gprs
.release(tagGPR
);
97 m_gprs
.release(payloadGPR
);
98 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderInteger
);
99 info
.fillInteger(*m_stream
, payloadGPR
);
100 returnFormat
= DataFormatInteger
;
104 case DataFormatInteger
: {
105 GPRReg gpr
= info
.gpr();
107 m_jit
.jitAssertIsInt32(gpr
);
108 returnFormat
= DataFormatInteger
;
113 RELEASE_ASSERT_NOT_REACHED();
114 return InvalidGPRReg
;
118 bool SpeculativeJIT::fillJSValue(Edge edge
, GPRReg
& tagGPR
, GPRReg
& payloadGPR
, FPRReg
& fpr
)
120 // FIXME: For double we could fill with a FPR.
123 VirtualRegister virtualRegister
= edge
->virtualRegister();
124 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
126 switch (info
.registerFormat()) {
127 case DataFormatNone
: {
129 if (edge
->hasConstant()) {
131 payloadGPR
= allocate();
132 m_jit
.move(Imm32(valueOfJSConstant(edge
.node()).tag()), tagGPR
);
133 m_jit
.move(Imm32(valueOfJSConstant(edge
.node()).payload()), payloadGPR
);
134 m_gprs
.retain(tagGPR
, virtualRegister
, SpillOrderConstant
);
135 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderConstant
);
136 info
.fillJSValue(*m_stream
, tagGPR
, payloadGPR
, isInt32Constant(edge
.node()) ? DataFormatJSInteger
: DataFormatJS
);
138 DataFormat spillFormat
= info
.spillFormat();
139 ASSERT(spillFormat
!= DataFormatNone
&& spillFormat
!= DataFormatStorage
);
141 payloadGPR
= allocate();
142 switch (spillFormat
) {
143 case DataFormatInteger
:
144 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), tagGPR
);
145 spillFormat
= DataFormatJSInteger
; // This will be used as the new register format.
148 m_jit
.move(TrustedImm32(JSValue::CellTag
), tagGPR
);
149 spillFormat
= DataFormatJSCell
; // This will be used as the new register format.
151 case DataFormatBoolean
:
152 m_jit
.move(TrustedImm32(JSValue::BooleanTag
), tagGPR
);
153 spillFormat
= DataFormatJSBoolean
; // This will be used as the new register format.
156 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), tagGPR
);
159 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), payloadGPR
);
160 m_gprs
.retain(tagGPR
, virtualRegister
, SpillOrderSpilled
);
161 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderSpilled
);
162 info
.fillJSValue(*m_stream
, tagGPR
, payloadGPR
, spillFormat
== DataFormatJSDouble
? DataFormatJS
: spillFormat
);
168 case DataFormatInteger
:
170 case DataFormatBoolean
: {
171 GPRReg gpr
= info
.gpr();
172 // If the register has already been locked we need to take a copy.
173 if (m_gprs
.isLocked(gpr
)) {
174 payloadGPR
= allocate();
175 m_jit
.move(gpr
, payloadGPR
);
181 uint32_t tag
= JSValue::EmptyValueTag
;
182 DataFormat fillFormat
= DataFormatJS
;
183 switch (info
.registerFormat()) {
184 case DataFormatInteger
:
185 tag
= JSValue::Int32Tag
;
186 fillFormat
= DataFormatJSInteger
;
189 tag
= JSValue::CellTag
;
190 fillFormat
= DataFormatJSCell
;
192 case DataFormatBoolean
:
193 tag
= JSValue::BooleanTag
;
194 fillFormat
= DataFormatJSBoolean
;
197 RELEASE_ASSERT_NOT_REACHED();
200 m_jit
.move(TrustedImm32(tag
), tagGPR
);
202 m_gprs
.retain(tagGPR
, virtualRegister
, SpillOrderJS
);
203 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderJS
);
204 info
.fillJSValue(*m_stream
, tagGPR
, payloadGPR
, fillFormat
);
208 case DataFormatJSDouble
:
209 case DataFormatDouble
: {
210 FPRReg oldFPR
= info
.fpr();
213 payloadGPR
= allocate();
214 boxDouble(oldFPR
, tagGPR
, payloadGPR
);
215 m_fprs
.unlock(oldFPR
);
216 m_fprs
.release(oldFPR
);
217 m_gprs
.retain(tagGPR
, virtualRegister
, SpillOrderJS
);
218 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderJS
);
219 info
.fillJSValue(*m_stream
, tagGPR
, payloadGPR
, DataFormatJS
);
224 case DataFormatJSInteger
:
225 case DataFormatJSCell
:
226 case DataFormatJSBoolean
: {
227 tagGPR
= info
.tagGPR();
228 payloadGPR
= info
.payloadGPR();
230 m_gprs
.lock(payloadGPR
);
234 case DataFormatStorage
:
235 // this type currently never occurs
236 RELEASE_ASSERT_NOT_REACHED();
239 RELEASE_ASSERT_NOT_REACHED();
244 void SpeculativeJIT::nonSpeculativeUInt32ToNumber(Node
* node
)
246 IntegerOperand
op1(this, node
->child1());
247 FPRTemporary
boxer(this);
248 GPRTemporary
resultTag(this, op1
);
249 GPRTemporary
resultPayload(this);
251 JITCompiler::Jump positive
= m_jit
.branch32(MacroAssembler::GreaterThanOrEqual
, op1
.gpr(), TrustedImm32(0));
253 m_jit
.convertInt32ToDouble(op1
.gpr(), boxer
.fpr());
254 m_jit
.move(JITCompiler::TrustedImmPtr(&AssemblyHelpers::twoToThe32
), resultPayload
.gpr()); // reuse resultPayload register here.
255 m_jit
.addDouble(JITCompiler::Address(resultPayload
.gpr(), 0), boxer
.fpr());
257 boxDouble(boxer
.fpr(), resultTag
.gpr(), resultPayload
.gpr());
259 JITCompiler::Jump done
= m_jit
.jump();
261 positive
.link(&m_jit
);
263 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), resultTag
.gpr());
264 m_jit
.move(op1
.gpr(), resultPayload
.gpr());
268 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
271 void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin
, GPRReg baseTagGPROrNone
, GPRReg basePayloadGPR
, GPRReg resultTagGPR
, GPRReg resultPayloadGPR
, unsigned identifierNumber
, JITCompiler::Jump slowPathTarget
, SpillRegistersMode spillMode
)
273 JITCompiler::DataLabelPtr structureToCompare
;
274 JITCompiler::PatchableJump structureCheck
= m_jit
.patchableBranchPtrWithPatch(JITCompiler::NotEqual
, JITCompiler::Address(basePayloadGPR
, JSCell::structureOffset()), structureToCompare
, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(unusedPointer
)));
276 JITCompiler::ConvertibleLoadLabel propertyStorageLoad
= m_jit
.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR
, JSObject::butterflyOffset()), resultPayloadGPR
);
277 JITCompiler::DataLabelCompact tagLoadWithPatch
= m_jit
.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)), resultTagGPR
);
278 JITCompiler::DataLabelCompact payloadLoadWithPatch
= m_jit
.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)), resultPayloadGPR
);
280 JITCompiler::Label doneLabel
= m_jit
.label();
282 OwnPtr
<SlowPathGenerator
> slowPath
;
283 if (baseTagGPROrNone
== InvalidGPRReg
) {
284 if (!slowPathTarget
.isSet()) {
285 slowPath
= slowPathCall(
286 structureCheck
.m_jump
, this, operationGetByIdOptimize
,
287 JSValueRegs(resultTagGPR
, resultPayloadGPR
),
288 static_cast<int32_t>(JSValue::CellTag
), basePayloadGPR
,
289 identifier(identifierNumber
));
291 JITCompiler::JumpList slowCases
;
292 slowCases
.append(structureCheck
.m_jump
);
293 slowCases
.append(slowPathTarget
);
294 slowPath
= slowPathCall(
295 slowCases
, this, operationGetByIdOptimize
,
296 JSValueRegs(resultTagGPR
, resultPayloadGPR
),
297 static_cast<int32_t>(JSValue::CellTag
), basePayloadGPR
,
298 identifier(identifierNumber
));
301 if (!slowPathTarget
.isSet()) {
302 slowPath
= slowPathCall(
303 structureCheck
.m_jump
, this, operationGetByIdOptimize
,
304 JSValueRegs(resultTagGPR
, resultPayloadGPR
), baseTagGPROrNone
, basePayloadGPR
,
305 identifier(identifierNumber
));
307 JITCompiler::JumpList slowCases
;
308 slowCases
.append(structureCheck
.m_jump
);
309 slowCases
.append(slowPathTarget
);
310 slowPath
= slowPathCall(
311 slowCases
, this, operationGetByIdOptimize
,
312 JSValueRegs(resultTagGPR
, resultPayloadGPR
), baseTagGPROrNone
, basePayloadGPR
,
313 identifier(identifierNumber
));
316 m_jit
.addPropertyAccess(
317 PropertyAccessRecord(
318 codeOrigin
, structureToCompare
, structureCheck
, propertyStorageLoad
,
319 tagLoadWithPatch
, payloadLoadWithPatch
, slowPath
.get(), doneLabel
,
320 safeCast
<int8_t>(basePayloadGPR
), safeCast
<int8_t>(resultTagGPR
),
321 safeCast
<int8_t>(resultPayloadGPR
), usedRegisters(),
322 spillMode
== NeedToSpill
? PropertyAccessRecord::RegistersInUse
: PropertyAccessRecord::RegistersFlushed
));
323 addSlowPathGenerator(slowPath
.release());
326 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin
, GPRReg basePayloadGPR
, GPRReg valueTagGPR
, GPRReg valuePayloadGPR
, Edge valueUse
, GPRReg scratchGPR
, unsigned identifierNumber
, PutKind putKind
, JITCompiler::Jump slowPathTarget
)
328 JITCompiler::DataLabelPtr structureToCompare
;
329 JITCompiler::PatchableJump structureCheck
= m_jit
.patchableBranchPtrWithPatch(JITCompiler::NotEqual
, JITCompiler::Address(basePayloadGPR
, JSCell::structureOffset()), structureToCompare
, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(unusedPointer
)));
331 writeBarrier(basePayloadGPR
, valueTagGPR
, valueUse
, WriteBarrierForPropertyAccess
, scratchGPR
);
333 JITCompiler::ConvertibleLoadLabel propertyStorageLoad
= m_jit
.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR
, JSObject::butterflyOffset()), scratchGPR
);
334 JITCompiler::DataLabel32 tagStoreWithPatch
= m_jit
.store32WithAddressOffsetPatch(valueTagGPR
, JITCompiler::Address(scratchGPR
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
335 JITCompiler::DataLabel32 payloadStoreWithPatch
= m_jit
.store32WithAddressOffsetPatch(valuePayloadGPR
, JITCompiler::Address(scratchGPR
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
337 JITCompiler::Label doneLabel
= m_jit
.label();
338 V_DFGOperation_EJCI optimizedCall
;
339 if (m_jit
.strictModeFor(m_currentNode
->codeOrigin
)) {
340 if (putKind
== Direct
)
341 optimizedCall
= operationPutByIdDirectStrictOptimize
;
343 optimizedCall
= operationPutByIdStrictOptimize
;
345 if (putKind
== Direct
)
346 optimizedCall
= operationPutByIdDirectNonStrictOptimize
;
348 optimizedCall
= operationPutByIdNonStrictOptimize
;
350 OwnPtr
<SlowPathGenerator
> slowPath
;
351 if (!slowPathTarget
.isSet()) {
352 slowPath
= slowPathCall(
353 structureCheck
.m_jump
, this, optimizedCall
, NoResult
, valueTagGPR
, valuePayloadGPR
,
354 basePayloadGPR
, identifier(identifierNumber
));
356 JITCompiler::JumpList slowCases
;
357 slowCases
.append(structureCheck
.m_jump
);
358 slowCases
.append(slowPathTarget
);
359 slowPath
= slowPathCall(
360 slowCases
, this, optimizedCall
, NoResult
, valueTagGPR
, valuePayloadGPR
,
361 basePayloadGPR
, identifier(identifierNumber
));
363 RegisterSet currentlyUsedRegisters
= usedRegisters();
364 currentlyUsedRegisters
.clear(scratchGPR
);
365 ASSERT(currentlyUsedRegisters
.get(basePayloadGPR
));
366 ASSERT(currentlyUsedRegisters
.get(valueTagGPR
));
367 ASSERT(currentlyUsedRegisters
.get(valuePayloadGPR
));
368 m_jit
.addPropertyAccess(
369 PropertyAccessRecord(
370 codeOrigin
, structureToCompare
, structureCheck
, propertyStorageLoad
,
371 JITCompiler::DataLabelCompact(tagStoreWithPatch
.label()),
372 JITCompiler::DataLabelCompact(payloadStoreWithPatch
.label()),
373 slowPath
.get(), doneLabel
, safeCast
<int8_t>(basePayloadGPR
),
374 safeCast
<int8_t>(valueTagGPR
), safeCast
<int8_t>(valuePayloadGPR
),
376 addSlowPathGenerator(slowPath
.release());
379 void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand
, bool invert
)
381 JSValueOperand
arg(this, operand
);
382 GPRReg argTagGPR
= arg
.tagGPR();
383 GPRReg argPayloadGPR
= arg
.payloadGPR();
385 GPRTemporary
resultPayload(this, arg
, false);
386 GPRReg resultPayloadGPR
= resultPayload
.gpr();
388 JITCompiler::Jump notCell
;
389 JITCompiler::Jump notMasqueradesAsUndefined
;
390 if (m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
391 if (!isKnownCell(operand
.node()))
392 notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, argTagGPR
, TrustedImm32(JSValue::CellTag
));
394 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
395 m_jit
.move(invert
? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR
);
396 notMasqueradesAsUndefined
= m_jit
.jump();
398 GPRTemporary
localGlobalObject(this);
399 GPRTemporary
remoteGlobalObject(this);
401 if (!isKnownCell(operand
.node()))
402 notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, argTagGPR
, TrustedImm32(JSValue::CellTag
));
404 m_jit
.loadPtr(JITCompiler::Address(argPayloadGPR
, JSCell::structureOffset()), resultPayloadGPR
);
405 JITCompiler::Jump isMasqueradesAsUndefined
= m_jit
.branchTest8(JITCompiler::NonZero
, JITCompiler::Address(resultPayloadGPR
, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined
));
407 m_jit
.move(invert
? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR
);
408 notMasqueradesAsUndefined
= m_jit
.jump();
410 isMasqueradesAsUndefined
.link(&m_jit
);
411 GPRReg localGlobalObjectGPR
= localGlobalObject
.gpr();
412 GPRReg remoteGlobalObjectGPR
= remoteGlobalObject
.gpr();
413 m_jit
.move(JITCompiler::TrustedImmPtr(m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)), localGlobalObjectGPR
);
414 m_jit
.loadPtr(JITCompiler::Address(resultPayloadGPR
, Structure::globalObjectOffset()), remoteGlobalObjectGPR
);
415 m_jit
.compare32(invert
? JITCompiler::NotEqual
: JITCompiler::Equal
, localGlobalObjectGPR
, remoteGlobalObjectGPR
, resultPayloadGPR
);
418 if (!isKnownCell(operand
.node())) {
419 JITCompiler::Jump done
= m_jit
.jump();
421 notCell
.link(&m_jit
);
422 // null or undefined?
423 COMPILE_ASSERT((JSValue::UndefinedTag
| 1) == JSValue::NullTag
, UndefinedTag_OR_1_EQUALS_NullTag
);
424 m_jit
.move(argTagGPR
, resultPayloadGPR
);
425 m_jit
.or32(TrustedImm32(1), resultPayloadGPR
);
426 m_jit
.compare32(invert
? JITCompiler::NotEqual
: JITCompiler::Equal
, resultPayloadGPR
, TrustedImm32(JSValue::NullTag
), resultPayloadGPR
);
431 notMasqueradesAsUndefined
.link(&m_jit
);
433 booleanResult(resultPayloadGPR
, m_currentNode
);
436 void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand
, Node
* branchNode
, bool invert
)
438 BlockIndex taken
= branchNode
->takenBlockIndex();
439 BlockIndex notTaken
= branchNode
->notTakenBlockIndex();
441 if (taken
== nextBlock()) {
443 BlockIndex tmp
= taken
;
448 JSValueOperand
arg(this, operand
);
449 GPRReg argTagGPR
= arg
.tagGPR();
450 GPRReg argPayloadGPR
= arg
.payloadGPR();
452 GPRTemporary
result(this, arg
);
453 GPRReg resultGPR
= result
.gpr();
455 JITCompiler::Jump notCell
;
457 if (m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
458 if (!isKnownCell(operand
.node()))
459 notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, argTagGPR
, TrustedImm32(JSValue::CellTag
));
461 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
462 jump(invert
? taken
: notTaken
, ForceJump
);
464 GPRTemporary
localGlobalObject(this);
465 GPRTemporary
remoteGlobalObject(this);
467 if (!isKnownCell(operand
.node()))
468 notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, argTagGPR
, TrustedImm32(JSValue::CellTag
));
470 m_jit
.loadPtr(JITCompiler::Address(argPayloadGPR
, JSCell::structureOffset()), resultGPR
);
471 branchTest8(JITCompiler::Zero
, JITCompiler::Address(resultGPR
, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined
), invert
? taken
: notTaken
);
473 GPRReg localGlobalObjectGPR
= localGlobalObject
.gpr();
474 GPRReg remoteGlobalObjectGPR
= remoteGlobalObject
.gpr();
475 m_jit
.move(TrustedImmPtr(m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)), localGlobalObjectGPR
);
476 m_jit
.loadPtr(JITCompiler::Address(resultGPR
, Structure::globalObjectOffset()), remoteGlobalObjectGPR
);
477 branchPtr(JITCompiler::Equal
, localGlobalObjectGPR
, remoteGlobalObjectGPR
, invert
? notTaken
: taken
);
480 if (!isKnownCell(operand
.node())) {
481 jump(notTaken
, ForceJump
);
483 notCell
.link(&m_jit
);
484 // null or undefined?
485 COMPILE_ASSERT((JSValue::UndefinedTag
| 1) == JSValue::NullTag
, UndefinedTag_OR_1_EQUALS_NullTag
);
486 m_jit
.move(argTagGPR
, resultGPR
);
487 m_jit
.or32(TrustedImm32(1), resultGPR
);
488 branch32(invert
? JITCompiler::NotEqual
: JITCompiler::Equal
, resultGPR
, JITCompiler::TrustedImm32(JSValue::NullTag
), taken
);
494 bool SpeculativeJIT::nonSpeculativeCompareNull(Node
* node
, Edge operand
, bool invert
)
496 unsigned branchIndexInBlock
= detectPeepHoleBranch();
497 if (branchIndexInBlock
!= UINT_MAX
) {
498 Node
* branchNode
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
500 ASSERT(node
->adjustedRefCount() == 1);
502 nonSpeculativePeepholeBranchNull(operand
, branchNode
, invert
);
506 m_indexInBlock
= branchIndexInBlock
;
507 m_currentNode
= branchNode
;
512 nonSpeculativeNonPeepholeCompareNull(operand
, invert
);
517 void SpeculativeJIT::nonSpeculativePeepholeBranch(Node
* node
, Node
* branchNode
, MacroAssembler::RelationalCondition cond
, S_DFGOperation_EJJ helperFunction
)
519 BlockIndex taken
= branchNode
->takenBlockIndex();
520 BlockIndex notTaken
= branchNode
->notTakenBlockIndex();
522 JITCompiler::ResultCondition callResultCondition
= JITCompiler::NonZero
;
524 // The branch instruction will branch to the taken block.
525 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
526 if (taken
== nextBlock()) {
527 cond
= JITCompiler::invert(cond
);
528 callResultCondition
= JITCompiler::Zero
;
529 BlockIndex tmp
= taken
;
534 JSValueOperand
arg1(this, node
->child1());
535 JSValueOperand
arg2(this, node
->child2());
536 GPRReg arg1TagGPR
= arg1
.tagGPR();
537 GPRReg arg1PayloadGPR
= arg1
.payloadGPR();
538 GPRReg arg2TagGPR
= arg2
.tagGPR();
539 GPRReg arg2PayloadGPR
= arg2
.payloadGPR();
541 JITCompiler::JumpList slowPath
;
543 if (isKnownNotInteger(node
->child1().node()) || isKnownNotInteger(node
->child2().node())) {
544 GPRResult
result(this);
545 GPRReg resultGPR
= result
.gpr();
551 callOperation(helperFunction
, resultGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
553 branchTest32(callResultCondition
, resultGPR
, taken
);
555 GPRTemporary
result(this);
556 GPRReg resultGPR
= result
.gpr();
561 if (!isKnownInteger(node
->child1().node()))
562 slowPath
.append(m_jit
.branch32(MacroAssembler::NotEqual
, arg1TagGPR
, JITCompiler::TrustedImm32(JSValue::Int32Tag
)));
563 if (!isKnownInteger(node
->child2().node()))
564 slowPath
.append(m_jit
.branch32(MacroAssembler::NotEqual
, arg2TagGPR
, JITCompiler::TrustedImm32(JSValue::Int32Tag
)));
566 branch32(cond
, arg1PayloadGPR
, arg2PayloadGPR
, taken
);
568 if (!isKnownInteger(node
->child1().node()) || !isKnownInteger(node
->child2().node())) {
569 jump(notTaken
, ForceJump
);
571 slowPath
.link(&m_jit
);
573 silentSpillAllRegisters(resultGPR
);
574 callOperation(helperFunction
, resultGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
575 silentFillAllRegisters(resultGPR
);
577 branchTest32(callResultCondition
, resultGPR
, taken
);
583 m_indexInBlock
= m_jit
.graph().m_blocks
[m_block
]->size() - 1;
584 m_currentNode
= branchNode
;
587 template<typename JumpType
>
588 class CompareAndBoxBooleanSlowPathGenerator
589 : public CallSlowPathGenerator
<JumpType
, S_DFGOperation_EJJ
, GPRReg
> {
591 CompareAndBoxBooleanSlowPathGenerator(
592 JumpType from
, SpeculativeJIT
* jit
,
593 S_DFGOperation_EJJ function
, GPRReg result
, GPRReg arg1Tag
, GPRReg arg1Payload
,
594 GPRReg arg2Tag
, GPRReg arg2Payload
)
595 : CallSlowPathGenerator
<JumpType
, S_DFGOperation_EJJ
, GPRReg
>(
596 from
, jit
, function
, NeedToSpill
, result
)
598 , m_arg1Payload(arg1Payload
)
600 , m_arg2Payload(arg2Payload
)
605 virtual void generateInternal(SpeculativeJIT
* jit
)
610 this->m_function
, this->m_result
, m_arg1Tag
, m_arg1Payload
, m_arg2Tag
,
612 jit
->m_jit
.and32(JITCompiler::TrustedImm32(1), this->m_result
);
618 GPRReg m_arg1Payload
;
620 GPRReg m_arg2Payload
;
623 void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node
* node
, MacroAssembler::RelationalCondition cond
, S_DFGOperation_EJJ helperFunction
)
625 JSValueOperand
arg1(this, node
->child1());
626 JSValueOperand
arg2(this, node
->child2());
627 GPRReg arg1TagGPR
= arg1
.tagGPR();
628 GPRReg arg1PayloadGPR
= arg1
.payloadGPR();
629 GPRReg arg2TagGPR
= arg2
.tagGPR();
630 GPRReg arg2PayloadGPR
= arg2
.payloadGPR();
632 JITCompiler::JumpList slowPath
;
634 if (isKnownNotInteger(node
->child1().node()) || isKnownNotInteger(node
->child2().node())) {
635 GPRResult
result(this);
636 GPRReg resultPayloadGPR
= result
.gpr();
642 callOperation(helperFunction
, resultPayloadGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
644 booleanResult(resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
646 GPRTemporary
resultPayload(this, arg1
, false);
647 GPRReg resultPayloadGPR
= resultPayload
.gpr();
652 if (!isKnownInteger(node
->child1().node()))
653 slowPath
.append(m_jit
.branch32(MacroAssembler::NotEqual
, arg1TagGPR
, JITCompiler::TrustedImm32(JSValue::Int32Tag
)));
654 if (!isKnownInteger(node
->child2().node()))
655 slowPath
.append(m_jit
.branch32(MacroAssembler::NotEqual
, arg2TagGPR
, JITCompiler::TrustedImm32(JSValue::Int32Tag
)));
657 m_jit
.compare32(cond
, arg1PayloadGPR
, arg2PayloadGPR
, resultPayloadGPR
);
659 if (!isKnownInteger(node
->child1().node()) || !isKnownInteger(node
->child2().node())) {
660 addSlowPathGenerator(adoptPtr(
661 new CompareAndBoxBooleanSlowPathGenerator
<JITCompiler::JumpList
>(
662 slowPath
, this, helperFunction
, resultPayloadGPR
, arg1TagGPR
,
663 arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
)));
666 booleanResult(resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
670 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node
* node
, Node
* branchNode
, bool invert
)
672 BlockIndex taken
= branchNode
->takenBlockIndex();
673 BlockIndex notTaken
= branchNode
->notTakenBlockIndex();
675 // The branch instruction will branch to the taken block.
676 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
677 if (taken
== nextBlock()) {
679 BlockIndex tmp
= taken
;
684 JSValueOperand
arg1(this, node
->child1());
685 JSValueOperand
arg2(this, node
->child2());
686 GPRReg arg1TagGPR
= arg1
.tagGPR();
687 GPRReg arg1PayloadGPR
= arg1
.payloadGPR();
688 GPRReg arg2TagGPR
= arg2
.tagGPR();
689 GPRReg arg2PayloadGPR
= arg2
.payloadGPR();
691 GPRTemporary
resultPayload(this, arg1
, false);
692 GPRReg resultPayloadGPR
= resultPayload
.gpr();
697 if (isKnownCell(node
->child1().node()) && isKnownCell(node
->child2().node())) {
698 // see if we get lucky: if the arguments are cells and they reference the same
699 // cell, then they must be strictly equal.
700 branchPtr(JITCompiler::Equal
, arg1PayloadGPR
, arg2PayloadGPR
, invert
? notTaken
: taken
);
702 silentSpillAllRegisters(resultPayloadGPR
);
703 callOperation(operationCompareStrictEqCell
, resultPayloadGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
704 silentFillAllRegisters(resultPayloadGPR
);
706 branchTest32(invert
? JITCompiler::Zero
: JITCompiler::NonZero
, resultPayloadGPR
, taken
);
708 // FIXME: Add fast paths for twoCells, number etc.
710 silentSpillAllRegisters(resultPayloadGPR
);
711 callOperation(operationCompareStrictEq
, resultPayloadGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
712 silentFillAllRegisters(resultPayloadGPR
);
714 branchTest32(invert
? JITCompiler::Zero
: JITCompiler::NonZero
, resultPayloadGPR
, taken
);
720 void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node
* node
, bool invert
)
722 JSValueOperand
arg1(this, node
->child1());
723 JSValueOperand
arg2(this, node
->child2());
724 GPRReg arg1TagGPR
= arg1
.tagGPR();
725 GPRReg arg1PayloadGPR
= arg1
.payloadGPR();
726 GPRReg arg2TagGPR
= arg2
.tagGPR();
727 GPRReg arg2PayloadGPR
= arg2
.payloadGPR();
729 GPRTemporary
resultPayload(this, arg1
, false);
730 GPRReg resultPayloadGPR
= resultPayload
.gpr();
735 if (isKnownCell(node
->child1().node()) && isKnownCell(node
->child2().node())) {
736 // see if we get lucky: if the arguments are cells and they reference the same
737 // cell, then they must be strictly equal.
738 // FIXME: this should flush registers instead of silent spill/fill.
739 JITCompiler::Jump notEqualCase
= m_jit
.branchPtr(JITCompiler::NotEqual
, arg1PayloadGPR
, arg2PayloadGPR
);
741 m_jit
.move(JITCompiler::TrustedImm32(!invert
), resultPayloadGPR
);
742 JITCompiler::Jump done
= m_jit
.jump();
744 notEqualCase
.link(&m_jit
);
746 silentSpillAllRegisters(resultPayloadGPR
);
747 callOperation(operationCompareStrictEqCell
, resultPayloadGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
748 silentFillAllRegisters(resultPayloadGPR
);
750 m_jit
.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR
);
754 // FIXME: Add fast paths.
756 silentSpillAllRegisters(resultPayloadGPR
);
757 callOperation(operationCompareStrictEq
, resultPayloadGPR
, arg1TagGPR
, arg1PayloadGPR
, arg2TagGPR
, arg2PayloadGPR
);
758 silentFillAllRegisters(resultPayloadGPR
);
760 m_jit
.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR
);
763 booleanResult(resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
766 void SpeculativeJIT::emitCall(Node
* node
)
768 if (node
->op() != Call
)
769 ASSERT(node
->op() == Construct
);
771 // For constructors, the this argument is not passed but we have to make space
773 int dummyThisArgument
= node
->op() == Call
? 0 : 1;
775 CallLinkInfo::CallType callType
= node
->op() == Call
? CallLinkInfo::Call
: CallLinkInfo::Construct
;
777 Edge calleeEdge
= m_jit
.graph().m_varArgChildren
[node
->firstChild()];
778 JSValueOperand
callee(this, calleeEdge
);
779 GPRReg calleeTagGPR
= callee
.tagGPR();
780 GPRReg calleePayloadGPR
= callee
.payloadGPR();
783 // The call instruction's first child is either the function (normal call) or the
784 // receiver (method call). subsequent children are the arguments.
785 int numPassedArgs
= node
->numChildren() - 1;
787 m_jit
.store32(MacroAssembler::TrustedImm32(numPassedArgs
+ dummyThisArgument
), callFramePayloadSlot(JSStack::ArgumentCount
));
788 m_jit
.storePtr(GPRInfo::callFrameRegister
, callFramePayloadSlot(JSStack::CallerFrame
));
789 m_jit
.store32(calleePayloadGPR
, callFramePayloadSlot(JSStack::Callee
));
790 m_jit
.store32(calleeTagGPR
, callFrameTagSlot(JSStack::Callee
));
792 for (int i
= 0; i
< numPassedArgs
; i
++) {
793 Edge argEdge
= m_jit
.graph().m_varArgChildren
[node
->firstChild() + 1 + i
];
794 JSValueOperand
arg(this, argEdge
);
795 GPRReg argTagGPR
= arg
.tagGPR();
796 GPRReg argPayloadGPR
= arg
.payloadGPR();
799 m_jit
.store32(argTagGPR
, argumentTagSlot(i
+ dummyThisArgument
));
800 m_jit
.store32(argPayloadGPR
, argumentPayloadSlot(i
+ dummyThisArgument
));
805 GPRResult
resultPayload(this);
806 GPRResult2
resultTag(this);
807 GPRReg resultPayloadGPR
= resultPayload
.gpr();
808 GPRReg resultTagGPR
= resultTag
.gpr();
810 JITCompiler::DataLabelPtr targetToCheck
;
811 JITCompiler::JumpList slowPath
;
813 CallBeginToken token
;
814 m_jit
.beginCall(node
->codeOrigin
, token
);
816 m_jit
.addPtr(TrustedImm32(m_jit
.codeBlock()->m_numCalleeRegisters
* sizeof(Register
)), GPRInfo::callFrameRegister
);
818 slowPath
.append(m_jit
.branch32(MacroAssembler::NotEqual
, calleeTagGPR
, TrustedImm32(JSValue::CellTag
)));
819 slowPath
.append(m_jit
.branchPtrWithPatch(MacroAssembler::NotEqual
, calleePayloadGPR
, targetToCheck
));
820 m_jit
.loadPtr(MacroAssembler::Address(calleePayloadGPR
, OBJECT_OFFSETOF(JSFunction
, m_scope
)), resultPayloadGPR
);
821 m_jit
.storePtr(resultPayloadGPR
, MacroAssembler::Address(GPRInfo::callFrameRegister
, static_cast<ptrdiff_t>(sizeof(Register
)) * JSStack::ScopeChain
+ OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
822 m_jit
.store32(MacroAssembler::TrustedImm32(JSValue::CellTag
), MacroAssembler::Address(GPRInfo::callFrameRegister
, static_cast<ptrdiff_t>(sizeof(Register
)) * JSStack::ScopeChain
+ OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
824 CodeOrigin codeOrigin
= node
->codeOrigin
;
825 JITCompiler::Call fastCall
= m_jit
.nearCall();
826 m_jit
.notifyCall(fastCall
, codeOrigin
, token
);
828 JITCompiler::Jump done
= m_jit
.jump();
830 slowPath
.link(&m_jit
);
832 if (calleeTagGPR
== GPRInfo::nonArgGPR0
) {
833 if (calleePayloadGPR
== GPRInfo::nonArgGPR1
)
834 m_jit
.swap(GPRInfo::nonArgGPR1
, GPRInfo::nonArgGPR0
);
836 m_jit
.move(calleeTagGPR
, GPRInfo::nonArgGPR1
);
837 m_jit
.move(calleePayloadGPR
, GPRInfo::nonArgGPR0
);
840 m_jit
.move(calleePayloadGPR
, GPRInfo::nonArgGPR0
);
841 m_jit
.move(calleeTagGPR
, GPRInfo::nonArgGPR1
);
843 m_jit
.prepareForExceptionCheck();
844 JITCompiler::Call slowCall
= m_jit
.nearCall();
845 m_jit
.notifyCall(slowCall
, codeOrigin
, token
);
849 m_jit
.setupResults(resultPayloadGPR
, resultTagGPR
);
851 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, DataFormatJS
, UseChildrenCalledExplicitly
);
853 m_jit
.addJSCall(fastCall
, slowCall
, targetToCheck
, callType
, calleePayloadGPR
, node
->codeOrigin
);
856 template<bool strict
>
857 GPRReg
SpeculativeJIT::fillSpeculateIntInternal(Edge edge
, DataFormat
& returnFormat
)
859 #if DFG_ENABLE(DEBUG_VERBOSE)
860 dataLogF("SpecInt@%d ", edge
->index());
862 AbstractValue
& value
= m_state
.forNode(edge
);
863 SpeculatedType type
= value
.m_type
;
864 ASSERT(edge
.useKind() != KnownInt32Use
|| !(value
.m_type
& ~SpecInt32
));
865 value
.filter(SpecInt32
);
866 VirtualRegister virtualRegister
= edge
->virtualRegister();
867 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
869 switch (info
.registerFormat()) {
870 case DataFormatNone
: {
871 if ((edge
->hasConstant() && !isInt32Constant(edge
.node())) || info
.spillFormat() == DataFormatDouble
) {
872 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
873 returnFormat
= DataFormatInteger
;
877 if (edge
->hasConstant()) {
878 ASSERT(isInt32Constant(edge
.node()));
879 GPRReg gpr
= allocate();
880 m_jit
.move(MacroAssembler::Imm32(valueOfInt32Constant(edge
.node())), gpr
);
881 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
882 info
.fillInteger(*m_stream
, gpr
);
883 returnFormat
= DataFormatInteger
;
887 DataFormat spillFormat
= info
.spillFormat();
888 ASSERT_UNUSED(spillFormat
, (spillFormat
& DataFormatJS
) || spillFormat
== DataFormatInteger
);
890 // If we know this was spilled as an integer we can fill without checking.
891 if (type
& ~SpecInt32
)
892 speculationCheck(BadType
, JSValueSource(JITCompiler::addressFor(virtualRegister
)), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::Int32Tag
)));
894 GPRReg gpr
= allocate();
895 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), gpr
);
896 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
897 info
.fillInteger(*m_stream
, gpr
);
898 returnFormat
= DataFormatInteger
;
902 case DataFormatJSInteger
:
904 // Check the value is an integer.
905 GPRReg tagGPR
= info
.tagGPR();
906 GPRReg payloadGPR
= info
.payloadGPR();
908 m_gprs
.lock(payloadGPR
);
909 if (type
& ~SpecInt32
)
910 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, tagGPR
, TrustedImm32(JSValue::Int32Tag
)));
911 m_gprs
.unlock(tagGPR
);
912 m_gprs
.release(tagGPR
);
913 m_gprs
.release(payloadGPR
);
914 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderInteger
);
915 info
.fillInteger(*m_stream
, payloadGPR
);
916 // If !strict we're done, return.
917 returnFormat
= DataFormatInteger
;
921 case DataFormatInteger
: {
922 GPRReg gpr
= info
.gpr();
924 returnFormat
= DataFormatInteger
;
928 case DataFormatDouble
:
930 case DataFormatBoolean
:
931 case DataFormatJSDouble
:
932 case DataFormatJSCell
:
933 case DataFormatJSBoolean
:
934 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
935 returnFormat
= DataFormatInteger
;
938 case DataFormatStorage
:
940 RELEASE_ASSERT_NOT_REACHED();
941 return InvalidGPRReg
;
945 GPRReg
SpeculativeJIT::fillSpeculateInt(Edge edge
, DataFormat
& returnFormat
)
947 return fillSpeculateIntInternal
<false>(edge
, returnFormat
);
950 GPRReg
SpeculativeJIT::fillSpeculateIntStrict(Edge edge
)
952 DataFormat mustBeDataFormatInteger
;
953 GPRReg result
= fillSpeculateIntInternal
<true>(edge
, mustBeDataFormatInteger
);
954 ASSERT(mustBeDataFormatInteger
== DataFormatInteger
);
958 FPRReg
SpeculativeJIT::fillSpeculateDouble(Edge edge
)
960 #if DFG_ENABLE(DEBUG_VERBOSE)
961 dataLogF("SpecDouble@%d ", edge
->index());
963 AbstractValue
& value
= m_state
.forNode(edge
);
964 SpeculatedType type
= value
.m_type
;
965 ASSERT(edge
.useKind() != KnownNumberUse
|| !(value
.m_type
& ~SpecNumber
));
966 value
.filter(SpecNumber
);
967 VirtualRegister virtualRegister
= edge
->virtualRegister();
968 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
970 if (info
.registerFormat() == DataFormatNone
) {
972 if (edge
->hasConstant()) {
973 if (isInt32Constant(edge
.node())) {
974 GPRReg gpr
= allocate();
975 m_jit
.move(MacroAssembler::Imm32(valueOfInt32Constant(edge
.node())), gpr
);
976 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
977 info
.fillInteger(*m_stream
, gpr
);
979 } else if (isNumberConstant(edge
.node())) {
980 FPRReg fpr
= fprAllocate();
981 m_jit
.loadDouble(addressOfDoubleConstant(edge
.node()), fpr
);
982 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderConstant
);
983 info
.fillDouble(*m_stream
, fpr
);
986 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
987 return fprAllocate();
990 DataFormat spillFormat
= info
.spillFormat();
991 ASSERT((spillFormat
& DataFormatJS
) || spillFormat
== DataFormatInteger
);
992 if (spillFormat
== DataFormatJSDouble
|| spillFormat
== DataFormatDouble
) {
993 FPRReg fpr
= fprAllocate();
994 m_jit
.loadDouble(JITCompiler::addressFor(virtualRegister
), fpr
);
995 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderSpilled
);
996 info
.fillDouble(*m_stream
, fpr
);
1000 FPRReg fpr
= fprAllocate();
1001 JITCompiler::Jump hasUnboxedDouble
;
1003 if (spillFormat
!= DataFormatJSInteger
&& spillFormat
!= DataFormatInteger
) {
1004 JITCompiler::Jump isInteger
= m_jit
.branch32(MacroAssembler::Equal
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::Int32Tag
));
1005 if (type
& ~SpecNumber
)
1006 speculationCheck(BadType
, JSValueSource(JITCompiler::addressFor(virtualRegister
)), edge
, m_jit
.branch32(MacroAssembler::AboveOrEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::LowestTag
)));
1007 m_jit
.loadDouble(JITCompiler::addressFor(virtualRegister
), fpr
);
1008 hasUnboxedDouble
= m_jit
.jump();
1010 isInteger
.link(&m_jit
);
1013 m_jit
.convertInt32ToDouble(JITCompiler::payloadFor(virtualRegister
), fpr
);
1015 if (hasUnboxedDouble
.isSet())
1016 hasUnboxedDouble
.link(&m_jit
);
1018 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderSpilled
);
1019 info
.fillDouble(*m_stream
, fpr
);
1025 switch (info
.registerFormat()) {
1027 case DataFormatJSInteger
: {
1028 GPRReg tagGPR
= info
.tagGPR();
1029 GPRReg payloadGPR
= info
.payloadGPR();
1030 FPRReg fpr
= fprAllocate();
1032 m_gprs
.lock(tagGPR
);
1033 m_gprs
.lock(payloadGPR
);
1035 JITCompiler::Jump hasUnboxedDouble
;
1037 if (info
.registerFormat() != DataFormatJSInteger
) {
1038 FPRTemporary
scratch(this);
1039 JITCompiler::Jump isInteger
= m_jit
.branch32(MacroAssembler::Equal
, tagGPR
, TrustedImm32(JSValue::Int32Tag
));
1040 if (type
& ~SpecNumber
)
1041 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), edge
, m_jit
.branch32(MacroAssembler::AboveOrEqual
, tagGPR
, TrustedImm32(JSValue::LowestTag
)));
1042 unboxDouble(tagGPR
, payloadGPR
, fpr
, scratch
.fpr());
1043 hasUnboxedDouble
= m_jit
.jump();
1044 isInteger
.link(&m_jit
);
1047 m_jit
.convertInt32ToDouble(payloadGPR
, fpr
);
1049 if (hasUnboxedDouble
.isSet())
1050 hasUnboxedDouble
.link(&m_jit
);
1052 m_gprs
.release(tagGPR
);
1053 m_gprs
.release(payloadGPR
);
1054 m_gprs
.unlock(tagGPR
);
1055 m_gprs
.unlock(payloadGPR
);
1056 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderDouble
);
1057 info
.fillDouble(*m_stream
, fpr
);
1062 case DataFormatInteger
: {
1063 FPRReg fpr
= fprAllocate();
1064 GPRReg gpr
= info
.gpr();
1066 m_jit
.convertInt32ToDouble(gpr
, fpr
);
1071 case DataFormatJSDouble
:
1072 case DataFormatDouble
: {
1073 FPRReg fpr
= info
.fpr();
1078 case DataFormatNone
:
1079 case DataFormatStorage
:
1080 RELEASE_ASSERT_NOT_REACHED();
1082 case DataFormatCell
:
1083 case DataFormatJSCell
:
1084 case DataFormatBoolean
:
1085 case DataFormatJSBoolean
:
1086 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1087 return fprAllocate();
1090 RELEASE_ASSERT_NOT_REACHED();
1091 return InvalidFPRReg
;
1095 GPRReg
SpeculativeJIT::fillSpeculateCell(Edge edge
)
1097 #if DFG_ENABLE(DEBUG_VERBOSE)
1098 dataLogF("SpecCell@%d ", edge
->index());
1100 AbstractValue
& value
= m_state
.forNode(edge
);
1101 SpeculatedType type
= value
.m_type
;
1102 ASSERT((edge
.useKind() != KnownCellUse
&& edge
.useKind() != KnownStringUse
) || !(value
.m_type
& ~SpecCell
));
1103 value
.filter(SpecCell
);
1104 VirtualRegister virtualRegister
= edge
->virtualRegister();
1105 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
1107 switch (info
.registerFormat()) {
1108 case DataFormatNone
: {
1110 if (edge
->hasConstant()) {
1111 JSValue jsValue
= valueOfJSConstant(edge
.node());
1112 GPRReg gpr
= allocate();
1113 if (jsValue
.isCell()) {
1114 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
1115 m_jit
.move(MacroAssembler::TrustedImmPtr(jsValue
.asCell()), gpr
);
1116 info
.fillCell(*m_stream
, gpr
);
1119 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1123 ASSERT((info
.spillFormat() & DataFormatJS
) || info
.spillFormat() == DataFormatCell
);
1124 if (type
& ~SpecCell
)
1125 speculationCheck(BadType
, JSValueSource(JITCompiler::addressFor(virtualRegister
)), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::CellTag
)));
1126 GPRReg gpr
= allocate();
1127 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), gpr
);
1128 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
1129 info
.fillCell(*m_stream
, gpr
);
1133 case DataFormatCell
: {
1134 GPRReg gpr
= info
.gpr();
1139 case DataFormatJSCell
:
1140 case DataFormatJS
: {
1141 GPRReg tagGPR
= info
.tagGPR();
1142 GPRReg payloadGPR
= info
.payloadGPR();
1143 m_gprs
.lock(tagGPR
);
1144 m_gprs
.lock(payloadGPR
);
1145 if (type
& ~SpecCell
)
1146 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, tagGPR
, TrustedImm32(JSValue::CellTag
)));
1147 m_gprs
.unlock(tagGPR
);
1148 m_gprs
.release(tagGPR
);
1149 m_gprs
.release(payloadGPR
);
1150 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderCell
);
1151 info
.fillCell(*m_stream
, payloadGPR
);
1155 case DataFormatJSInteger
:
1156 case DataFormatInteger
:
1157 case DataFormatJSDouble
:
1158 case DataFormatDouble
:
1159 case DataFormatJSBoolean
:
1160 case DataFormatBoolean
:
1161 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1164 case DataFormatStorage
:
1165 RELEASE_ASSERT_NOT_REACHED();
1168 RELEASE_ASSERT_NOT_REACHED();
1169 return InvalidGPRReg
;
1173 GPRReg
SpeculativeJIT::fillSpeculateBoolean(Edge edge
)
1175 #if DFG_ENABLE(DEBUG_VERBOSE)
1176 dataLogF("SpecBool@%d ", edge
.node()->index());
1178 AbstractValue
& value
= m_state
.forNode(edge
);
1179 SpeculatedType type
= value
.m_type
;
1180 value
.filter(SpecBoolean
);
1181 VirtualRegister virtualRegister
= edge
->virtualRegister();
1182 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
1184 switch (info
.registerFormat()) {
1185 case DataFormatNone
: {
1186 if (info
.spillFormat() == DataFormatInteger
|| info
.spillFormat() == DataFormatDouble
) {
1187 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1191 if (edge
->hasConstant()) {
1192 JSValue jsValue
= valueOfJSConstant(edge
.node());
1193 GPRReg gpr
= allocate();
1194 if (jsValue
.isBoolean()) {
1195 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
1196 m_jit
.move(MacroAssembler::TrustedImm32(jsValue
.asBoolean()), gpr
);
1197 info
.fillBoolean(*m_stream
, gpr
);
1200 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1204 ASSERT((info
.spillFormat() & DataFormatJS
) || info
.spillFormat() == DataFormatBoolean
);
1206 if (type
& ~SpecBoolean
)
1207 speculationCheck(BadType
, JSValueSource(JITCompiler::addressFor(virtualRegister
)), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::BooleanTag
)));
1209 GPRReg gpr
= allocate();
1210 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), gpr
);
1211 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
1212 info
.fillBoolean(*m_stream
, gpr
);
1216 case DataFormatBoolean
: {
1217 GPRReg gpr
= info
.gpr();
1222 case DataFormatJSBoolean
:
1223 case DataFormatJS
: {
1224 GPRReg tagGPR
= info
.tagGPR();
1225 GPRReg payloadGPR
= info
.payloadGPR();
1226 m_gprs
.lock(tagGPR
);
1227 m_gprs
.lock(payloadGPR
);
1228 if (type
& ~SpecBoolean
)
1229 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), edge
, m_jit
.branch32(MacroAssembler::NotEqual
, tagGPR
, TrustedImm32(JSValue::BooleanTag
)));
1231 m_gprs
.unlock(tagGPR
);
1232 m_gprs
.release(tagGPR
);
1233 m_gprs
.release(payloadGPR
);
1234 m_gprs
.retain(payloadGPR
, virtualRegister
, SpillOrderBoolean
);
1235 info
.fillBoolean(*m_stream
, payloadGPR
);
1239 case DataFormatJSInteger
:
1240 case DataFormatInteger
:
1241 case DataFormatJSDouble
:
1242 case DataFormatDouble
:
1243 case DataFormatJSCell
:
1244 case DataFormatCell
:
1245 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
1248 case DataFormatStorage
:
1249 RELEASE_ASSERT_NOT_REACHED();
1252 RELEASE_ASSERT_NOT_REACHED();
1253 return InvalidGPRReg
;
1257 JITCompiler::Jump
SpeculativeJIT::convertToDouble(JSValueOperand
& op
, FPRReg result
)
1259 FPRTemporary
scratch(this);
1261 GPRReg opPayloadGPR
= op
.payloadGPR();
1262 GPRReg opTagGPR
= op
.tagGPR();
1263 FPRReg scratchFPR
= scratch
.fpr();
1265 JITCompiler::Jump isInteger
= m_jit
.branch32(MacroAssembler::Equal
, opTagGPR
, TrustedImm32(JSValue::Int32Tag
));
1266 JITCompiler::Jump notNumber
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, opPayloadGPR
, TrustedImm32(JSValue::LowestTag
));
1268 unboxDouble(opTagGPR
, opPayloadGPR
, result
, scratchFPR
);
1269 JITCompiler::Jump done
= m_jit
.jump();
1271 isInteger
.link(&m_jit
);
1272 m_jit
.convertInt32ToDouble(opPayloadGPR
, result
);
1279 void SpeculativeJIT::compileObjectEquality(Node
* node
)
1281 SpeculateCellOperand
op1(this, node
->child1());
1282 SpeculateCellOperand
op2(this, node
->child2());
1283 GPRReg op1GPR
= op1
.gpr();
1284 GPRReg op2GPR
= op2
.gpr();
1286 if (m_jit
.graph().globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
1287 m_jit
.graph().globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1289 JSValueSource::unboxedCell(op1GPR
), node
->child1(), SpecObject
, m_jit
.branchPtr(
1290 MacroAssembler::Equal
,
1291 MacroAssembler::Address(op1GPR
, JSCell::structureOffset()),
1292 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1294 JSValueSource::unboxedCell(op2GPR
), node
->child2(), SpecObject
, m_jit
.branchPtr(
1295 MacroAssembler::Equal
,
1296 MacroAssembler::Address(op2GPR
, JSCell::structureOffset()),
1297 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1299 GPRTemporary
structure(this);
1300 GPRReg structureGPR
= structure
.gpr();
1302 m_jit
.loadPtr(MacroAssembler::Address(op1GPR
, JSCell::structureOffset()), structureGPR
);
1304 JSValueSource::unboxedCell(op1GPR
), node
->child1(), SpecObject
, m_jit
.branchPtr(
1305 MacroAssembler::Equal
,
1307 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1308 speculationCheck(BadType
, JSValueSource::unboxedCell(op1GPR
), node
->child1(),
1310 MacroAssembler::NonZero
,
1311 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1312 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1314 m_jit
.loadPtr(MacroAssembler::Address(op2GPR
, JSCell::structureOffset()), structureGPR
);
1316 JSValueSource::unboxedCell(op2GPR
), node
->child2(), SpecObject
, m_jit
.branchPtr(
1317 MacroAssembler::Equal
,
1319 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1320 speculationCheck(BadType
, JSValueSource::unboxedCell(op2GPR
), node
->child2(),
1322 MacroAssembler::NonZero
,
1323 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1324 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1327 GPRTemporary
resultPayload(this, op2
);
1328 GPRReg resultPayloadGPR
= resultPayload
.gpr();
1330 MacroAssembler::Jump falseCase
= m_jit
.branchPtr(MacroAssembler::NotEqual
, op1GPR
, op2GPR
);
1331 m_jit
.move(TrustedImm32(1), resultPayloadGPR
);
1332 MacroAssembler::Jump done
= m_jit
.jump();
1333 falseCase
.link(&m_jit
);
1334 m_jit
.move(TrustedImm32(0), resultPayloadGPR
);
1337 booleanResult(resultPayloadGPR
, node
);
1340 void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild
, Edge rightChild
)
1342 SpeculateCellOperand
op1(this, leftChild
);
1343 JSValueOperand
op2(this, rightChild
, ManualOperandSpeculation
);
1344 GPRTemporary
result(this);
1346 GPRReg op1GPR
= op1
.gpr();
1347 GPRReg op2TagGPR
= op2
.tagGPR();
1348 GPRReg op2PayloadGPR
= op2
.payloadGPR();
1349 GPRReg resultGPR
= result
.gpr();
1350 GPRTemporary structure
;
1351 GPRReg structureGPR
= InvalidGPRReg
;
1353 bool masqueradesAsUndefinedWatchpointValid
= m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid();
1355 if (!masqueradesAsUndefinedWatchpointValid
) {
1356 // The masquerades as undefined case will use the structure register, so allocate it here.
1357 // Do this at the top of the function to avoid branching around a register allocation.
1358 GPRTemporary
realStructure(this);
1359 structure
.adopt(realStructure
);
1360 structureGPR
= structure
.gpr();
1363 if (masqueradesAsUndefinedWatchpointValid
) {
1364 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1366 JSValueSource::unboxedCell(op1GPR
), leftChild
, SpecObject
, m_jit
.branchPtr(
1367 MacroAssembler::Equal
,
1368 MacroAssembler::Address(op1GPR
, JSCell::structureOffset()),
1369 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1371 m_jit
.loadPtr(MacroAssembler::Address(op1GPR
, JSCell::structureOffset()), structureGPR
);
1373 JSValueSource::unboxedCell(op1GPR
), leftChild
, SpecObject
, m_jit
.branchPtr(
1374 MacroAssembler::Equal
,
1376 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1377 speculationCheck(BadType
, JSValueSource::unboxedCell(op1GPR
), leftChild
,
1379 MacroAssembler::NonZero
,
1380 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1381 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1385 // It seems that most of the time when programs do a == b where b may be either null/undefined
1386 // or an object, b is usually an object. Balance the branches to make that case fast.
1387 MacroAssembler::Jump rightNotCell
=
1388 m_jit
.branch32(MacroAssembler::NotEqual
, op2TagGPR
, TrustedImm32(JSValue::CellTag
));
1390 // We know that within this branch, rightChild must be a cell.
1391 if (masqueradesAsUndefinedWatchpointValid
) {
1392 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1394 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, (~SpecCell
) | SpecObject
,
1396 MacroAssembler::Equal
,
1397 MacroAssembler::Address(op2PayloadGPR
, JSCell::structureOffset()),
1398 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1400 m_jit
.loadPtr(MacroAssembler::Address(op2PayloadGPR
, JSCell::structureOffset()), structureGPR
);
1402 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, (~SpecCell
) | SpecObject
,
1404 MacroAssembler::Equal
,
1406 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1407 speculationCheck(BadType
, JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
,
1409 MacroAssembler::NonZero
,
1410 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1411 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1414 // At this point we know that we can perform a straight-forward equality comparison on pointer
1415 // values because both left and right are pointers to objects that have no special equality
1417 MacroAssembler::Jump falseCase
= m_jit
.branchPtr(MacroAssembler::NotEqual
, op1GPR
, op2PayloadGPR
);
1418 MacroAssembler::Jump trueCase
= m_jit
.jump();
1420 rightNotCell
.link(&m_jit
);
1422 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1423 // prove that it is either null or undefined.
1424 if (needsTypeCheck(rightChild
, SpecCell
| SpecOther
)) {
1425 m_jit
.move(op2TagGPR
, resultGPR
);
1426 m_jit
.or32(TrustedImm32(1), resultGPR
);
1429 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, SpecCell
| SpecOther
,
1431 MacroAssembler::NotEqual
, resultGPR
,
1432 MacroAssembler::TrustedImm32(JSValue::NullTag
)));
1435 falseCase
.link(&m_jit
);
1436 m_jit
.move(TrustedImm32(0), resultGPR
);
1437 MacroAssembler::Jump done
= m_jit
.jump();
1438 trueCase
.link(&m_jit
);
1439 m_jit
.move(TrustedImm32(1), resultGPR
);
1442 booleanResult(resultGPR
, m_currentNode
);
1445 void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
, Edge rightChild
, Node
* branchNode
)
1447 BlockIndex taken
= branchNode
->takenBlockIndex();
1448 BlockIndex notTaken
= branchNode
->notTakenBlockIndex();
1450 SpeculateCellOperand
op1(this, leftChild
);
1451 JSValueOperand
op2(this, rightChild
, ManualOperandSpeculation
);
1452 GPRTemporary
result(this);
1454 GPRReg op1GPR
= op1
.gpr();
1455 GPRReg op2TagGPR
= op2
.tagGPR();
1456 GPRReg op2PayloadGPR
= op2
.payloadGPR();
1457 GPRReg resultGPR
= result
.gpr();
1458 GPRTemporary structure
;
1459 GPRReg structureGPR
= InvalidGPRReg
;
1461 bool masqueradesAsUndefinedWatchpointValid
= m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid();
1463 if (!masqueradesAsUndefinedWatchpointValid
) {
1464 // The masquerades as undefined case will use the structure register, so allocate it here.
1465 // Do this at the top of the function to avoid branching around a register allocation.
1466 GPRTemporary
realStructure(this);
1467 structure
.adopt(realStructure
);
1468 structureGPR
= structure
.gpr();
1471 if (masqueradesAsUndefinedWatchpointValid
) {
1472 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1474 JSValueSource::unboxedCell(op1GPR
), leftChild
, SpecObject
, m_jit
.branchPtr(
1475 MacroAssembler::Equal
,
1476 MacroAssembler::Address(op1GPR
, JSCell::structureOffset()),
1477 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1479 m_jit
.loadPtr(MacroAssembler::Address(op1GPR
, JSCell::structureOffset()), structureGPR
);
1481 JSValueSource::unboxedCell(op1GPR
), leftChild
, SpecObject
, m_jit
.branchPtr(
1482 MacroAssembler::Equal
,
1484 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1485 speculationCheck(BadType
, JSValueSource::unboxedCell(op1GPR
), leftChild
,
1487 MacroAssembler::NonZero
,
1488 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1489 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1492 // It seems that most of the time when programs do a == b where b may be either null/undefined
1493 // or an object, b is usually an object. Balance the branches to make that case fast.
1494 MacroAssembler::Jump rightNotCell
=
1495 m_jit
.branch32(MacroAssembler::NotEqual
, op2TagGPR
, TrustedImm32(JSValue::CellTag
));
1497 // We know that within this branch, rightChild must be a cell.
1498 if (masqueradesAsUndefinedWatchpointValid
) {
1499 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1501 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, (~SpecCell
) | SpecObject
,
1503 MacroAssembler::Equal
,
1504 MacroAssembler::Address(op2PayloadGPR
, JSCell::structureOffset()),
1505 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1507 m_jit
.loadPtr(MacroAssembler::Address(op2PayloadGPR
, JSCell::structureOffset()), structureGPR
);
1509 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, (~SpecCell
) | SpecObject
,
1511 MacroAssembler::Equal
,
1513 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1514 speculationCheck(BadType
, JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
,
1516 MacroAssembler::NonZero
,
1517 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1518 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
)));
1521 // At this point we know that we can perform a straight-forward equality comparison on pointer
1522 // values because both left and right are pointers to objects that have no special equality
1524 branch32(MacroAssembler::Equal
, op1GPR
, op2PayloadGPR
, taken
);
1526 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1527 // prove that it is either null or undefined.
1528 if (!needsTypeCheck(rightChild
, SpecCell
| SpecOther
))
1529 rightNotCell
.link(&m_jit
);
1531 jump(notTaken
, ForceJump
);
1533 rightNotCell
.link(&m_jit
);
1534 m_jit
.move(op2TagGPR
, resultGPR
);
1535 m_jit
.or32(TrustedImm32(1), resultGPR
);
1538 JSValueRegs(op2TagGPR
, op2PayloadGPR
), rightChild
, SpecCell
| SpecOther
,
1540 MacroAssembler::NotEqual
, resultGPR
,
1541 MacroAssembler::TrustedImm32(JSValue::NullTag
)));
1547 void SpeculativeJIT::compileIntegerCompare(Node
* node
, MacroAssembler::RelationalCondition condition
)
1549 SpeculateIntegerOperand
op1(this, node
->child1());
1550 SpeculateIntegerOperand
op2(this, node
->child2());
1551 GPRTemporary
resultPayload(this);
1553 m_jit
.compare32(condition
, op1
.gpr(), op2
.gpr(), resultPayload
.gpr());
1555 // If we add a DataFormatBool, we should use it here.
1556 booleanResult(resultPayload
.gpr(), node
);
1559 void SpeculativeJIT::compileDoubleCompare(Node
* node
, MacroAssembler::DoubleCondition condition
)
1561 SpeculateDoubleOperand
op1(this, node
->child1());
1562 SpeculateDoubleOperand
op2(this, node
->child2());
1563 GPRTemporary
resultPayload(this);
1565 m_jit
.move(TrustedImm32(1), resultPayload
.gpr());
1566 MacroAssembler::Jump trueCase
= m_jit
.branchDouble(condition
, op1
.fpr(), op2
.fpr());
1567 m_jit
.move(TrustedImm32(0), resultPayload
.gpr());
1568 trueCase
.link(&m_jit
);
1570 booleanResult(resultPayload
.gpr(), node
);
1573 void SpeculativeJIT::compileValueAdd(Node
* node
)
1575 JSValueOperand
op1(this, node
->child1());
1576 JSValueOperand
op2(this, node
->child2());
1578 GPRReg op1TagGPR
= op1
.tagGPR();
1579 GPRReg op1PayloadGPR
= op1
.payloadGPR();
1580 GPRReg op2TagGPR
= op2
.tagGPR();
1581 GPRReg op2PayloadGPR
= op2
.payloadGPR();
1585 GPRResult2
resultTag(this);
1586 GPRResult
resultPayload(this);
1587 if (isKnownNotNumber(node
->child1().node()) || isKnownNotNumber(node
->child2().node()))
1588 callOperation(operationValueAddNotNumber
, resultTag
.gpr(), resultPayload
.gpr(), op1TagGPR
, op1PayloadGPR
, op2TagGPR
, op2PayloadGPR
);
1590 callOperation(operationValueAdd
, resultTag
.gpr(), resultPayload
.gpr(), op1TagGPR
, op1PayloadGPR
, op2TagGPR
, op2PayloadGPR
);
1592 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
1595 void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse
)
1597 JSValueOperand
value(this, nodeUse
, ManualOperandSpeculation
);
1598 GPRTemporary
resultPayload(this);
1599 GPRReg valueTagGPR
= value
.tagGPR();
1600 GPRReg valuePayloadGPR
= value
.payloadGPR();
1601 GPRReg resultPayloadGPR
= resultPayload
.gpr();
1602 GPRTemporary structure
;
1603 GPRReg structureGPR
= InvalidGPRReg
;
1605 bool masqueradesAsUndefinedWatchpointValid
= m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid();
1607 if (!masqueradesAsUndefinedWatchpointValid
) {
1608 // The masquerades as undefined case will use the structure register, so allocate it here.
1609 // Do this at the top of the function to avoid branching around a register allocation.
1610 GPRTemporary
realStructure(this);
1611 structure
.adopt(realStructure
);
1612 structureGPR
= structure
.gpr();
1615 MacroAssembler::Jump notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, valueTagGPR
, TrustedImm32(JSValue::CellTag
));
1616 if (masqueradesAsUndefinedWatchpointValid
) {
1617 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1620 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, (~SpecCell
) | SpecObject
,
1622 MacroAssembler::Equal
,
1623 MacroAssembler::Address(valuePayloadGPR
, JSCell::structureOffset()),
1624 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1626 m_jit
.loadPtr(MacroAssembler::Address(valuePayloadGPR
, JSCell::structureOffset()), structureGPR
);
1629 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, (~SpecCell
) | SpecObject
,
1631 MacroAssembler::Equal
,
1633 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1635 MacroAssembler::Jump isNotMasqueradesAsUndefined
=
1637 MacroAssembler::Zero
,
1638 MacroAssembler::Address(structureGPR
, Structure::typeInfoFlagsOffset()),
1639 MacroAssembler::TrustedImm32(MasqueradesAsUndefined
));
1641 speculationCheck(BadType
, JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
,
1643 MacroAssembler::Equal
,
1644 MacroAssembler::Address(structureGPR
, Structure::globalObjectOffset()),
1645 MacroAssembler::TrustedImmPtr(m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
))));
1647 isNotMasqueradesAsUndefined
.link(&m_jit
);
1649 m_jit
.move(TrustedImm32(0), resultPayloadGPR
);
1650 MacroAssembler::Jump done
= m_jit
.jump();
1652 notCell
.link(&m_jit
);
1654 COMPILE_ASSERT((JSValue::UndefinedTag
| 1) == JSValue::NullTag
, UndefinedTag_OR_1_EQUALS_NullTag
);
1655 if (needsTypeCheck(nodeUse
, SpecCell
| SpecOther
)) {
1656 m_jit
.move(valueTagGPR
, resultPayloadGPR
);
1657 m_jit
.or32(TrustedImm32(1), resultPayloadGPR
);
1659 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, SpecCell
| SpecOther
,
1661 MacroAssembler::NotEqual
,
1663 TrustedImm32(JSValue::NullTag
)));
1665 m_jit
.move(TrustedImm32(1), resultPayloadGPR
);
1669 booleanResult(resultPayloadGPR
, m_currentNode
);
1672 void SpeculativeJIT::compileLogicalNot(Node
* node
)
1674 switch (node
->child1().useKind()) {
1676 SpeculateBooleanOperand
value(this, node
->child1());
1677 GPRTemporary
result(this, value
);
1678 m_jit
.xor32(TrustedImm32(1), value
.gpr(), result
.gpr());
1679 booleanResult(result
.gpr(), node
);
1683 case ObjectOrOtherUse
: {
1684 compileObjectOrOtherLogicalNot(node
->child1());
1689 SpeculateIntegerOperand
value(this, node
->child1());
1690 GPRTemporary
resultPayload(this, value
);
1691 m_jit
.compare32(MacroAssembler::Equal
, value
.gpr(), MacroAssembler::TrustedImm32(0), resultPayload
.gpr());
1692 booleanResult(resultPayload
.gpr(), node
);
1697 SpeculateDoubleOperand
value(this, node
->child1());
1698 FPRTemporary
scratch(this);
1699 GPRTemporary
resultPayload(this);
1700 m_jit
.move(TrustedImm32(0), resultPayload
.gpr());
1701 MacroAssembler::Jump nonZero
= m_jit
.branchDoubleNonZero(value
.fpr(), scratch
.fpr());
1702 m_jit
.move(TrustedImm32(1), resultPayload
.gpr());
1703 nonZero
.link(&m_jit
);
1704 booleanResult(resultPayload
.gpr(), node
);
1709 JSValueOperand
arg1(this, node
->child1());
1710 GPRTemporary
resultPayload(this, arg1
, false);
1711 GPRReg arg1TagGPR
= arg1
.tagGPR();
1712 GPRReg arg1PayloadGPR
= arg1
.payloadGPR();
1713 GPRReg resultPayloadGPR
= resultPayload
.gpr();
1717 JITCompiler::Jump slowCase
= m_jit
.branch32(JITCompiler::NotEqual
, arg1TagGPR
, TrustedImm32(JSValue::BooleanTag
));
1719 m_jit
.move(arg1PayloadGPR
, resultPayloadGPR
);
1721 addSlowPathGenerator(
1723 slowCase
, this, dfgConvertJSValueToBoolean
, resultPayloadGPR
, arg1TagGPR
,
1726 m_jit
.xor32(TrustedImm32(1), resultPayloadGPR
);
1727 booleanResult(resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
1732 RELEASE_ASSERT_NOT_REACHED();
1737 void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse
, BlockIndex taken
, BlockIndex notTaken
)
1739 JSValueOperand
value(this, nodeUse
, ManualOperandSpeculation
);
1740 GPRTemporary
scratch(this);
1741 GPRReg valueTagGPR
= value
.tagGPR();
1742 GPRReg valuePayloadGPR
= value
.payloadGPR();
1743 GPRReg scratchGPR
= scratch
.gpr();
1745 MacroAssembler::Jump notCell
= m_jit
.branch32(MacroAssembler::NotEqual
, valueTagGPR
, TrustedImm32(JSValue::CellTag
));
1746 if (m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
1747 m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
1750 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, (~SpecCell
) | SpecObject
,
1752 MacroAssembler::Equal
,
1753 MacroAssembler::Address(valuePayloadGPR
, JSCell::structureOffset()),
1754 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1756 m_jit
.loadPtr(MacroAssembler::Address(valuePayloadGPR
, JSCell::structureOffset()), scratchGPR
);
1759 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, (~SpecCell
) | SpecObject
,
1761 MacroAssembler::Equal
,
1763 MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get())));
1765 JITCompiler::Jump isNotMasqueradesAsUndefined
= m_jit
.branchTest8(JITCompiler::Zero
, MacroAssembler::Address(scratchGPR
, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined
));
1767 speculationCheck(BadType
, JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
,
1769 MacroAssembler::Equal
,
1770 MacroAssembler::Address(scratchGPR
, Structure::globalObjectOffset()),
1771 MacroAssembler::TrustedImmPtr(m_jit
.graph().globalObjectFor(m_currentNode
->codeOrigin
))));
1773 isNotMasqueradesAsUndefined
.link(&m_jit
);
1775 jump(taken
, ForceJump
);
1777 notCell
.link(&m_jit
);
1779 COMPILE_ASSERT((JSValue::UndefinedTag
| 1) == JSValue::NullTag
, UndefinedTag_OR_1_EQUALS_NullTag
);
1780 if (needsTypeCheck(nodeUse
, SpecCell
| SpecOther
)) {
1781 m_jit
.move(valueTagGPR
, scratchGPR
);
1782 m_jit
.or32(TrustedImm32(1), scratchGPR
);
1784 JSValueRegs(valueTagGPR
, valuePayloadGPR
), nodeUse
, SpecCell
| SpecOther
,
1785 m_jit
.branch32(MacroAssembler::NotEqual
, scratchGPR
, TrustedImm32(JSValue::NullTag
)));
1790 noResult(m_currentNode
);
1793 void SpeculativeJIT::emitBranch(Node
* node
)
1795 BlockIndex taken
= node
->takenBlockIndex();
1796 BlockIndex notTaken
= node
->notTakenBlockIndex();
1798 switch (node
->child1().useKind()) {
1800 SpeculateBooleanOperand
value(this, node
->child1());
1801 MacroAssembler::ResultCondition condition
= MacroAssembler::NonZero
;
1803 if (taken
== nextBlock()) {
1804 condition
= MacroAssembler::Zero
;
1805 BlockIndex tmp
= taken
;
1810 branchTest32(condition
, value
.gpr(), TrustedImm32(1), taken
);
1817 case ObjectOrOtherUse
: {
1818 emitObjectOrOtherBranch(node
->child1(), taken
, notTaken
);
1824 if (node
->child1().useKind() == Int32Use
) {
1825 bool invert
= false;
1827 if (taken
== nextBlock()) {
1829 BlockIndex tmp
= taken
;
1834 SpeculateIntegerOperand
value(this, node
->child1());
1835 branchTest32(invert
? MacroAssembler::Zero
: MacroAssembler::NonZero
, value
.gpr(), taken
);
1837 SpeculateDoubleOperand
value(this, node
->child1());
1838 FPRTemporary
scratch(this);
1839 branchDoubleNonZero(value
.fpr(), scratch
.fpr(), taken
);
1849 JSValueOperand
value(this, node
->child1());
1851 GPRReg valueTagGPR
= value
.tagGPR();
1852 GPRReg valuePayloadGPR
= value
.payloadGPR();
1854 GPRTemporary
result(this);
1855 GPRReg resultGPR
= result
.gpr();
1857 use(node
->child1());
1859 JITCompiler::Jump fastPath
= m_jit
.branch32(JITCompiler::Equal
, valueTagGPR
, JITCompiler::TrustedImm32(JSValue::Int32Tag
));
1860 JITCompiler::Jump slowPath
= m_jit
.branch32(JITCompiler::NotEqual
, valueTagGPR
, JITCompiler::TrustedImm32(JSValue::BooleanTag
));
1862 fastPath
.link(&m_jit
);
1863 branchTest32(JITCompiler::Zero
, valuePayloadGPR
, notTaken
);
1864 jump(taken
, ForceJump
);
1866 slowPath
.link(&m_jit
);
1867 silentSpillAllRegisters(resultGPR
);
1868 callOperation(dfgConvertJSValueToBoolean
, resultGPR
, valueTagGPR
, valuePayloadGPR
);
1869 silentFillAllRegisters(resultGPR
);
1871 branchTest32(JITCompiler::NonZero
, resultGPR
, taken
);
1874 noResult(node
, UseChildrenCalledExplicitly
);
1879 RELEASE_ASSERT_NOT_REACHED();
1884 template<typename BaseOperandType
, typename PropertyOperandType
, typename ValueOperandType
, typename TagType
>
1885 void SpeculativeJIT::compileContiguousPutByVal(Node
* node
, BaseOperandType
& base
, PropertyOperandType
& property
, ValueOperandType
& value
, GPRReg valuePayloadReg
, TagType valueTag
)
1887 Edge child4
= m_jit
.graph().varArgChild(node
, 3);
1889 ArrayMode arrayMode
= node
->arrayMode();
1891 GPRReg baseReg
= base
.gpr();
1892 GPRReg propertyReg
= property
.gpr();
1894 StorageOperand
storage(this, child4
);
1895 GPRReg storageReg
= storage
.gpr();
1897 if (node
->op() == PutByValAlias
) {
1898 // Store the value to the array.
1899 GPRReg propertyReg
= property
.gpr();
1900 m_jit
.store32(valueTag
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
1901 m_jit
.store32(valuePayloadReg
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
1907 MacroAssembler::Jump slowCase
;
1909 if (arrayMode
.isInBounds()) {
1911 StoreToHoleOrOutOfBounds
, JSValueRegs(), 0,
1912 m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength())));
1914 MacroAssembler::Jump inBounds
= m_jit
.branch32(MacroAssembler::Below
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength()));
1916 slowCase
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfVectorLength()));
1918 if (!arrayMode
.isOutOfBounds())
1919 speculationCheck(OutOfBounds
, JSValueRegs(), 0, slowCase
);
1921 m_jit
.add32(TrustedImm32(1), propertyReg
);
1922 m_jit
.store32(propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength()));
1923 m_jit
.sub32(TrustedImm32(1), propertyReg
);
1925 inBounds
.link(&m_jit
);
1928 m_jit
.store32(valueTag
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
1929 m_jit
.store32(valuePayloadReg
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
1936 if (arrayMode
.isOutOfBounds()) {
1937 addSlowPathGenerator(
1940 m_jit
.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict
: operationPutByValBeyondArrayBoundsNonStrict
,
1941 NoResult
, baseReg
, propertyReg
, valueTag
, valuePayloadReg
));
1944 noResult(node
, UseChildrenCalledExplicitly
);
1947 void SpeculativeJIT::compile(Node
* node
)
1949 NodeType op
= node
->op();
1951 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1952 m_jit
.clearRegisterAllocationOffsets();
1957 initConstantInfo(node
);
1960 case PhantomArguments
:
1961 initConstantInfo(node
);
1964 case WeakJSConstant
:
1965 m_jit
.addWeakReference(node
->weakConstant());
1966 initConstantInfo(node
);
1970 RELEASE_ASSERT_NOT_REACHED();
1975 SpeculatedType prediction
= node
->variableAccessData()->prediction();
1976 AbstractValue
& value
= m_state
.variables().operand(node
->local());
1978 // If we have no prediction for this local, then don't attempt to compile.
1979 if (prediction
== SpecNone
) {
1980 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
1984 // If the CFA is tracking this variable and it found that the variable
1985 // cannot have been assigned, then don't attempt to proceed.
1986 if (value
.isClear()) {
1987 // FIXME: We should trap instead.
1988 // https://bugs.webkit.org/show_bug.cgi?id=110383
1989 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
1993 if (node
->variableAccessData()->shouldUseDoubleFormat()) {
1994 FPRTemporary
result(this);
1995 m_jit
.loadDouble(JITCompiler::addressFor(node
->local()), result
.fpr());
1996 VirtualRegister virtualRegister
= node
->virtualRegister();
1997 m_fprs
.retain(result
.fpr(), virtualRegister
, SpillOrderDouble
);
1998 m_generationInfo
[virtualRegister
].initDouble(node
, node
->refCount(), result
.fpr());
2002 if (isInt32Speculation(value
.m_type
)) {
2003 GPRTemporary
result(this);
2004 m_jit
.load32(JITCompiler::payloadFor(node
->local()), result
.gpr());
2006 // Like integerResult, but don't useChildren - our children are phi nodes,
2007 // and don't represent values within this dataflow with virtual registers.
2008 VirtualRegister virtualRegister
= node
->virtualRegister();
2009 m_gprs
.retain(result
.gpr(), virtualRegister
, SpillOrderInteger
);
2010 m_generationInfo
[virtualRegister
].initInteger(node
, node
->refCount(), result
.gpr());
2014 if (isCellSpeculation(value
.m_type
)) {
2015 GPRTemporary
result(this);
2016 m_jit
.load32(JITCompiler::payloadFor(node
->local()), result
.gpr());
2018 // Like cellResult, but don't useChildren - our children are phi nodes,
2019 // and don't represent values within this dataflow with virtual registers.
2020 VirtualRegister virtualRegister
= node
->virtualRegister();
2021 m_gprs
.retain(result
.gpr(), virtualRegister
, SpillOrderCell
);
2022 m_generationInfo
[virtualRegister
].initCell(node
, node
->refCount(), result
.gpr());
2026 if (isBooleanSpeculation(value
.m_type
)) {
2027 GPRTemporary
result(this);
2028 m_jit
.load32(JITCompiler::payloadFor(node
->local()), result
.gpr());
2030 // Like booleanResult, but don't useChildren - our children are phi nodes,
2031 // and don't represent values within this dataflow with virtual registers.
2032 VirtualRegister virtualRegister
= node
->virtualRegister();
2033 m_gprs
.retain(result
.gpr(), virtualRegister
, SpillOrderBoolean
);
2034 m_generationInfo
[virtualRegister
].initBoolean(node
, node
->refCount(), result
.gpr());
2038 GPRTemporary
result(this);
2039 GPRTemporary
tag(this);
2040 m_jit
.load32(JITCompiler::payloadFor(node
->local()), result
.gpr());
2041 m_jit
.load32(JITCompiler::tagFor(node
->local()), tag
.gpr());
2043 // Like jsValueResult, but don't useChildren - our children are phi nodes,
2044 // and don't represent values within this dataflow with virtual registers.
2045 VirtualRegister virtualRegister
= node
->virtualRegister();
2046 m_gprs
.retain(result
.gpr(), virtualRegister
, SpillOrderJS
);
2047 m_gprs
.retain(tag
.gpr(), virtualRegister
, SpillOrderJS
);
2049 m_generationInfo
[virtualRegister
].initJSValue(node
, node
->refCount(), tag
.gpr(), result
.gpr(), DataFormatJS
);
2053 case GetLocalUnlinked
: {
2054 GPRTemporary
payload(this);
2055 GPRTemporary
tag(this);
2056 m_jit
.load32(JITCompiler::payloadFor(node
->unlinkedLocal()), payload
.gpr());
2057 m_jit
.load32(JITCompiler::tagFor(node
->unlinkedLocal()), tag
.gpr());
2058 jsValueResult(tag
.gpr(), payload
.gpr(), node
);
2062 case MovHintAndCheck
: {
2063 compileMovHintAndCheck(node
);
2068 compileInlineStart(node
);
2074 RELEASE_ASSERT_NOT_REACHED();
2079 // SetLocal doubles as a hint as to where a node will be stored and
2080 // as a speculation point. So before we speculate make sure that we
2081 // know where the child of this node needs to go in the virtual
2083 compileMovHint(node
);
2085 if (node
->variableAccessData()->shouldUnboxIfPossible()) {
2086 if (node
->variableAccessData()->shouldUseDoubleFormat()) {
2087 SpeculateDoubleOperand
value(this, node
->child1());
2088 m_jit
.storeDouble(value
.fpr(), JITCompiler::addressFor(node
->local()));
2090 // Indicate that it's no longer necessary to retrieve the value of
2091 // this bytecode variable from registers or other locations in the stack,
2092 // but that it is stored as a double.
2093 recordSetLocal(node
->local(), ValueSource(DoubleInJSStack
));
2096 SpeculatedType predictedType
= node
->variableAccessData()->argumentAwarePrediction();
2097 if (m_generationInfo
[node
->child1()->virtualRegister()].registerFormat() == DataFormatDouble
) {
2098 SpeculateDoubleOperand
value(this, node
->child1(), ManualOperandSpeculation
);
2099 m_jit
.storeDouble(value
.fpr(), JITCompiler::addressFor(node
->local()));
2101 recordSetLocal(node
->local(), ValueSource(DoubleInJSStack
));
2104 if (isInt32Speculation(predictedType
)) {
2105 SpeculateIntegerOperand
value(this, node
->child1());
2106 m_jit
.store32(value
.gpr(), JITCompiler::payloadFor(node
->local()));
2108 recordSetLocal(node
->local(), ValueSource(Int32InJSStack
));
2111 if (isCellSpeculation(predictedType
)) {
2112 SpeculateCellOperand
cell(this, node
->child1());
2113 GPRReg cellGPR
= cell
.gpr();
2114 m_jit
.storePtr(cellGPR
, JITCompiler::payloadFor(node
->local()));
2116 recordSetLocal(node
->local(), ValueSource(CellInJSStack
));
2119 if (isBooleanSpeculation(predictedType
)) {
2120 SpeculateBooleanOperand
value(this, node
->child1());
2121 m_jit
.store32(value
.gpr(), JITCompiler::payloadFor(node
->local()));
2123 recordSetLocal(node
->local(), ValueSource(BooleanInJSStack
));
2127 JSValueOperand
value(this, node
->child1());
2128 m_jit
.store32(value
.payloadGPR(), JITCompiler::payloadFor(node
->local()));
2129 m_jit
.store32(value
.tagGPR(), JITCompiler::tagFor(node
->local()));
2131 recordSetLocal(node
->local(), ValueSource(ValueInJSStack
));
2133 // If we're storing an arguments object that has been optimized away,
2134 // our variable event stream for OSR exit now reflects the optimized
2135 // value (JSValue()). On the slow path, we want an arguments object
2136 // instead. We add an additional move hint to show OSR exit that it
2137 // needs to reconstruct the arguments object.
2138 if (node
->child1()->op() == PhantomArguments
)
2139 compileMovHint(node
);
2145 // This is a no-op; it just marks the fact that the argument is being used.
2146 // But it may be profitable to use this as a hook to run speculation checks
2147 // on arguments, thereby allowing us to trivially eliminate such checks if
2148 // the argument is not used.
2154 if (isInt32Constant(node
->child1().node())) {
2155 SpeculateIntegerOperand
op2(this, node
->child2());
2156 GPRTemporary
result(this, op2
);
2158 bitOp(op
, valueOfInt32Constant(node
->child1().node()), op2
.gpr(), result
.gpr());
2160 integerResult(result
.gpr(), node
);
2161 } else if (isInt32Constant(node
->child2().node())) {
2162 SpeculateIntegerOperand
op1(this, node
->child1());
2163 GPRTemporary
result(this, op1
);
2165 bitOp(op
, valueOfInt32Constant(node
->child2().node()), op1
.gpr(), result
.gpr());
2167 integerResult(result
.gpr(), node
);
2169 SpeculateIntegerOperand
op1(this, node
->child1());
2170 SpeculateIntegerOperand
op2(this, node
->child2());
2171 GPRTemporary
result(this, op1
, op2
);
2173 GPRReg reg1
= op1
.gpr();
2174 GPRReg reg2
= op2
.gpr();
2175 bitOp(op
, reg1
, reg2
, result
.gpr());
2177 integerResult(result
.gpr(), node
);
2184 if (isInt32Constant(node
->child2().node())) {
2185 SpeculateIntegerOperand
op1(this, node
->child1());
2186 GPRTemporary
result(this, op1
);
2188 shiftOp(op
, op1
.gpr(), valueOfInt32Constant(node
->child2().node()) & 0x1f, result
.gpr());
2190 integerResult(result
.gpr(), node
);
2192 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
2193 SpeculateIntegerOperand
op1(this, node
->child1());
2194 SpeculateIntegerOperand
op2(this, node
->child2());
2195 GPRTemporary
result(this, op1
);
2197 GPRReg reg1
= op1
.gpr();
2198 GPRReg reg2
= op2
.gpr();
2199 shiftOp(op
, reg1
, reg2
, result
.gpr());
2201 integerResult(result
.gpr(), node
);
2205 case UInt32ToNumber
: {
2206 compileUInt32ToNumber(node
);
2210 case DoubleAsInt32
: {
2211 compileDoubleAsInt32(node
);
2215 case ValueToInt32
: {
2216 compileValueToInt32(node
);
2221 case ForwardInt32ToDouble
: {
2222 compileInt32ToDouble(node
);
2232 compileMakeRope(node
);
2236 compileArithSub(node
);
2240 compileArithNegate(node
);
2244 compileArithMul(node
);
2248 compileArithIMul(node
);
2252 switch (node
->binaryUseKind()) {
2255 compileIntegerArithDivForX86(node
);
2257 compileIntegerArithDivForARM64(node
);
2258 #elif CPU(APPLE_ARMV7S)
2259 compileIntegerArithDivForARMv7s(node
);
2260 #else // CPU type without integer divide
2261 RELEASE_ASSERT_NOT_REACHED(); // should have been coverted into a double divide.
2267 SpeculateDoubleOperand
op1(this, node
->child1());
2268 SpeculateDoubleOperand
op2(this, node
->child2());
2269 FPRTemporary
result(this, op1
);
2271 FPRReg reg1
= op1
.fpr();
2272 FPRReg reg2
= op2
.fpr();
2273 m_jit
.divDouble(reg1
, reg2
, result
.fpr());
2275 doubleResult(result
.fpr(), node
);
2280 RELEASE_ASSERT_NOT_REACHED();
2287 compileArithMod(node
);
2292 switch (node
->child1().useKind()) {
2294 SpeculateIntegerOperand
op1(this, node
->child1());
2295 GPRTemporary
result(this, op1
);
2296 GPRTemporary
scratch(this);
2298 m_jit
.zeroExtend32ToPtr(op1
.gpr(), result
.gpr());
2299 m_jit
.rshift32(result
.gpr(), MacroAssembler::TrustedImm32(31), scratch
.gpr());
2300 m_jit
.add32(scratch
.gpr(), result
.gpr());
2301 m_jit
.xor32(scratch
.gpr(), result
.gpr());
2302 speculationCheck(Overflow
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::Equal
, result
.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
2303 integerResult(result
.gpr(), node
);
2309 SpeculateDoubleOperand
op1(this, node
->child1());
2310 FPRTemporary
result(this);
2312 m_jit
.absDouble(op1
.fpr(), result
.fpr());
2313 doubleResult(result
.fpr(), node
);
2318 RELEASE_ASSERT_NOT_REACHED();
2326 switch (node
->binaryUseKind()) {
2328 SpeculateStrictInt32Operand
op1(this, node
->child1());
2329 SpeculateStrictInt32Operand
op2(this, node
->child2());
2330 GPRTemporary
result(this, op1
);
2332 GPRReg op1GPR
= op1
.gpr();
2333 GPRReg op2GPR
= op2
.gpr();
2334 GPRReg resultGPR
= result
.gpr();
2336 MacroAssembler::Jump op1Less
= m_jit
.branch32(op
== ArithMin
? MacroAssembler::LessThan
: MacroAssembler::GreaterThan
, op1GPR
, op2GPR
);
2337 m_jit
.move(op2GPR
, resultGPR
);
2338 if (op1GPR
!= resultGPR
) {
2339 MacroAssembler::Jump done
= m_jit
.jump();
2340 op1Less
.link(&m_jit
);
2341 m_jit
.move(op1GPR
, resultGPR
);
2344 op1Less
.link(&m_jit
);
2346 integerResult(resultGPR
, node
);
2351 SpeculateDoubleOperand
op1(this, node
->child1());
2352 SpeculateDoubleOperand
op2(this, node
->child2());
2353 FPRTemporary
result(this, op1
);
2355 FPRReg op1FPR
= op1
.fpr();
2356 FPRReg op2FPR
= op2
.fpr();
2357 FPRReg resultFPR
= result
.fpr();
2359 MacroAssembler::JumpList done
;
2361 MacroAssembler::Jump op1Less
= m_jit
.branchDouble(op
== ArithMin
? MacroAssembler::DoubleLessThan
: MacroAssembler::DoubleGreaterThan
, op1FPR
, op2FPR
);
2363 // op2 is eather the lesser one or one of then is NaN
2364 MacroAssembler::Jump op2Less
= m_jit
.branchDouble(op
== ArithMin
? MacroAssembler::DoubleGreaterThanOrEqual
: MacroAssembler::DoubleLessThanOrEqual
, op1FPR
, op2FPR
);
2366 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2367 // op1 + op2 and putting it into result.
2368 m_jit
.addDouble(op1FPR
, op2FPR
, resultFPR
);
2369 done
.append(m_jit
.jump());
2371 op2Less
.link(&m_jit
);
2372 m_jit
.moveDouble(op2FPR
, resultFPR
);
2374 if (op1FPR
!= resultFPR
) {
2375 done
.append(m_jit
.jump());
2377 op1Less
.link(&m_jit
);
2378 m_jit
.moveDouble(op1FPR
, resultFPR
);
2380 op1Less
.link(&m_jit
);
2384 doubleResult(resultFPR
, node
);
2389 RELEASE_ASSERT_NOT_REACHED();
2396 SpeculateDoubleOperand
op1(this, node
->child1());
2397 FPRTemporary
result(this, op1
);
2399 m_jit
.sqrtDouble(op1
.fpr(), result
.fpr());
2401 doubleResult(result
.fpr(), node
);
2406 compileLogicalNot(node
);
2410 if (compare(node
, JITCompiler::LessThan
, JITCompiler::DoubleLessThan
, operationCompareLess
))
2415 if (compare(node
, JITCompiler::LessThanOrEqual
, JITCompiler::DoubleLessThanOrEqual
, operationCompareLessEq
))
2419 case CompareGreater
:
2420 if (compare(node
, JITCompiler::GreaterThan
, JITCompiler::DoubleGreaterThan
, operationCompareGreater
))
2424 case CompareGreaterEq
:
2425 if (compare(node
, JITCompiler::GreaterThanOrEqual
, JITCompiler::DoubleGreaterThanOrEqual
, operationCompareGreaterEq
))
2429 case CompareEqConstant
:
2430 ASSERT(isNullConstant(node
->child2().node()));
2431 if (nonSpeculativeCompareNull(node
, node
->child1()))
2436 if (compare(node
, JITCompiler::Equal
, JITCompiler::DoubleEqual
, operationCompareEq
))
2440 case CompareStrictEqConstant
:
2441 if (compileStrictEqForConstant(node
, node
->child1(), valueOfJSConstant(node
->child2().node())))
2445 case CompareStrictEq
:
2446 if (compileStrictEq(node
))
2450 case StringCharCodeAt
: {
2451 compileGetCharCodeAt(node
);
2455 case StringCharAt
: {
2456 // Relies on StringCharAt node having same basic layout as GetByVal
2457 compileGetByValOnString(node
);
2461 case StringFromCharCode
: {
2462 compileFromCharCode(node
);
2472 case ArrayifyToStructure
: {
2478 switch (node
->arrayMode().type()) {
2479 case Array::SelectUsingPredictions
:
2480 case Array::ForceExit
:
2481 RELEASE_ASSERT_NOT_REACHED();
2482 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
2484 case Array::Generic
: {
2485 SpeculateCellOperand
base(this, node
->child1()); // Save a register, speculate cell. We'll probably be right.
2486 JSValueOperand
property(this, node
->child2());
2487 GPRReg baseGPR
= base
.gpr();
2488 GPRReg propertyTagGPR
= property
.tagGPR();
2489 GPRReg propertyPayloadGPR
= property
.payloadGPR();
2492 GPRResult2
resultTag(this);
2493 GPRResult
resultPayload(this);
2494 callOperation(operationGetByValCell
, resultTag
.gpr(), resultPayload
.gpr(), baseGPR
, propertyTagGPR
, propertyPayloadGPR
);
2496 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
2500 case Array::Contiguous
: {
2501 if (node
->arrayMode().isInBounds()) {
2502 SpeculateStrictInt32Operand
property(this, node
->child2());
2503 StorageOperand
storage(this, node
->child3());
2505 GPRReg propertyReg
= property
.gpr();
2506 GPRReg storageReg
= storage
.gpr();
2511 speculationCheck(OutOfBounds
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength())));
2513 GPRTemporary
resultPayload(this);
2514 if (node
->arrayMode().type() == Array::Int32
) {
2516 OutOfBounds
, JSValueRegs(), 0,
2518 MacroAssembler::Equal
,
2519 MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)),
2520 TrustedImm32(JSValue::EmptyValueTag
)));
2521 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), resultPayload
.gpr());
2522 integerResult(resultPayload
.gpr(), node
);
2526 GPRTemporary
resultTag(this);
2527 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), resultTag
.gpr());
2528 speculationCheck(LoadFromHole
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::Equal
, resultTag
.gpr(), TrustedImm32(JSValue::EmptyValueTag
)));
2529 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), resultPayload
.gpr());
2530 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
2534 SpeculateCellOperand
base(this, node
->child1());
2535 SpeculateStrictInt32Operand
property(this, node
->child2());
2536 StorageOperand
storage(this, node
->child3());
2538 GPRReg baseReg
= base
.gpr();
2539 GPRReg propertyReg
= property
.gpr();
2540 GPRReg storageReg
= storage
.gpr();
2545 GPRTemporary
resultTag(this);
2546 GPRTemporary
resultPayload(this);
2547 GPRReg resultTagReg
= resultTag
.gpr();
2548 GPRReg resultPayloadReg
= resultPayload
.gpr();
2550 MacroAssembler::JumpList slowCases
;
2552 slowCases
.append(m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength())));
2554 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), resultTagReg
);
2555 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), resultPayloadReg
);
2556 slowCases
.append(m_jit
.branch32(MacroAssembler::Equal
, resultTagReg
, TrustedImm32(JSValue::EmptyValueTag
)));
2558 addSlowPathGenerator(
2560 slowCases
, this, operationGetByValArrayInt
,
2561 JSValueRegs(resultTagReg
, resultPayloadReg
), baseReg
, propertyReg
));
2563 jsValueResult(resultTagReg
, resultPayloadReg
, node
);
2566 case Array::Double
: {
2567 if (node
->arrayMode().isInBounds()) {
2568 if (node
->arrayMode().isSaneChain()) {
2569 JSGlobalObject
* globalObject
= m_jit
.globalObjectFor(node
->codeOrigin
);
2570 ASSERT(globalObject
->arrayPrototypeChainIsSane());
2571 globalObject
->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
2572 globalObject
->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
2575 SpeculateStrictInt32Operand
property(this, node
->child2());
2576 StorageOperand
storage(this, node
->child3());
2578 GPRReg propertyReg
= property
.gpr();
2579 GPRReg storageReg
= storage
.gpr();
2584 speculationCheck(OutOfBounds
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength())));
2586 FPRTemporary
result(this);
2587 m_jit
.loadDouble(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
), result
.fpr());
2588 if (!node
->arrayMode().isSaneChain())
2589 speculationCheck(LoadFromHole
, JSValueRegs(), 0, m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, result
.fpr(), result
.fpr()));
2590 doubleResult(result
.fpr(), node
);
2594 SpeculateCellOperand
base(this, node
->child1());
2595 SpeculateStrictInt32Operand
property(this, node
->child2());
2596 StorageOperand
storage(this, node
->child3());
2598 GPRReg baseReg
= base
.gpr();
2599 GPRReg propertyReg
= property
.gpr();
2600 GPRReg storageReg
= storage
.gpr();
2605 GPRTemporary
resultTag(this);
2606 GPRTemporary
resultPayload(this);
2607 FPRTemporary
temp(this);
2608 GPRReg resultTagReg
= resultTag
.gpr();
2609 GPRReg resultPayloadReg
= resultPayload
.gpr();
2610 FPRReg tempReg
= temp
.fpr();
2612 MacroAssembler::JumpList slowCases
;
2614 slowCases
.append(m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, Butterfly::offsetOfPublicLength())));
2616 m_jit
.loadDouble(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
), tempReg
);
2617 slowCases
.append(m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, tempReg
, tempReg
));
2618 boxDouble(tempReg
, resultTagReg
, resultPayloadReg
);
2620 addSlowPathGenerator(
2622 slowCases
, this, operationGetByValArrayInt
,
2623 JSValueRegs(resultTagReg
, resultPayloadReg
), baseReg
, propertyReg
));
2625 jsValueResult(resultTagReg
, resultPayloadReg
, node
);
2628 case Array::ArrayStorage
:
2629 case Array::SlowPutArrayStorage
: {
2630 if (node
->arrayMode().isInBounds()) {
2631 SpeculateStrictInt32Operand
property(this, node
->child2());
2632 StorageOperand
storage(this, node
->child3());
2633 GPRReg propertyReg
= property
.gpr();
2634 GPRReg storageReg
= storage
.gpr();
2639 speculationCheck(OutOfBounds
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, ArrayStorage::vectorLengthOffset())));
2641 GPRTemporary
resultTag(this);
2642 GPRTemporary
resultPayload(this);
2644 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), resultTag
.gpr());
2645 speculationCheck(LoadFromHole
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::Equal
, resultTag
.gpr(), TrustedImm32(JSValue::EmptyValueTag
)));
2646 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), resultPayload
.gpr());
2648 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
2652 SpeculateCellOperand
base(this, node
->child1());
2653 SpeculateStrictInt32Operand
property(this, node
->child2());
2654 StorageOperand
storage(this, node
->child3());
2655 GPRReg propertyReg
= property
.gpr();
2656 GPRReg storageReg
= storage
.gpr();
2657 GPRReg baseReg
= base
.gpr();
2662 GPRTemporary
resultTag(this);
2663 GPRTemporary
resultPayload(this);
2664 GPRReg resultTagReg
= resultTag
.gpr();
2665 GPRReg resultPayloadReg
= resultPayload
.gpr();
2667 JITCompiler::Jump outOfBounds
= m_jit
.branch32(
2668 MacroAssembler::AboveOrEqual
, propertyReg
,
2669 MacroAssembler::Address(storageReg
, ArrayStorage::vectorLengthOffset()));
2671 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), resultTagReg
);
2672 JITCompiler::Jump hole
= m_jit
.branch32(
2673 MacroAssembler::Equal
, resultTag
.gpr(), TrustedImm32(JSValue::EmptyValueTag
));
2674 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), resultPayloadReg
);
2676 JITCompiler::JumpList slowCases
;
2677 slowCases
.append(outOfBounds
);
2678 slowCases
.append(hole
);
2679 addSlowPathGenerator(
2681 slowCases
, this, operationGetByValArrayInt
,
2682 JSValueRegs(resultTagReg
, resultPayloadReg
),
2683 baseReg
, propertyReg
));
2685 jsValueResult(resultTagReg
, resultPayloadReg
, node
);
2689 compileGetByValOnString(node
);
2691 case Array::Arguments
:
2692 compileGetByValOnArguments(node
);
2694 case Array::Int8Array
:
2695 compileGetByValOnIntTypedArray(m_jit
.vm()->int8ArrayDescriptor(), node
, sizeof(int8_t), SignedTypedArray
);
2697 case Array::Int16Array
:
2698 compileGetByValOnIntTypedArray(m_jit
.vm()->int16ArrayDescriptor(), node
, sizeof(int16_t), SignedTypedArray
);
2700 case Array::Int32Array
:
2701 compileGetByValOnIntTypedArray(m_jit
.vm()->int32ArrayDescriptor(), node
, sizeof(int32_t), SignedTypedArray
);
2703 case Array::Uint8Array
:
2704 compileGetByValOnIntTypedArray(m_jit
.vm()->uint8ArrayDescriptor(), node
, sizeof(uint8_t), UnsignedTypedArray
);
2706 case Array::Uint8ClampedArray
:
2707 compileGetByValOnIntTypedArray(m_jit
.vm()->uint8ClampedArrayDescriptor(), node
, sizeof(uint8_t), UnsignedTypedArray
);
2709 case Array::Uint16Array
:
2710 compileGetByValOnIntTypedArray(m_jit
.vm()->uint16ArrayDescriptor(), node
, sizeof(uint16_t), UnsignedTypedArray
);
2712 case Array::Uint32Array
:
2713 compileGetByValOnIntTypedArray(m_jit
.vm()->uint32ArrayDescriptor(), node
, sizeof(uint32_t), UnsignedTypedArray
);
2715 case Array::Float32Array
:
2716 compileGetByValOnFloatTypedArray(m_jit
.vm()->float32ArrayDescriptor(), node
, sizeof(float));
2718 case Array::Float64Array
:
2719 compileGetByValOnFloatTypedArray(m_jit
.vm()->float64ArrayDescriptor(), node
, sizeof(double));
2722 RELEASE_ASSERT_NOT_REACHED();
2729 case PutByValAlias
: {
2730 Edge child1
= m_jit
.graph().varArgChild(node
, 0);
2731 Edge child2
= m_jit
.graph().varArgChild(node
, 1);
2732 Edge child3
= m_jit
.graph().varArgChild(node
, 2);
2733 Edge child4
= m_jit
.graph().varArgChild(node
, 3);
2735 ArrayMode arrayMode
= node
->arrayMode().modeForPut();
2736 bool alreadyHandled
= false;
2738 switch (arrayMode
.type()) {
2739 case Array::SelectUsingPredictions
:
2740 case Array::ForceExit
:
2741 RELEASE_ASSERT_NOT_REACHED();
2742 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
2743 alreadyHandled
= true;
2745 case Array::Generic
: {
2746 ASSERT(node
->op() == PutByVal
);
2748 SpeculateCellOperand
base(this, child1
); // Save a register, speculate cell. We'll probably be right.
2749 JSValueOperand
property(this, child2
);
2750 JSValueOperand
value(this, child3
);
2751 GPRReg baseGPR
= base
.gpr();
2752 GPRReg propertyTagGPR
= property
.tagGPR();
2753 GPRReg propertyPayloadGPR
= property
.payloadGPR();
2754 GPRReg valueTagGPR
= value
.tagGPR();
2755 GPRReg valuePayloadGPR
= value
.payloadGPR();
2758 callOperation(m_jit
.codeBlock()->isStrictMode() ? operationPutByValCellStrict
: operationPutByValCellNonStrict
, baseGPR
, propertyTagGPR
, propertyPayloadGPR
, valueTagGPR
, valuePayloadGPR
);
2761 alreadyHandled
= true;
2771 SpeculateCellOperand
base(this, child1
);
2772 SpeculateStrictInt32Operand
property(this, child2
);
2774 GPRReg baseReg
= base
.gpr();
2775 GPRReg propertyReg
= property
.gpr();
2777 switch (arrayMode
.type()) {
2778 case Array::Int32
: {
2779 SpeculateIntegerOperand
value(this, child3
);
2781 GPRReg valuePayloadReg
= value
.gpr();
2786 compileContiguousPutByVal(node
, base
, property
, value
, valuePayloadReg
, TrustedImm32(JSValue::Int32Tag
));
2789 case Array::Contiguous
: {
2790 JSValueOperand
value(this, child3
);
2792 GPRReg valueTagReg
= value
.tagGPR();
2793 GPRReg valuePayloadReg
= value
.payloadGPR();
2798 if (Heap::isWriteBarrierEnabled()) {
2799 GPRTemporary
scratch(this);
2800 writeBarrier(baseReg
, valueTagReg
, child3
, WriteBarrierForPropertyAccess
, scratch
.gpr());
2803 compileContiguousPutByVal(node
, base
, property
, value
, valuePayloadReg
, valueTagReg
);
2806 case Array::Double
: {
2807 compileDoublePutByVal(node
, base
, property
);
2810 case Array::ArrayStorage
:
2811 case Array::SlowPutArrayStorage
: {
2812 JSValueOperand
value(this, child3
);
2814 GPRReg valueTagReg
= value
.tagGPR();
2815 GPRReg valuePayloadReg
= value
.payloadGPR();
2821 GPRTemporary
scratch(this);
2822 GPRReg scratchReg
= scratch
.gpr();
2823 writeBarrier(baseReg
, valueTagReg
, child3
, WriteBarrierForPropertyAccess
, scratchReg
);
2826 StorageOperand
storage(this, child4
);
2827 GPRReg storageReg
= storage
.gpr();
2829 if (node
->op() == PutByValAlias
) {
2830 // Store the value to the array.
2831 GPRReg propertyReg
= property
.gpr();
2832 m_jit
.store32(value
.tagGPR(), MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
2833 m_jit
.store32(value
.payloadGPR(), MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
2839 MacroAssembler::JumpList slowCases
;
2841 MacroAssembler::Jump beyondArrayBounds
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(storageReg
, ArrayStorage::vectorLengthOffset()));
2842 if (!arrayMode
.isOutOfBounds())
2843 speculationCheck(OutOfBounds
, JSValueRegs(), 0, beyondArrayBounds
);
2845 slowCases
.append(beyondArrayBounds
);
2847 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2848 if (arrayMode
.isInBounds()) {
2850 StoreToHole
, JSValueRegs(), 0,
2851 m_jit
.branch32(MacroAssembler::Equal
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), TrustedImm32(JSValue::EmptyValueTag
)));
2853 MacroAssembler::Jump notHoleValue
= m_jit
.branch32(MacroAssembler::NotEqual
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), TrustedImm32(JSValue::EmptyValueTag
));
2854 if (arrayMode
.isSlowPut()) {
2855 // This is sort of strange. If we wanted to optimize this code path, we would invert
2856 // the above branch. But it's simply not worth it since this only happens if we're
2857 // already having a bad time.
2858 slowCases
.append(m_jit
.jump());
2860 m_jit
.add32(TrustedImm32(1), MacroAssembler::Address(storageReg
, ArrayStorage::numValuesInVectorOffset()));
2862 // If we're writing to a hole we might be growing the array;
2863 MacroAssembler::Jump lengthDoesNotNeedUpdate
= m_jit
.branch32(MacroAssembler::Below
, propertyReg
, MacroAssembler::Address(storageReg
, ArrayStorage::lengthOffset()));
2864 m_jit
.add32(TrustedImm32(1), propertyReg
);
2865 m_jit
.store32(propertyReg
, MacroAssembler::Address(storageReg
, ArrayStorage::lengthOffset()));
2866 m_jit
.sub32(TrustedImm32(1), propertyReg
);
2868 lengthDoesNotNeedUpdate
.link(&m_jit
);
2870 notHoleValue
.link(&m_jit
);
2873 // Store the value to the array.
2874 m_jit
.store32(valueTagReg
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
2875 m_jit
.store32(valuePayloadReg
, MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
2882 if (!slowCases
.empty()) {
2883 addSlowPathGenerator(
2886 m_jit
.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict
: operationPutByValBeyondArrayBoundsNonStrict
,
2887 NoResult
, baseReg
, propertyReg
, valueTagReg
, valuePayloadReg
));
2890 noResult(node
, UseChildrenCalledExplicitly
);
2894 case Array::Arguments
:
2895 // FIXME: we could at some point make this work. Right now we're assuming that the register
2896 // pressure would be too great.
2897 RELEASE_ASSERT_NOT_REACHED();
2900 case Array::Int8Array
:
2901 compilePutByValForIntTypedArray(m_jit
.vm()->int8ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(int8_t), SignedTypedArray
);
2904 case Array::Int16Array
:
2905 compilePutByValForIntTypedArray(m_jit
.vm()->int16ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(int16_t), SignedTypedArray
);
2908 case Array::Int32Array
:
2909 compilePutByValForIntTypedArray(m_jit
.vm()->int32ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(int32_t), SignedTypedArray
);
2912 case Array::Uint8Array
:
2913 compilePutByValForIntTypedArray(m_jit
.vm()->uint8ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(uint8_t), UnsignedTypedArray
);
2916 case Array::Uint8ClampedArray
:
2917 compilePutByValForIntTypedArray(m_jit
.vm()->uint8ClampedArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(uint8_t), UnsignedTypedArray
, ClampRounding
);
2920 case Array::Uint16Array
:
2921 compilePutByValForIntTypedArray(m_jit
.vm()->uint16ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(uint16_t), UnsignedTypedArray
);
2924 case Array::Uint32Array
:
2925 compilePutByValForIntTypedArray(m_jit
.vm()->uint32ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(uint32_t), UnsignedTypedArray
);
2928 case Array::Float32Array
:
2929 compilePutByValForFloatTypedArray(m_jit
.vm()->float32ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(float));
2932 case Array::Float64Array
:
2933 compilePutByValForFloatTypedArray(m_jit
.vm()->float64ArrayDescriptor(), base
.gpr(), property
.gpr(), node
, sizeof(double));
2937 RELEASE_ASSERT_NOT_REACHED();
2944 if (compileRegExpExec(node
))
2947 if (!node
->adjustedRefCount()) {
2948 SpeculateCellOperand
base(this, node
->child1());
2949 SpeculateCellOperand
argument(this, node
->child2());
2950 GPRReg baseGPR
= base
.gpr();
2951 GPRReg argumentGPR
= argument
.gpr();
2954 GPRResult
result(this);
2955 callOperation(operationRegExpTest
, result
.gpr(), baseGPR
, argumentGPR
);
2957 // Must use jsValueResult because otherwise we screw up register
2958 // allocation, which thinks that this node has a result.
2959 booleanResult(result
.gpr(), node
);
2963 SpeculateCellOperand
base(this, node
->child1());
2964 SpeculateCellOperand
argument(this, node
->child2());
2965 GPRReg baseGPR
= base
.gpr();
2966 GPRReg argumentGPR
= argument
.gpr();
2969 GPRResult2
resultTag(this);
2970 GPRResult
resultPayload(this);
2971 callOperation(operationRegExpExec
, resultTag
.gpr(), resultPayload
.gpr(), baseGPR
, argumentGPR
);
2973 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
2978 SpeculateCellOperand
base(this, node
->child1());
2979 SpeculateCellOperand
argument(this, node
->child2());
2980 GPRReg baseGPR
= base
.gpr();
2981 GPRReg argumentGPR
= argument
.gpr();
2984 GPRResult
result(this);
2985 callOperation(operationRegExpTest
, result
.gpr(), baseGPR
, argumentGPR
);
2987 // If we add a DataFormatBool, we should use it here.
2988 booleanResult(result
.gpr(), node
);
2993 ASSERT(node
->arrayMode().isJSArray());
2995 SpeculateCellOperand
base(this, node
->child1());
2996 GPRTemporary
storageLength(this);
2998 GPRReg baseGPR
= base
.gpr();
2999 GPRReg storageLengthGPR
= storageLength
.gpr();
3001 StorageOperand
storage(this, node
->child3());
3002 GPRReg storageGPR
= storage
.gpr();
3004 switch (node
->arrayMode().type()) {
3005 case Array::Int32
: {
3006 SpeculateIntegerOperand
value(this, node
->child2());
3007 GPRReg valuePayloadGPR
= value
.gpr();
3009 m_jit
.load32(MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()), storageLengthGPR
);
3010 MacroAssembler::Jump slowPath
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfVectorLength()));
3011 m_jit
.store32(TrustedImm32(JSValue::Int32Tag
), MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3012 m_jit
.store32(valuePayloadGPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3013 m_jit
.add32(TrustedImm32(1), storageLengthGPR
);
3014 m_jit
.store32(storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3015 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), storageGPR
);
3017 addSlowPathGenerator(
3019 slowPath
, this, operationArrayPush
,
3020 JSValueRegs(storageGPR
, storageLengthGPR
),
3021 TrustedImm32(JSValue::Int32Tag
), valuePayloadGPR
, baseGPR
));
3023 jsValueResult(storageGPR
, storageLengthGPR
, node
);
3027 case Array::Contiguous
: {
3028 JSValueOperand
value(this, node
->child2());
3029 GPRReg valueTagGPR
= value
.tagGPR();
3030 GPRReg valuePayloadGPR
= value
.payloadGPR();
3032 if (Heap::isWriteBarrierEnabled()) {
3033 GPRTemporary
scratch(this);
3034 writeBarrier(baseGPR
, valueTagGPR
, node
->child2(), WriteBarrierForPropertyAccess
, scratch
.gpr(), storageLengthGPR
);
3037 m_jit
.load32(MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()), storageLengthGPR
);
3038 MacroAssembler::Jump slowPath
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfVectorLength()));
3039 m_jit
.store32(valueTagGPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3040 m_jit
.store32(valuePayloadGPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3041 m_jit
.add32(TrustedImm32(1), storageLengthGPR
);
3042 m_jit
.store32(storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3043 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), storageGPR
);
3045 addSlowPathGenerator(
3047 slowPath
, this, operationArrayPush
,
3048 JSValueRegs(storageGPR
, storageLengthGPR
),
3049 valueTagGPR
, valuePayloadGPR
, baseGPR
));
3051 jsValueResult(storageGPR
, storageLengthGPR
, node
);
3055 case Array::Double
: {
3056 SpeculateDoubleOperand
value(this, node
->child2());
3057 FPRReg valueFPR
= value
.fpr();
3060 JSValueRegs(), node
->child2(), SpecRealNumber
,
3061 m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, valueFPR
, valueFPR
));
3063 m_jit
.load32(MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()), storageLengthGPR
);
3064 MacroAssembler::Jump slowPath
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfVectorLength()));
3065 m_jit
.storeDouble(valueFPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
));
3066 m_jit
.add32(TrustedImm32(1), storageLengthGPR
);
3067 m_jit
.store32(storageLengthGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3068 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), storageGPR
);
3070 addSlowPathGenerator(
3072 slowPath
, this, operationArrayPushDouble
,
3073 JSValueRegs(storageGPR
, storageLengthGPR
),
3074 valueFPR
, baseGPR
));
3076 jsValueResult(storageGPR
, storageLengthGPR
, node
);
3080 case Array::ArrayStorage
: {
3081 JSValueOperand
value(this, node
->child2());
3082 GPRReg valueTagGPR
= value
.tagGPR();
3083 GPRReg valuePayloadGPR
= value
.payloadGPR();
3085 if (Heap::isWriteBarrierEnabled()) {
3086 GPRTemporary
scratch(this);
3087 writeBarrier(baseGPR
, valueTagGPR
, node
->child2(), WriteBarrierForPropertyAccess
, scratch
.gpr(), storageLengthGPR
);
3090 m_jit
.load32(MacroAssembler::Address(storageGPR
, ArrayStorage::lengthOffset()), storageLengthGPR
);
3092 // Refuse to handle bizarre lengths.
3093 speculationCheck(Uncountable
, JSValueRegs(), 0, m_jit
.branch32(MacroAssembler::Above
, storageLengthGPR
, TrustedImm32(0x7ffffffe)));
3095 MacroAssembler::Jump slowPath
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, storageLengthGPR
, MacroAssembler::Address(storageGPR
, ArrayStorage::vectorLengthOffset()));
3097 m_jit
.store32(valueTagGPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3098 m_jit
.store32(valuePayloadGPR
, MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3100 m_jit
.add32(TrustedImm32(1), storageLengthGPR
);
3101 m_jit
.store32(storageLengthGPR
, MacroAssembler::Address(storageGPR
, ArrayStorage::lengthOffset()));
3102 m_jit
.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR
, OBJECT_OFFSETOF(ArrayStorage
, m_numValuesInVector
)));
3103 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), storageGPR
);
3105 addSlowPathGenerator(slowPathCall(slowPath
, this, operationArrayPush
, JSValueRegs(storageGPR
, storageLengthGPR
), valueTagGPR
, valuePayloadGPR
, baseGPR
));
3107 jsValueResult(storageGPR
, storageLengthGPR
, node
);
3119 ASSERT(node
->arrayMode().isJSArray());
3121 SpeculateCellOperand
base(this, node
->child1());
3122 StorageOperand
storage(this, node
->child2());
3123 GPRTemporary
valueTag(this);
3124 GPRTemporary
valuePayload(this);
3126 GPRReg baseGPR
= base
.gpr();
3127 GPRReg valueTagGPR
= valueTag
.gpr();
3128 GPRReg valuePayloadGPR
= valuePayload
.gpr();
3129 GPRReg storageGPR
= storage
.gpr();
3131 switch (node
->arrayMode().type()) {
3133 case Array::Contiguous
: {
3135 MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()), valuePayloadGPR
);
3136 MacroAssembler::Jump undefinedCase
=
3137 m_jit
.branchTest32(MacroAssembler::Zero
, valuePayloadGPR
);
3138 m_jit
.sub32(TrustedImm32(1), valuePayloadGPR
);
3140 valuePayloadGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3142 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)),
3144 MacroAssembler::Jump slowCase
= m_jit
.branch32(MacroAssembler::Equal
, valueTagGPR
, TrustedImm32(JSValue::EmptyValueTag
));
3146 MacroAssembler::TrustedImm32(JSValue::EmptyValueTag
),
3147 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3149 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)),
3152 addSlowPathGenerator(
3154 undefinedCase
, this,
3155 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR
,
3156 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR
));
3157 addSlowPathGenerator(
3159 slowCase
, this, operationArrayPopAndRecoverLength
,
3160 JSValueRegs(valueTagGPR
, valuePayloadGPR
), baseGPR
));
3162 jsValueResult(valueTagGPR
, valuePayloadGPR
, node
);
3166 case Array::Double
: {
3167 FPRTemporary
temp(this);
3168 FPRReg tempFPR
= temp
.fpr();
3171 MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()), valuePayloadGPR
);
3172 MacroAssembler::Jump undefinedCase
=
3173 m_jit
.branchTest32(MacroAssembler::Zero
, valuePayloadGPR
);
3174 m_jit
.sub32(TrustedImm32(1), valuePayloadGPR
);
3176 valuePayloadGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3178 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
),
3180 MacroAssembler::Jump slowCase
= m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, tempFPR
, tempFPR
);
3181 JSValue nan
= JSValue(JSValue::EncodeAsDouble
, QNaN
);
3183 MacroAssembler::TrustedImm32(nan
.u
.asBits
.tag
),
3184 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3186 MacroAssembler::TrustedImm32(nan
.u
.asBits
.payload
),
3187 MacroAssembler::BaseIndex(storageGPR
, valuePayloadGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3188 boxDouble(tempFPR
, valueTagGPR
, valuePayloadGPR
);
3190 addSlowPathGenerator(
3192 undefinedCase
, this,
3193 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR
,
3194 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR
));
3195 addSlowPathGenerator(
3197 slowCase
, this, operationArrayPopAndRecoverLength
,
3198 JSValueRegs(valueTagGPR
, valuePayloadGPR
), baseGPR
));
3200 jsValueResult(valueTagGPR
, valuePayloadGPR
, node
);
3204 case Array::ArrayStorage
: {
3205 GPRTemporary
storageLength(this);
3206 GPRReg storageLengthGPR
= storageLength
.gpr();
3208 m_jit
.load32(MacroAssembler::Address(storageGPR
, ArrayStorage::lengthOffset()), storageLengthGPR
);
3210 JITCompiler::JumpList setUndefinedCases
;
3211 setUndefinedCases
.append(m_jit
.branchTest32(MacroAssembler::Zero
, storageLengthGPR
));
3213 m_jit
.sub32(TrustedImm32(1), storageLengthGPR
);
3215 MacroAssembler::Jump slowCase
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, storageLengthGPR
, MacroAssembler::Address(storageGPR
, ArrayStorage::vectorLengthOffset()));
3217 m_jit
.load32(MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)), valueTagGPR
);
3218 m_jit
.load32(MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), valuePayloadGPR
);
3220 m_jit
.store32(storageLengthGPR
, MacroAssembler::Address(storageGPR
, ArrayStorage::lengthOffset()));
3222 setUndefinedCases
.append(m_jit
.branch32(MacroAssembler::Equal
, TrustedImm32(JSValue::EmptyValueTag
), valueTagGPR
));
3224 m_jit
.store32(TrustedImm32(JSValue::EmptyValueTag
), MacroAssembler::BaseIndex(storageGPR
, storageLengthGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(ArrayStorage
, m_vector
[0]) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3226 m_jit
.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR
, OBJECT_OFFSETOF(ArrayStorage
, m_numValuesInVector
)));
3228 addSlowPathGenerator(
3230 setUndefinedCases
, this,
3231 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR
,
3232 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR
));
3234 addSlowPathGenerator(
3236 slowCase
, this, operationArrayPop
,
3237 JSValueRegs(valueTagGPR
, valuePayloadGPR
), baseGPR
));
3239 jsValueResult(valueTagGPR
, valuePayloadGPR
, node
);
3251 BlockIndex taken
= node
->takenBlockIndex();
3262 ASSERT(GPRInfo::callFrameRegister
!= GPRInfo::regT2
);
3263 ASSERT(GPRInfo::regT1
!= GPRInfo::returnValueGPR
);
3264 ASSERT(GPRInfo::returnValueGPR
!= GPRInfo::callFrameRegister
);
3266 #if DFG_ENABLE(SUCCESS_STATS)
3267 static SamplingCounter
counter("SpeculativeJIT");
3268 m_jit
.emitCount(counter
);
3271 // Return the result in returnValueGPR.
3272 JSValueOperand
op1(this, node
->child1());
3275 boxDouble(op1
.fpr(), GPRInfo::returnValueGPR2
, GPRInfo::returnValueGPR
);
3277 if (op1
.payloadGPR() == GPRInfo::returnValueGPR2
&& op1
.tagGPR() == GPRInfo::returnValueGPR
)
3278 m_jit
.swap(GPRInfo::returnValueGPR
, GPRInfo::returnValueGPR2
);
3279 else if (op1
.payloadGPR() == GPRInfo::returnValueGPR2
) {
3280 m_jit
.move(op1
.payloadGPR(), GPRInfo::returnValueGPR
);
3281 m_jit
.move(op1
.tagGPR(), GPRInfo::returnValueGPR2
);
3283 m_jit
.move(op1
.tagGPR(), GPRInfo::returnValueGPR2
);
3284 m_jit
.move(op1
.payloadGPR(), GPRInfo::returnValueGPR
);
3288 // Grab the return address.
3289 m_jit
.emitGetFromCallFrameHeaderPtr(JSStack::ReturnPC
, GPRInfo::regT2
);
3290 // Restore our caller's "r".
3291 m_jit
.emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame
, GPRInfo::callFrameRegister
);
3293 m_jit
.restoreReturnAddressBeforeReturn(GPRInfo::regT2
);
3301 case ThrowReferenceError
: {
3302 // We expect that throw statements are rare and are intended to exit the code block
3303 // anyway, so we just OSR back to the old JIT for now.
3304 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), 0);
3309 RELEASE_ASSERT(node
->child1().useKind() == UntypedUse
);
3310 JSValueOperand
op1(this, node
->child1());
3311 GPRTemporary
resultTag(this, op1
);
3312 GPRTemporary
resultPayload(this, op1
, false);
3314 GPRReg op1TagGPR
= op1
.tagGPR();
3315 GPRReg op1PayloadGPR
= op1
.payloadGPR();
3316 GPRReg resultTagGPR
= resultTag
.gpr();
3317 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3321 if (!(m_state
.forNode(node
->child1()).m_type
& ~(SpecNumber
| SpecBoolean
))) {
3322 m_jit
.move(op1TagGPR
, resultTagGPR
);
3323 m_jit
.move(op1PayloadGPR
, resultPayloadGPR
);
3325 MacroAssembler::Jump alreadyPrimitive
= m_jit
.branch32(MacroAssembler::NotEqual
, op1TagGPR
, TrustedImm32(JSValue::CellTag
));
3326 MacroAssembler::Jump notPrimitive
= m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(op1PayloadGPR
, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit
.vm()->stringStructure
.get()));
3328 alreadyPrimitive
.link(&m_jit
);
3329 m_jit
.move(op1TagGPR
, resultTagGPR
);
3330 m_jit
.move(op1PayloadGPR
, resultPayloadGPR
);
3332 addSlowPathGenerator(
3334 notPrimitive
, this, operationToPrimitive
,
3335 JSValueRegs(resultTagGPR
, resultPayloadGPR
), op1TagGPR
, op1PayloadGPR
));
3338 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
3343 if (node
->child1().useKind() == UntypedUse
) {
3344 JSValueOperand
op1(this, node
->child1());
3345 GPRReg op1PayloadGPR
= op1
.payloadGPR();
3346 GPRReg op1TagGPR
= op1
.tagGPR();
3348 GPRResult
result(this);
3349 GPRReg resultGPR
= result
.gpr();
3353 JITCompiler::Jump done
;
3354 if (node
->child1()->prediction() & SpecString
) {
3355 JITCompiler::Jump slowPath1
= m_jit
.branch32(
3356 JITCompiler::NotEqual
, op1TagGPR
, TrustedImm32(JSValue::CellTag
));
3357 JITCompiler::Jump slowPath2
= m_jit
.branchPtr(
3358 JITCompiler::NotEqual
,
3359 JITCompiler::Address(op1PayloadGPR
, JSCell::structureOffset()),
3360 TrustedImmPtr(m_jit
.vm()->stringStructure
.get()));
3361 m_jit
.move(op1PayloadGPR
, resultGPR
);
3362 done
= m_jit
.jump();
3363 slowPath1
.link(&m_jit
);
3364 slowPath2
.link(&m_jit
);
3366 callOperation(operationToString
, resultGPR
, op1TagGPR
, op1PayloadGPR
);
3369 cellResult(resultGPR
, node
);
3373 compileToStringOnCell(node
);
3377 case NewStringObject
: {
3378 compileNewStringObject(node
);
3383 JSGlobalObject
* globalObject
= m_jit
.graph().globalObjectFor(node
->codeOrigin
);
3384 if (!globalObject
->isHavingABadTime() && !hasArrayStorage(node
->indexingType())) {
3385 globalObject
->havingABadTimeWatchpoint()->add(speculationWatchpoint());
3387 Structure
* structure
= globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType());
3388 ASSERT(structure
->indexingType() == node
->indexingType());
3390 hasUndecided(structure
->indexingType())
3391 || hasInt32(structure
->indexingType())
3392 || hasDouble(structure
->indexingType())
3393 || hasContiguous(structure
->indexingType()));
3395 unsigned numElements
= node
->numChildren();
3397 GPRTemporary
result(this);
3398 GPRTemporary
storage(this);
3400 GPRReg resultGPR
= result
.gpr();
3401 GPRReg storageGPR
= storage
.gpr();
3403 emitAllocateJSArray(resultGPR
, structure
, storageGPR
, numElements
);
3405 // At this point, one way or another, resultGPR and storageGPR have pointers to
3406 // the JSArray and the Butterfly, respectively.
3408 ASSERT(!hasUndecided(structure
->indexingType()) || !node
->numChildren());
3410 for (unsigned operandIdx
= 0; operandIdx
< node
->numChildren(); ++operandIdx
) {
3411 Edge use
= m_jit
.graph().m_varArgChildren
[node
->firstChild() + operandIdx
];
3412 switch (node
->indexingType()) {
3413 case ALL_BLANK_INDEXING_TYPES
:
3414 case ALL_UNDECIDED_INDEXING_TYPES
:
3417 case ALL_DOUBLE_INDEXING_TYPES
: {
3418 SpeculateDoubleOperand
operand(this, use
);
3419 FPRReg opFPR
= operand
.fpr();
3421 JSValueRegs(), use
, SpecRealNumber
,
3422 m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, opFPR
, opFPR
));
3424 m_jit
.storeDouble(opFPR
, MacroAssembler::Address(storageGPR
, sizeof(double) * operandIdx
));
3427 case ALL_INT32_INDEXING_TYPES
: {
3428 SpeculateIntegerOperand
operand(this, use
);
3429 m_jit
.store32(TrustedImm32(JSValue::Int32Tag
), MacroAssembler::Address(storageGPR
, sizeof(JSValue
) * operandIdx
+ OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3430 m_jit
.store32(operand
.gpr(), MacroAssembler::Address(storageGPR
, sizeof(JSValue
) * operandIdx
+ OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3433 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
3434 JSValueOperand
operand(this, m_jit
.graph().m_varArgChildren
[node
->firstChild() + operandIdx
]);
3435 GPRReg opTagGPR
= operand
.tagGPR();
3436 GPRReg opPayloadGPR
= operand
.payloadGPR();
3437 m_jit
.store32(opTagGPR
, MacroAssembler::Address(storageGPR
, sizeof(JSValue
) * operandIdx
+ OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3438 m_jit
.store32(opPayloadGPR
, MacroAssembler::Address(storageGPR
, sizeof(JSValue
) * operandIdx
+ OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3447 // Yuck, we should *really* have a way of also returning the storageGPR. But
3448 // that's the least of what's wrong with this code. We really shouldn't be
3449 // allocating the array after having computed - and probably spilled to the
3450 // stack - all of the things that will go into the array. The solution to that
3451 // bigger problem will also likely fix the redundancy in reloading the storage
3452 // pointer that we currently have.
3454 cellResult(resultGPR
, node
);
3458 if (!node
->numChildren()) {
3460 GPRResult
result(this);
3462 operationNewEmptyArray
, result
.gpr(), globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()));
3463 cellResult(result
.gpr(), node
);
3467 size_t scratchSize
= sizeof(EncodedJSValue
) * node
->numChildren();
3468 ScratchBuffer
* scratchBuffer
= m_jit
.vm()->scratchBufferForSize(scratchSize
);
3469 EncodedJSValue
* buffer
= scratchBuffer
? static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer()) : 0;
3471 for (unsigned operandIdx
= 0; operandIdx
< node
->numChildren(); ++operandIdx
) {
3472 // Need to perform the speculations that this node promises to perform. If we're
3473 // emitting code here and the indexing type is not array storage then there is
3474 // probably something hilarious going on and we're already failing at all the
3475 // things, but at least we're going to be sound.
3476 Edge use
= m_jit
.graph().m_varArgChildren
[node
->firstChild() + operandIdx
];
3477 switch (node
->indexingType()) {
3478 case ALL_BLANK_INDEXING_TYPES
:
3479 case ALL_UNDECIDED_INDEXING_TYPES
:
3482 case ALL_DOUBLE_INDEXING_TYPES
: {
3483 SpeculateDoubleOperand
operand(this, use
);
3484 FPRReg opFPR
= operand
.fpr();
3486 JSValueRegs(), use
, SpecRealNumber
,
3487 m_jit
.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered
, opFPR
, opFPR
));
3489 m_jit
.storeDouble(opFPR
, reinterpret_cast<char*>(buffer
+ operandIdx
));
3492 case ALL_INT32_INDEXING_TYPES
: {
3493 SpeculateIntegerOperand
operand(this, use
);
3494 GPRReg opGPR
= operand
.gpr();
3495 m_jit
.store32(TrustedImm32(JSValue::Int32Tag
), reinterpret_cast<char*>(buffer
+ operandIdx
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
3496 m_jit
.store32(opGPR
, reinterpret_cast<char*>(buffer
+ operandIdx
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
3499 case ALL_CONTIGUOUS_INDEXING_TYPES
:
3500 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
3501 JSValueOperand
operand(this, m_jit
.graph().m_varArgChildren
[node
->firstChild() + operandIdx
]);
3502 GPRReg opTagGPR
= operand
.tagGPR();
3503 GPRReg opPayloadGPR
= operand
.payloadGPR();
3505 m_jit
.store32(opTagGPR
, reinterpret_cast<char*>(buffer
+ operandIdx
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
3506 m_jit
.store32(opPayloadGPR
, reinterpret_cast<char*>(buffer
+ operandIdx
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
3516 switch (node
->indexingType()) {
3517 case ALL_DOUBLE_INDEXING_TYPES
:
3518 case ALL_INT32_INDEXING_TYPES
:
3528 GPRTemporary
scratch(this);
3530 // Tell GC mark phase how much of the scratch buffer is active during call.
3531 m_jit
.move(TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratch
.gpr());
3532 m_jit
.storePtr(TrustedImmPtr(scratchSize
), scratch
.gpr());
3535 GPRResult
result(this);
3538 operationNewArray
, result
.gpr(), globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()),
3539 static_cast<void*>(buffer
), node
->numChildren());
3542 GPRTemporary
scratch(this);
3544 m_jit
.move(TrustedImmPtr(scratchBuffer
->activeLengthPtr()), scratch
.gpr());
3545 m_jit
.storePtr(TrustedImmPtr(0), scratch
.gpr());
3548 cellResult(result
.gpr(), node
, UseChildrenCalledExplicitly
);
3552 case NewArrayWithSize
: {
3553 JSGlobalObject
* globalObject
= m_jit
.graph().globalObjectFor(node
->codeOrigin
);
3554 if (!globalObject
->isHavingABadTime() && !hasArrayStorage(node
->indexingType())) {
3555 globalObject
->havingABadTimeWatchpoint()->add(speculationWatchpoint());
3557 SpeculateStrictInt32Operand
size(this, node
->child1());
3558 GPRTemporary
result(this);
3559 GPRTemporary
storage(this);
3560 GPRTemporary
scratch(this);
3561 GPRTemporary
scratch2(this);
3563 GPRReg sizeGPR
= size
.gpr();
3564 GPRReg resultGPR
= result
.gpr();
3565 GPRReg storageGPR
= storage
.gpr();
3566 GPRReg scratchGPR
= scratch
.gpr();
3567 GPRReg scratch2GPR
= scratch2
.gpr();
3569 MacroAssembler::JumpList slowCases
;
3570 slowCases
.append(m_jit
.branch32(MacroAssembler::AboveOrEqual
, sizeGPR
, TrustedImm32(MIN_SPARSE_ARRAY_INDEX
)));
3572 ASSERT((1 << 3) == sizeof(JSValue
));
3573 m_jit
.move(sizeGPR
, scratchGPR
);
3574 m_jit
.lshift32(TrustedImm32(3), scratchGPR
);
3575 m_jit
.add32(TrustedImm32(sizeof(IndexingHeader
)), scratchGPR
, resultGPR
);
3577 emitAllocateBasicStorage(resultGPR
, storageGPR
));
3578 m_jit
.subPtr(scratchGPR
, storageGPR
);
3579 Structure
* structure
= globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType());
3580 emitAllocateJSObject
<JSArray
>(resultGPR
, TrustedImmPtr(structure
), storageGPR
, scratchGPR
, scratch2GPR
, slowCases
);
3582 m_jit
.store32(sizeGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfPublicLength()));
3583 m_jit
.store32(sizeGPR
, MacroAssembler::Address(storageGPR
, Butterfly::offsetOfVectorLength()));
3585 if (hasDouble(node
->indexingType())) {
3586 JSValue nan
= JSValue(JSValue::EncodeAsDouble
, QNaN
);
3588 m_jit
.move(sizeGPR
, scratchGPR
);
3589 MacroAssembler::Jump done
= m_jit
.branchTest32(MacroAssembler::Zero
, scratchGPR
);
3590 MacroAssembler::Label loop
= m_jit
.label();
3591 m_jit
.sub32(TrustedImm32(1), scratchGPR
);
3592 m_jit
.store32(TrustedImm32(nan
.u
.asBits
.tag
), MacroAssembler::BaseIndex(storageGPR
, scratchGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
)));
3593 m_jit
.store32(TrustedImm32(nan
.u
.asBits
.payload
), MacroAssembler::BaseIndex(storageGPR
, scratchGPR
, MacroAssembler::TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)));
3594 m_jit
.branchTest32(MacroAssembler::NonZero
, scratchGPR
).linkTo(loop
, &m_jit
);
3598 addSlowPathGenerator(adoptPtr(
3599 new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
3600 slowCases
, this, operationNewArrayWithSize
, resultGPR
,
3601 globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()),
3602 globalObject
->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage
),
3605 cellResult(resultGPR
, node
);
3609 SpeculateStrictInt32Operand
size(this, node
->child1());
3610 GPRReg sizeGPR
= size
.gpr();
3612 GPRResult
result(this);
3613 GPRReg resultGPR
= result
.gpr();
3614 GPRReg structureGPR
= selectScratchGPR(sizeGPR
);
3615 MacroAssembler::Jump bigLength
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, sizeGPR
, TrustedImm32(MIN_SPARSE_ARRAY_INDEX
));
3616 m_jit
.move(TrustedImmPtr(globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType())), structureGPR
);
3617 MacroAssembler::Jump done
= m_jit
.jump();
3618 bigLength
.link(&m_jit
);
3619 m_jit
.move(TrustedImmPtr(globalObject
->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage
)), structureGPR
);
3622 operationNewArrayWithSize
, resultGPR
, structureGPR
, sizeGPR
);
3623 cellResult(resultGPR
, node
);
3627 case NewArrayBuffer
: {
3628 JSGlobalObject
* globalObject
= m_jit
.graph().globalObjectFor(node
->codeOrigin
);
3629 IndexingType indexingType
= node
->indexingType();
3630 if (!globalObject
->isHavingABadTime() && !hasArrayStorage(indexingType
)) {
3631 globalObject
->havingABadTimeWatchpoint()->add(speculationWatchpoint());
3633 unsigned numElements
= node
->numConstants();
3635 GPRTemporary
result(this);
3636 GPRTemporary
storage(this);
3638 GPRReg resultGPR
= result
.gpr();
3639 GPRReg storageGPR
= storage
.gpr();
3641 emitAllocateJSArray(resultGPR
, globalObject
->arrayStructureForIndexingTypeDuringAllocation(indexingType
), storageGPR
, numElements
);
3643 if (node
->indexingType() == ArrayWithDouble
) {
3644 JSValue
* data
= m_jit
.codeBlock()->constantBuffer(node
->startConstant());
3645 for (unsigned index
= 0; index
< node
->numConstants(); ++index
) {
3650 u
.value
= data
[index
].asNumber();
3651 m_jit
.store32(Imm32(u
.halves
[0]), MacroAssembler::Address(storageGPR
, sizeof(double) * index
));
3652 m_jit
.store32(Imm32(u
.halves
[1]), MacroAssembler::Address(storageGPR
, sizeof(double) * index
+ sizeof(int32_t)));
3655 int32_t* data
= bitwise_cast
<int32_t*>(m_jit
.codeBlock()->constantBuffer(node
->startConstant()));
3656 for (unsigned index
= 0; index
< node
->numConstants() * 2; ++index
) {
3658 Imm32(data
[index
]), MacroAssembler::Address(storageGPR
, sizeof(int32_t) * index
));
3662 cellResult(resultGPR
, node
);
3667 GPRResult
result(this);
3669 callOperation(operationNewArrayBuffer
, result
.gpr(), globalObject
->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()), node
->startConstant(), node
->numConstants());
3671 cellResult(result
.gpr(), node
);
3677 GPRResult
resultPayload(this);
3678 GPRResult2
resultTag(this);
3680 callOperation(operationNewRegexp
, resultTag
.gpr(), resultPayload
.gpr(), m_jit
.codeBlock()->regexp(node
->regexpIndex()));
3682 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
3683 cellResult(resultPayload
.gpr(), node
);
3688 ASSERT(node
->child1().useKind() == UntypedUse
);
3690 JSValueOperand
thisValue(this, node
->child1());
3691 GPRReg thisValueTagGPR
= thisValue
.tagGPR();
3692 GPRReg thisValuePayloadGPR
= thisValue
.payloadGPR();
3696 GPRResult2
resultTag(this);
3697 GPRResult
resultPayload(this);
3698 callOperation(operationConvertThis
, resultTag
.gpr(), resultPayload
.gpr(), thisValueTagGPR
, thisValuePayloadGPR
);
3700 cellResult(resultPayload
.gpr(), node
);
3705 // Note that there is not so much profit to speculate here. The only things we
3706 // speculate on are (1) that it's a cell, since that eliminates cell checks
3707 // later if the proto is reused, and (2) if we have a FinalObject prediction
3708 // then we speculate because we want to get recompiled if it isn't (since
3709 // otherwise we'd start taking slow path a lot).
3711 SpeculateCellOperand
callee(this, node
->child1());
3712 GPRTemporary
result(this);
3713 GPRTemporary
allocator(this);
3714 GPRTemporary
structure(this);
3715 GPRTemporary
scratch(this);
3717 GPRReg calleeGPR
= callee
.gpr();
3718 GPRReg resultGPR
= result
.gpr();
3719 GPRReg allocatorGPR
= allocator
.gpr();
3720 GPRReg structureGPR
= structure
.gpr();
3721 GPRReg scratchGPR
= scratch
.gpr();
3723 MacroAssembler::JumpList slowPath
;
3725 m_jit
.loadPtr(JITCompiler::Address(calleeGPR
, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR
);
3726 m_jit
.loadPtr(JITCompiler::Address(calleeGPR
, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR
);
3727 slowPath
.append(m_jit
.branchTestPtr(MacroAssembler::Zero
, allocatorGPR
));
3728 emitAllocateJSObject(resultGPR
, allocatorGPR
, structureGPR
, TrustedImmPtr(0), scratchGPR
, slowPath
);
3730 addSlowPathGenerator(slowPathCall(slowPath
, this, operationCreateThis
, resultGPR
, calleeGPR
, node
->inlineCapacity()));
3732 cellResult(resultGPR
, node
);
3736 case AllocationProfileWatchpoint
: {
3737 jsCast
<JSFunction
*>(node
->function())->addAllocationProfileWatchpoint(speculationWatchpoint());
3743 GPRTemporary
result(this);
3744 GPRTemporary
allocator(this);
3745 GPRTemporary
scratch(this);
3747 GPRReg resultGPR
= result
.gpr();
3748 GPRReg allocatorGPR
= allocator
.gpr();
3749 GPRReg scratchGPR
= scratch
.gpr();
3751 MacroAssembler::JumpList slowPath
;
3753 Structure
* structure
= node
->structure();
3754 size_t allocationSize
= JSObject::allocationSize(structure
->inlineCapacity());
3755 MarkedAllocator
* allocatorPtr
= &m_jit
.vm()->heap
.allocatorForObjectWithoutDestructor(allocationSize
);
3757 m_jit
.move(TrustedImmPtr(allocatorPtr
), allocatorGPR
);
3758 emitAllocateJSObject(resultGPR
, allocatorGPR
, TrustedImmPtr(structure
), TrustedImmPtr(0), scratchGPR
, slowPath
);
3760 addSlowPathGenerator(slowPathCall(slowPath
, this, operationNewObject
, resultGPR
, structure
));
3762 cellResult(resultGPR
, node
);
3767 GPRTemporary
result(this);
3768 m_jit
.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister
>(node
->codeOrigin
.stackOffset() + static_cast<int>(JSStack::Callee
))), result
.gpr());
3769 cellResult(result
.gpr(), node
);
3774 SpeculateCellOperand
callee(this, node
->child1());
3775 m_jit
.storePtr(callee
.gpr(), JITCompiler::payloadFor(static_cast<VirtualRegister
>(node
->codeOrigin
.stackOffset() + static_cast<int>(JSStack::Callee
))));
3776 m_jit
.store32(MacroAssembler::TrustedImm32(JSValue::CellTag
), JITCompiler::tagFor(static_cast<VirtualRegister
>(node
->codeOrigin
.stackOffset() + static_cast<int>(JSStack::Callee
))));
3782 SpeculateCellOperand
function(this, node
->child1());
3783 GPRTemporary
result(this, function
);
3784 m_jit
.loadPtr(JITCompiler::Address(function
.gpr(), JSFunction::offsetOfScopeChain()), result
.gpr());
3785 cellResult(result
.gpr(), node
);
3790 GPRTemporary
result(this);
3791 GPRReg resultGPR
= result
.gpr();
3793 m_jit
.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister
>(node
->codeOrigin
.stackOffset() + static_cast<int>(JSStack::ScopeChain
))), resultGPR
);
3794 cellResult(resultGPR
, node
);
3799 SpeculateCellOperand
callee(this, node
->child1());
3800 m_jit
.storePtr(callee
.gpr(), JITCompiler::payloadFor(static_cast<VirtualRegister
>(node
->codeOrigin
.stackOffset() + static_cast<int>(JSStack::ScopeChain
))));
3805 case SkipTopScope
: {
3806 SpeculateCellOperand
scope(this, node
->child1());
3807 GPRTemporary
result(this, scope
);
3808 GPRReg resultGPR
= result
.gpr();
3809 m_jit
.move(scope
.gpr(), resultGPR
);
3810 JITCompiler::Jump activationNotCreated
=
3811 m_jit
.branchTestPtr(
3813 JITCompiler::payloadFor(
3814 static_cast<VirtualRegister
>(m_jit
.codeBlock()->activationRegister())));
3815 m_jit
.loadPtr(JITCompiler::Address(resultGPR
, JSScope::offsetOfNext()), resultGPR
);
3816 activationNotCreated
.link(&m_jit
);
3817 cellResult(resultGPR
, node
);
3822 SpeculateCellOperand
scope(this, node
->child1());
3823 GPRTemporary
result(this, scope
);
3824 m_jit
.loadPtr(JITCompiler::Address(scope
.gpr(), JSScope::offsetOfNext()), result
.gpr());
3825 cellResult(result
.gpr(), node
);
3829 case GetScopeRegisters
: {
3830 SpeculateCellOperand
scope(this, node
->child1());
3831 GPRTemporary
result(this);
3832 GPRReg scopeGPR
= scope
.gpr();
3833 GPRReg resultGPR
= result
.gpr();
3835 m_jit
.loadPtr(JITCompiler::Address(scopeGPR
, JSVariableObject::offsetOfRegisters()), resultGPR
);
3836 storageResult(resultGPR
, node
);
3839 case GetScopedVar
: {
3840 StorageOperand
registers(this, node
->child1());
3841 GPRTemporary
resultTag(this);
3842 GPRTemporary
resultPayload(this);
3843 GPRReg registersGPR
= registers
.gpr();
3844 GPRReg resultTagGPR
= resultTag
.gpr();
3845 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3846 m_jit
.load32(JITCompiler::Address(registersGPR
, node
->varNumber() * sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)), resultTagGPR
);
3847 m_jit
.load32(JITCompiler::Address(registersGPR
, node
->varNumber() * sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)), resultPayloadGPR
);
3848 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
3851 case PutScopedVar
: {
3852 SpeculateCellOperand
scope(this, node
->child1());
3853 StorageOperand
registers(this, node
->child2());
3854 JSValueOperand
value(this, node
->child3());
3855 GPRTemporary
scratchRegister(this);
3856 GPRReg scopeGPR
= scope
.gpr();
3857 GPRReg registersGPR
= registers
.gpr();
3858 GPRReg valueTagGPR
= value
.tagGPR();
3859 GPRReg valuePayloadGPR
= value
.payloadGPR();
3860 GPRReg scratchGPR
= scratchRegister
.gpr();
3862 m_jit
.store32(valueTagGPR
, JITCompiler::Address(registersGPR
, node
->varNumber() * sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
3863 m_jit
.store32(valuePayloadGPR
, JITCompiler::Address(registersGPR
, node
->varNumber() * sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
3864 writeBarrier(scopeGPR
, valueTagGPR
, node
->child2(), WriteBarrierForVariableAccess
, scratchGPR
);
3870 if (!node
->prediction()) {
3871 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
3875 if (isCellSpeculation(node
->child1()->prediction())) {
3876 SpeculateCellOperand
base(this, node
->child1());
3877 GPRTemporary
resultTag(this, base
);
3878 GPRTemporary
resultPayload(this);
3880 GPRReg baseGPR
= base
.gpr();
3881 GPRReg resultTagGPR
= resultTag
.gpr();
3882 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3886 cachedGetById(node
->codeOrigin
, InvalidGPRReg
, baseGPR
, resultTagGPR
, resultPayloadGPR
, node
->identifierNumber());
3888 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
3892 JSValueOperand
base(this, node
->child1());
3893 GPRTemporary
resultTag(this, base
);
3894 GPRTemporary
resultPayload(this);
3896 GPRReg baseTagGPR
= base
.tagGPR();
3897 GPRReg basePayloadGPR
= base
.payloadGPR();
3898 GPRReg resultTagGPR
= resultTag
.gpr();
3899 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3903 JITCompiler::Jump notCell
= m_jit
.branch32(JITCompiler::NotEqual
, baseTagGPR
, TrustedImm32(JSValue::CellTag
));
3905 cachedGetById(node
->codeOrigin
, baseTagGPR
, basePayloadGPR
, resultTagGPR
, resultPayloadGPR
, node
->identifierNumber(), notCell
);
3907 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
3911 case GetByIdFlush
: {
3912 if (!node
->prediction()) {
3913 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
3917 switch (node
->child1().useKind()) {
3919 SpeculateCellOperand
base(this, node
->child1());
3921 GPRReg baseGPR
= base
.gpr();
3923 GPRResult
resultTag(this);
3924 GPRResult2
resultPayload(this);
3925 GPRReg resultTagGPR
= resultTag
.gpr();
3926 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3932 cachedGetById(node
->codeOrigin
, InvalidGPRReg
, baseGPR
, resultTagGPR
, resultPayloadGPR
, node
->identifierNumber(), JITCompiler::Jump(), DontSpill
);
3934 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
3939 JSValueOperand
base(this, node
->child1());
3940 GPRReg baseTagGPR
= base
.tagGPR();
3941 GPRReg basePayloadGPR
= base
.payloadGPR();
3943 GPRResult
resultTag(this);
3944 GPRResult2
resultPayload(this);
3945 GPRReg resultTagGPR
= resultTag
.gpr();
3946 GPRReg resultPayloadGPR
= resultPayload
.gpr();
3952 JITCompiler::Jump notCell
= m_jit
.branch32(JITCompiler::NotEqual
, baseTagGPR
, TrustedImm32(JSValue::CellTag
));
3954 cachedGetById(node
->codeOrigin
, baseTagGPR
, basePayloadGPR
, resultTagGPR
, resultPayloadGPR
, node
->identifierNumber(), notCell
, DontSpill
);
3956 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
, UseChildrenCalledExplicitly
);
3961 RELEASE_ASSERT_NOT_REACHED();
3967 case GetArrayLength
:
3968 compileGetArrayLength(node
);
3971 case CheckFunction
: {
3972 SpeculateCellOperand
function(this, node
->child1());
3973 speculationCheck(BadFunction
, JSValueSource::unboxedCell(function
.gpr()), node
->child1(), m_jit
.branchWeakPtr(JITCompiler::NotEqual
, function
.gpr(), node
->function()));
3978 case CheckExecutable
: {
3979 SpeculateCellOperand
function(this, node
->child1());
3980 speculationCheck(BadExecutable
, JSValueSource::unboxedCell(function
.gpr()), node
->child1(), m_jit
.branchWeakPtr(JITCompiler::NotEqual
, JITCompiler::Address(function
.gpr(), JSFunction::offsetOfExecutable()), node
->executable()));
3985 case CheckStructure
:
3986 case ForwardCheckStructure
: {
3987 SpeculateCellOperand
base(this, node
->child1());
3989 ASSERT(node
->structureSet().size());
3991 if (node
->structureSet().size() == 1) {
3993 BadCache
, JSValueSource::unboxedCell(base
.gpr()), 0,
3994 m_jit
.branchWeakPtr(
3995 JITCompiler::NotEqual
,
3996 JITCompiler::Address(base
.gpr(), JSCell::structureOffset()),
3997 node
->structureSet()[0]));
3999 GPRTemporary
structure(this);
4001 m_jit
.loadPtr(JITCompiler::Address(base
.gpr(), JSCell::structureOffset()), structure
.gpr());
4003 JITCompiler::JumpList done
;
4005 for (size_t i
= 0; i
< node
->structureSet().size() - 1; ++i
)
4006 done
.append(m_jit
.branchWeakPtr(JITCompiler::Equal
, structure
.gpr(), node
->structureSet()[i
]));
4009 BadCache
, JSValueSource::unboxedCell(base
.gpr()), 0,
4010 m_jit
.branchWeakPtr(
4011 JITCompiler::NotEqual
, structure
.gpr(), node
->structureSet().last()));
4020 case StructureTransitionWatchpoint
:
4021 case ForwardStructureTransitionWatchpoint
: {
4022 // There is a fascinating question here of what to do about array profiling.
4023 // We *could* try to tell the OSR exit about where the base of the access is.
4024 // The DFG will have kept it alive, though it may not be in a register, and
4025 // we shouldn't really load it since that could be a waste. For now though,
4026 // we'll just rely on the fact that when a watchpoint fires then that's
4027 // quite a hint already.
4029 m_jit
.addWeakReference(node
->structure());
4030 node
->structure()->addTransitionWatchpoint(
4031 speculationWatchpoint(
4032 node
->child1()->op() == WeakJSConstant
? BadWeakConstantCache
: BadCache
));
4034 #if !ASSERT_DISABLED
4035 SpeculateCellOperand
op1(this, node
->child1());
4036 JITCompiler::Jump isOK
= m_jit
.branchPtr(JITCompiler::Equal
, JITCompiler::Address(op1
.gpr(), JSCell::structureOffset()), TrustedImmPtr(node
->structure()));
4040 speculateCell(node
->child1());
4047 case PhantomPutStructure
: {
4048 ASSERT(isKnownCell(node
->child1().node()));
4049 ASSERT(node
->structureTransitionData().previousStructure
->transitionWatchpointSetHasBeenInvalidated());
4050 m_jit
.addWeakReferenceTransition(
4051 node
->codeOrigin
.codeOriginOwner(),
4052 node
->structureTransitionData().previousStructure
,
4053 node
->structureTransitionData().newStructure
);
4058 case PutStructure
: {
4059 ASSERT(node
->structureTransitionData().previousStructure
->transitionWatchpointSetHasBeenInvalidated());
4061 SpeculateCellOperand
base(this, node
->child1());
4062 GPRReg baseGPR
= base
.gpr();
4064 m_jit
.addWeakReferenceTransition(
4065 node
->codeOrigin
.codeOriginOwner(),
4066 node
->structureTransitionData().previousStructure
,
4067 node
->structureTransitionData().newStructure
);
4069 #if ENABLE(WRITE_BARRIER_PROFILING)
4070 // Must always emit this write barrier as the structure transition itself requires it
4071 writeBarrier(baseGPR
, node
->structureTransitionData().newStructure
, WriteBarrierForGenericAccess
);
4074 m_jit
.storePtr(MacroAssembler::TrustedImmPtr(node
->structureTransitionData().newStructure
), MacroAssembler::Address(baseGPR
, JSCell::structureOffset()));
4080 case AllocatePropertyStorage
:
4081 compileAllocatePropertyStorage(node
);
4084 case ReallocatePropertyStorage
:
4085 compileReallocatePropertyStorage(node
);
4088 case GetButterfly
: {
4089 SpeculateCellOperand
base(this, node
->child1());
4090 GPRTemporary
result(this, base
);
4092 GPRReg baseGPR
= base
.gpr();
4093 GPRReg resultGPR
= result
.gpr();
4095 m_jit
.loadPtr(JITCompiler::Address(baseGPR
, JSObject::butterflyOffset()), resultGPR
);
4097 storageResult(resultGPR
, node
);
4101 case GetIndexedPropertyStorage
: {
4102 compileGetIndexedPropertyStorage(node
);
4107 StorageOperand
storage(this, node
->child1());
4108 GPRTemporary
resultTag(this, storage
);
4109 GPRTemporary
resultPayload(this);
4111 GPRReg storageGPR
= storage
.gpr();
4112 GPRReg resultTagGPR
= resultTag
.gpr();
4113 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4115 StorageAccessData
& storageAccessData
= m_jit
.graph().m_storageAccessData
[node
->storageAccessDataIndex()];
4117 m_jit
.load32(JITCompiler::Address(storageGPR
, storageAccessData
.offset
* sizeof(EncodedJSValue
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)), resultPayloadGPR
);
4118 m_jit
.load32(JITCompiler::Address(storageGPR
, storageAccessData
.offset
* sizeof(EncodedJSValue
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)), resultTagGPR
);
4120 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4125 #if ENABLE(WRITE_BARRIER_PROFILING)
4126 SpeculateCellOperand
base(this, node
->child2());
4128 StorageOperand
storage(this, node
->child1());
4129 JSValueOperand
value(this, node
->child3());
4131 GPRReg storageGPR
= storage
.gpr();
4132 GPRReg valueTagGPR
= value
.tagGPR();
4133 GPRReg valuePayloadGPR
= value
.payloadGPR();
4135 #if ENABLE(WRITE_BARRIER_PROFILING)
4136 writeBarrier(base
.gpr(), valueTagGPR
, node
->child3(), WriteBarrierForPropertyAccess
);
4139 StorageAccessData
& storageAccessData
= m_jit
.graph().m_storageAccessData
[node
->storageAccessDataIndex()];
4141 m_jit
.storePtr(valueTagGPR
, JITCompiler::Address(storageGPR
, storageAccessData
.offset
* sizeof(EncodedJSValue
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
4142 m_jit
.storePtr(valuePayloadGPR
, JITCompiler::Address(storageGPR
, storageAccessData
.offset
* sizeof(EncodedJSValue
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
4149 SpeculateCellOperand
base(this, node
->child1());
4150 JSValueOperand
value(this, node
->child2());
4151 GPRTemporary
scratch(this);
4153 GPRReg baseGPR
= base
.gpr();
4154 GPRReg valueTagGPR
= value
.tagGPR();
4155 GPRReg valuePayloadGPR
= value
.payloadGPR();
4156 GPRReg scratchGPR
= scratch
.gpr();
4161 cachedPutById(node
->codeOrigin
, baseGPR
, valueTagGPR
, valuePayloadGPR
, node
->child2(), scratchGPR
, node
->identifierNumber(), NotDirect
);
4163 noResult(node
, UseChildrenCalledExplicitly
);
4167 case PutByIdDirect
: {
4168 SpeculateCellOperand
base(this, node
->child1());
4169 JSValueOperand
value(this, node
->child2());
4170 GPRTemporary
scratch(this);
4172 GPRReg baseGPR
= base
.gpr();
4173 GPRReg valueTagGPR
= value
.tagGPR();
4174 GPRReg valuePayloadGPR
= value
.payloadGPR();
4175 GPRReg scratchGPR
= scratch
.gpr();
4180 cachedPutById(node
->codeOrigin
, baseGPR
, valueTagGPR
, valuePayloadGPR
, node
->child2(), scratchGPR
, node
->identifierNumber(), Direct
);
4182 noResult(node
, UseChildrenCalledExplicitly
);
4186 case GetGlobalVar
: {
4187 GPRTemporary
resultPayload(this);
4188 GPRTemporary
resultTag(this);
4190 m_jit
.move(TrustedImmPtr(node
->registerPointer()), resultPayload
.gpr());
4191 m_jit
.load32(JITCompiler::Address(resultPayload
.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)), resultTag
.gpr());
4192 m_jit
.load32(JITCompiler::Address(resultPayload
.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)), resultPayload
.gpr());
4194 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
4198 case PutGlobalVar
: {
4199 JSValueOperand
value(this, node
->child1());
4200 if (Heap::isWriteBarrierEnabled()) {
4201 GPRTemporary
scratch(this);
4202 GPRReg scratchReg
= scratch
.gpr();
4204 writeBarrier(m_jit
.globalObjectFor(node
->codeOrigin
), value
.tagGPR(), node
->child1(), WriteBarrierForVariableAccess
, scratchReg
);
4207 // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have
4208 // a spare register - a good optimization would be to put the register pointer into
4209 // a register and then do a zero offset store followed by a four-offset store (or
4210 // vice-versa depending on endianness).
4211 m_jit
.store32(value
.tagGPR(), node
->registerPointer()->tagPointer());
4212 m_jit
.store32(value
.payloadGPR(), node
->registerPointer()->payloadPointer());
4218 case PutGlobalVarCheck
: {
4219 JSValueOperand
value(this, node
->child1());
4221 WatchpointSet
* watchpointSet
=
4222 m_jit
.globalObjectFor(node
->codeOrigin
)->symbolTable()->get(
4223 identifier(node
->identifierNumberForCheck())->impl()).watchpointSet();
4224 addSlowPathGenerator(
4227 JITCompiler::NonZero
,
4228 JITCompiler::AbsoluteAddress(watchpointSet
->addressOfIsWatched())),
4229 this, operationNotifyGlobalVarWrite
, NoResult
, watchpointSet
));
4231 if (Heap::isWriteBarrierEnabled()) {
4232 GPRTemporary
scratch(this);
4233 GPRReg scratchReg
= scratch
.gpr();
4235 writeBarrier(m_jit
.globalObjectFor(node
->codeOrigin
), value
.tagGPR(), node
->child1(), WriteBarrierForVariableAccess
, scratchReg
);
4238 // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have
4239 // a spare register - a good optimization would be to put the register pointer into
4240 // a register and then do a zero offset store followed by a four-offset store (or
4241 // vice-versa depending on endianness).
4242 m_jit
.store32(value
.tagGPR(), node
->registerPointer()->tagPointer());
4243 m_jit
.store32(value
.payloadGPR(), node
->registerPointer()->payloadPointer());
4249 case GlobalVarWatchpoint
: {
4250 m_jit
.globalObjectFor(node
->codeOrigin
)->symbolTable()->get(
4251 identifier(node
->identifierNumberForCheck())->impl()).addWatchpoint(
4252 speculationWatchpoint());
4254 #if DFG_ENABLE(JIT_ASSERT)
4255 GPRTemporary
scratch(this);
4256 GPRReg scratchGPR
= scratch
.gpr();
4257 m_jit
.load32(node
->registerPointer()->tagPointer(), scratchGPR
);
4258 JITCompiler::Jump notOK
= m_jit
.branch32(
4259 JITCompiler::NotEqual
, scratchGPR
,
4260 TrustedImm32(node
->registerPointer()->get().tag()));
4261 m_jit
.load32(node
->registerPointer()->payloadPointer(), scratchGPR
);
4262 JITCompiler::Jump ok
= m_jit
.branch32(
4263 JITCompiler::Equal
, scratchGPR
,
4264 TrustedImm32(node
->registerPointer()->get().payload()));
4274 case CheckHasInstance
: {
4275 SpeculateCellOperand
base(this, node
->child1());
4276 GPRTemporary
structure(this);
4278 // Speculate that base 'ImplementsDefaultHasInstance'.
4279 m_jit
.loadPtr(MacroAssembler::Address(base
.gpr(), JSCell::structureOffset()), structure
.gpr());
4280 speculationCheck(Uncountable
, JSValueRegs(), 0, m_jit
.branchTest8(MacroAssembler::Zero
, MacroAssembler::Address(structure
.gpr(), Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance
)));
4287 compileInstanceOf(node
);
4292 JSValueOperand
value(this, node
->child1());
4293 GPRTemporary
result(this);
4294 GPRTemporary
localGlobalObject(this);
4295 GPRTemporary
remoteGlobalObject(this);
4297 JITCompiler::Jump isCell
= m_jit
.branch32(JITCompiler::Equal
, value
.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag
));
4299 m_jit
.compare32(JITCompiler::Equal
, value
.tagGPR(), TrustedImm32(JSValue::UndefinedTag
), result
.gpr());
4300 JITCompiler::Jump done
= m_jit
.jump();
4302 isCell
.link(&m_jit
);
4303 JITCompiler::Jump notMasqueradesAsUndefined
;
4304 if (m_jit
.graph().globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
4305 m_jit
.graph().globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
4306 m_jit
.move(TrustedImm32(0), result
.gpr());
4307 notMasqueradesAsUndefined
= m_jit
.jump();
4309 m_jit
.loadPtr(JITCompiler::Address(value
.payloadGPR(), JSCell::structureOffset()), result
.gpr());
4310 JITCompiler::Jump isMasqueradesAsUndefined
= m_jit
.branchTest8(JITCompiler::NonZero
, JITCompiler::Address(result
.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined
));
4311 m_jit
.move(TrustedImm32(0), result
.gpr());
4312 notMasqueradesAsUndefined
= m_jit
.jump();
4314 isMasqueradesAsUndefined
.link(&m_jit
);
4315 GPRReg localGlobalObjectGPR
= localGlobalObject
.gpr();
4316 GPRReg remoteGlobalObjectGPR
= remoteGlobalObject
.gpr();
4317 m_jit
.move(TrustedImmPtr(m_jit
.globalObjectFor(node
->codeOrigin
)), localGlobalObjectGPR
);
4318 m_jit
.loadPtr(JITCompiler::Address(result
.gpr(), Structure::globalObjectOffset()), remoteGlobalObjectGPR
);
4319 m_jit
.compare32(JITCompiler::Equal
, localGlobalObjectGPR
, remoteGlobalObjectGPR
, result
.gpr());
4322 notMasqueradesAsUndefined
.link(&m_jit
);
4324 booleanResult(result
.gpr(), node
);
4329 JSValueOperand
value(this, node
->child1());
4330 GPRTemporary
result(this, value
);
4332 m_jit
.compare32(JITCompiler::Equal
, value
.tagGPR(), JITCompiler::TrustedImm32(JSValue::BooleanTag
), result
.gpr());
4333 booleanResult(result
.gpr(), node
);
4338 JSValueOperand
value(this, node
->child1());
4339 GPRTemporary
result(this, value
);
4341 m_jit
.add32(TrustedImm32(1), value
.tagGPR(), result
.gpr());
4342 m_jit
.compare32(JITCompiler::Below
, result
.gpr(), JITCompiler::TrustedImm32(JSValue::LowestTag
+ 1), result
.gpr());
4343 booleanResult(result
.gpr(), node
);
4348 JSValueOperand
value(this, node
->child1());
4349 GPRTemporary
result(this, value
);
4351 JITCompiler::Jump isNotCell
= m_jit
.branch32(JITCompiler::NotEqual
, value
.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag
));
4353 m_jit
.loadPtr(JITCompiler::Address(value
.payloadGPR(), JSCell::structureOffset()), result
.gpr());
4354 m_jit
.compare8(JITCompiler::Equal
, JITCompiler::Address(result
.gpr(), Structure::typeInfoTypeOffset()), TrustedImm32(StringType
), result
.gpr());
4355 JITCompiler::Jump done
= m_jit
.jump();
4357 isNotCell
.link(&m_jit
);
4358 m_jit
.move(TrustedImm32(0), result
.gpr());
4361 booleanResult(result
.gpr(), node
);
4366 JSValueOperand
value(this, node
->child1());
4367 GPRReg valueTagGPR
= value
.tagGPR();
4368 GPRReg valuePayloadGPR
= value
.payloadGPR();
4369 GPRResult
result(this);
4370 GPRReg resultGPR
= result
.gpr();
4372 callOperation(operationIsObject
, resultGPR
, valueTagGPR
, valuePayloadGPR
);
4373 booleanResult(result
.gpr(), node
);
4378 JSValueOperand
value(this, node
->child1());
4379 GPRReg valueTagGPR
= value
.tagGPR();
4380 GPRReg valuePayloadGPR
= value
.payloadGPR();
4381 GPRResult
result(this);
4382 GPRReg resultGPR
= result
.gpr();
4384 callOperation(operationIsFunction
, resultGPR
, valueTagGPR
, valuePayloadGPR
);
4385 booleanResult(result
.gpr(), node
);
4389 JSValueOperand
value(this, node
->child1(), ManualOperandSpeculation
);
4390 GPRReg tagGPR
= value
.tagGPR();
4391 GPRReg payloadGPR
= value
.payloadGPR();
4392 GPRTemporary
temp(this);
4393 GPRReg tempGPR
= temp
.gpr();
4394 GPRResult
result(this);
4395 GPRReg resultGPR
= result
.gpr();
4396 JITCompiler::JumpList doneJumps
;
4400 ASSERT(node
->child1().useKind() == UntypedUse
|| node
->child1().useKind() == CellUse
|| node
->child1().useKind() == StringUse
);
4402 JITCompiler::Jump isNotCell
= m_jit
.branch32(JITCompiler::NotEqual
, tagGPR
, JITCompiler::TrustedImm32(JSValue::CellTag
));
4403 if (node
->child1().useKind() != UntypedUse
)
4404 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), node
->child1(), isNotCell
);
4406 if (!node
->child1()->shouldSpeculateObject() || node
->child1().useKind() == StringUse
) {
4407 m_jit
.loadPtr(JITCompiler::Address(payloadGPR
, JSCell::structureOffset()), tempGPR
);
4408 JITCompiler::Jump notString
= m_jit
.branch8(JITCompiler::NotEqual
, JITCompiler::Address(tempGPR
, Structure::typeInfoTypeOffset()), TrustedImm32(StringType
));
4409 if (node
->child1().useKind() == StringUse
)
4410 DFG_TYPE_CHECK(JSValueRegs(tagGPR
, payloadGPR
), node
->child1(), SpecString
, notString
);
4411 m_jit
.move(TrustedImmPtr(m_jit
.vm()->smallStrings
.stringString()), resultGPR
);
4412 doneJumps
.append(m_jit
.jump());
4413 if (node
->child1().useKind() != StringUse
) {
4414 notString
.link(&m_jit
);
4415 callOperation(operationTypeOf
, resultGPR
, payloadGPR
);
4416 doneJumps
.append(m_jit
.jump());
4419 callOperation(operationTypeOf
, resultGPR
, payloadGPR
);
4420 doneJumps
.append(m_jit
.jump());
4423 if (node
->child1().useKind() == UntypedUse
) {
4424 isNotCell
.link(&m_jit
);
4426 m_jit
.add32(TrustedImm32(1), tagGPR
, tempGPR
);
4427 JITCompiler::Jump notNumber
= m_jit
.branch32(JITCompiler::AboveOrEqual
, tempGPR
, JITCompiler::TrustedImm32(JSValue::LowestTag
+ 1));
4428 m_jit
.move(TrustedImmPtr(m_jit
.vm()->smallStrings
.numberString()), resultGPR
);
4429 doneJumps
.append(m_jit
.jump());
4430 notNumber
.link(&m_jit
);
4432 JITCompiler::Jump notUndefined
= m_jit
.branch32(JITCompiler::NotEqual
, tagGPR
, TrustedImm32(JSValue::UndefinedTag
));
4433 m_jit
.move(TrustedImmPtr(m_jit
.vm()->smallStrings
.undefinedString()), resultGPR
);
4434 doneJumps
.append(m_jit
.jump());
4435 notUndefined
.link(&m_jit
);
4437 JITCompiler::Jump notNull
= m_jit
.branch32(JITCompiler::NotEqual
, tagGPR
, TrustedImm32(JSValue::NullTag
));
4438 m_jit
.move(TrustedImmPtr(m_jit
.vm()->smallStrings
.objectString()), resultGPR
);
4439 doneJumps
.append(m_jit
.jump());
4440 notNull
.link(&m_jit
);
4442 // Only boolean left
4443 m_jit
.move(TrustedImmPtr(m_jit
.vm()->smallStrings
.booleanString()), resultGPR
);
4445 doneJumps
.link(&m_jit
);
4446 cellResult(resultGPR
, node
);
4455 #if ENABLE(DEBUG_WITH_BREAKPOINT)
4458 RELEASE_ASSERT_NOT_REACHED();
4469 GPRResult
resultPayload(this);
4470 GPRResult2
resultTag(this);
4471 ResolveOperationData
& data
= m_jit
.graph().m_resolveOperationsData
[node
->resolveOperationsDataIndex()];
4472 callOperation(operationResolve
, resultTag
.gpr(), resultPayload
.gpr(), identifier(data
.identifierNumber
), data
.resolveOperations
);
4473 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
4479 GPRResult
resultPayload(this);
4480 GPRResult2
resultTag(this);
4481 ResolveOperationData
& data
= m_jit
.graph().m_resolveOperationsData
[node
->resolveOperationsDataIndex()];
4482 callOperation(operationResolveBase
, resultTag
.gpr(), resultPayload
.gpr(), identifier(data
.identifierNumber
), data
.resolveOperations
, data
.putToBaseOperation
);
4483 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
4487 case ResolveBaseStrictPut
: {
4489 GPRResult
resultPayload(this);
4490 GPRResult2
resultTag(this);
4491 ResolveOperationData
& data
= m_jit
.graph().m_resolveOperationsData
[node
->resolveOperationsDataIndex()];
4492 callOperation(operationResolveBaseStrictPut
, resultTag
.gpr(), resultPayload
.gpr(), identifier(data
.identifierNumber
), data
.resolveOperations
, data
.putToBaseOperation
);
4493 jsValueResult(resultTag
.gpr(), resultPayload
.gpr(), node
);
4497 case ResolveGlobal
: {
4498 GPRTemporary
globalObject(this);
4499 GPRTemporary
resolveInfo(this);
4500 GPRTemporary
resultTag(this);
4501 GPRTemporary
resultPayload(this);
4503 GPRReg globalObjectGPR
= globalObject
.gpr();
4504 GPRReg resolveInfoGPR
= resolveInfo
.gpr();
4505 GPRReg resultTagGPR
= resultTag
.gpr();
4506 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4508 ResolveGlobalData
& data
= m_jit
.graph().m_resolveGlobalData
[node
->resolveGlobalDataIndex()];
4509 ResolveOperation
* resolveOperationAddress
= &(data
.resolveOperations
->data()[data
.resolvePropertyIndex
]);
4511 // Check Structure of global object
4512 m_jit
.move(JITCompiler::TrustedImmPtr(m_jit
.globalObjectFor(node
->codeOrigin
)), globalObjectGPR
);
4513 m_jit
.move(JITCompiler::TrustedImmPtr(resolveOperationAddress
), resolveInfoGPR
);
4514 m_jit
.loadPtr(JITCompiler::Address(resolveInfoGPR
, OBJECT_OFFSETOF(ResolveOperation
, m_structure
)), resultPayloadGPR
);
4516 JITCompiler::Jump structuresNotMatch
= m_jit
.branchPtr(JITCompiler::NotEqual
, resultPayloadGPR
, JITCompiler::Address(globalObjectGPR
, JSCell::structureOffset()));
4519 m_jit
.loadPtr(JITCompiler::Address(globalObjectGPR
, JSObject::butterflyOffset()), resultPayloadGPR
);
4520 m_jit
.load32(JITCompiler::Address(resolveInfoGPR
, OBJECT_OFFSETOF(ResolveOperation
, m_offset
)), resolveInfoGPR
);
4521 #if DFG_ENABLE(JIT_ASSERT)
4522 JITCompiler::Jump isOutOfLine
= m_jit
.branch32(JITCompiler::GreaterThanOrEqual
, resolveInfoGPR
, TrustedImm32(firstOutOfLineOffset
));
4524 isOutOfLine
.link(&m_jit
);
4526 m_jit
.neg32(resolveInfoGPR
);
4527 m_jit
.signExtend32ToPtr(resolveInfoGPR
, resolveInfoGPR
);
4528 m_jit
.load32(JITCompiler::BaseIndex(resultPayloadGPR
, resolveInfoGPR
, JITCompiler::TimesEight
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
) + (firstOutOfLineOffset
- 2) * static_cast<ptrdiff_t>(sizeof(JSValue
))), resultTagGPR
);
4529 m_jit
.load32(JITCompiler::BaseIndex(resultPayloadGPR
, resolveInfoGPR
, JITCompiler::TimesEight
, OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
) + (firstOutOfLineOffset
- 2) * static_cast<ptrdiff_t>(sizeof(JSValue
))), resultPayloadGPR
);
4531 addSlowPathGenerator(
4533 structuresNotMatch
, this, operationResolveGlobal
,
4534 JSValueRegs(resultTagGPR
, resultPayloadGPR
), resolveInfoGPR
, globalObjectGPR
,
4535 &m_jit
.codeBlock()->identifier(data
.identifierNumber
)));
4537 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4541 case CreateActivation
: {
4542 JSValueOperand
value(this, node
->child1());
4543 GPRTemporary
result(this, value
, false);
4545 GPRReg valueTagGPR
= value
.tagGPR();
4546 GPRReg valuePayloadGPR
= value
.payloadGPR();
4547 GPRReg resultGPR
= result
.gpr();
4549 m_jit
.move(valuePayloadGPR
, resultGPR
);
4551 JITCompiler::Jump notCreated
= m_jit
.branch32(JITCompiler::Equal
, valueTagGPR
, TrustedImm32(JSValue::EmptyValueTag
));
4553 addSlowPathGenerator(
4554 slowPathCall(notCreated
, this, operationCreateActivation
, resultGPR
));
4556 cellResult(resultGPR
, node
);
4560 case CreateArguments
: {
4561 JSValueOperand
value(this, node
->child1());
4562 GPRTemporary
result(this, value
, false);
4564 GPRReg valueTagGPR
= value
.tagGPR();
4565 GPRReg valuePayloadGPR
= value
.payloadGPR();
4566 GPRReg resultGPR
= result
.gpr();
4568 m_jit
.move(valuePayloadGPR
, resultGPR
);
4570 JITCompiler::Jump notCreated
= m_jit
.branch32(JITCompiler::Equal
, valueTagGPR
, TrustedImm32(JSValue::EmptyValueTag
));
4572 if (node
->codeOrigin
.inlineCallFrame
) {
4573 addSlowPathGenerator(
4575 notCreated
, this, operationCreateInlinedArguments
, resultGPR
,
4576 node
->codeOrigin
.inlineCallFrame
));
4578 addSlowPathGenerator(
4579 slowPathCall(notCreated
, this, operationCreateArguments
, resultGPR
));
4582 cellResult(resultGPR
, node
);
4586 case TearOffActivation
: {
4587 JSValueOperand
activationValue(this, node
->child1());
4588 GPRTemporary
scratch(this);
4590 GPRReg activationValueTagGPR
= activationValue
.tagGPR();
4591 GPRReg activationValuePayloadGPR
= activationValue
.payloadGPR();
4592 GPRReg scratchGPR
= scratch
.gpr();
4594 JITCompiler::Jump notCreated
= m_jit
.branch32(JITCompiler::Equal
, activationValueTagGPR
, TrustedImm32(JSValue::EmptyValueTag
));
4596 SharedSymbolTable
* symbolTable
= m_jit
.symbolTableFor(node
->codeOrigin
);
4597 int registersOffset
= JSActivation::registersOffset(symbolTable
);
4599 int captureEnd
= symbolTable
->captureEnd();
4600 for (int i
= symbolTable
->captureStart(); i
< captureEnd
; ++i
) {
4602 JITCompiler::Address(
4603 GPRInfo::callFrameRegister
, i
* sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)),
4606 scratchGPR
, JITCompiler::Address(
4607 activationValuePayloadGPR
, registersOffset
+ i
* sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
4609 JITCompiler::Address(
4610 GPRInfo::callFrameRegister
, i
* sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)),
4613 scratchGPR
, JITCompiler::Address(
4614 activationValuePayloadGPR
, registersOffset
+ i
* sizeof(Register
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
4616 m_jit
.addPtr(TrustedImm32(registersOffset
), activationValuePayloadGPR
, scratchGPR
);
4617 m_jit
.storePtr(scratchGPR
, JITCompiler::Address(activationValuePayloadGPR
, JSActivation::offsetOfRegisters()));
4619 notCreated
.link(&m_jit
);
4624 case TearOffArguments
: {
4625 JSValueOperand
unmodifiedArgumentsValue(this, node
->child1());
4626 JSValueOperand
activationValue(this, node
->child2());
4627 GPRReg unmodifiedArgumentsValuePayloadGPR
= unmodifiedArgumentsValue
.payloadGPR();
4628 GPRReg activationValuePayloadGPR
= activationValue
.payloadGPR();
4630 JITCompiler::Jump created
= m_jit
.branchTest32(
4631 JITCompiler::NonZero
, unmodifiedArgumentsValuePayloadGPR
);
4633 if (node
->codeOrigin
.inlineCallFrame
) {
4634 addSlowPathGenerator(
4636 created
, this, operationTearOffInlinedArguments
, NoResult
,
4637 unmodifiedArgumentsValuePayloadGPR
, activationValuePayloadGPR
, node
->codeOrigin
.inlineCallFrame
));
4639 addSlowPathGenerator(
4641 created
, this, operationTearOffArguments
, NoResult
,
4642 unmodifiedArgumentsValuePayloadGPR
, activationValuePayloadGPR
));
4649 case CheckArgumentsNotCreated
: {
4650 ASSERT(!isEmptySpeculation(
4651 m_state
.variables().operand(
4652 m_jit
.graph().argumentsRegisterFor(node
->codeOrigin
)).m_type
));
4654 Uncountable
, JSValueRegs(), 0,
4656 JITCompiler::NotEqual
,
4657 JITCompiler::tagFor(m_jit
.argumentsRegisterFor(node
->codeOrigin
)),
4658 TrustedImm32(JSValue::EmptyValueTag
)));
4663 case GetMyArgumentsLength
: {
4664 GPRTemporary
result(this);
4665 GPRReg resultGPR
= result
.gpr();
4667 if (!isEmptySpeculation(
4668 m_state
.variables().operand(
4669 m_jit
.graph().argumentsRegisterFor(node
->codeOrigin
)).m_type
)) {
4671 ArgumentsEscaped
, JSValueRegs(), 0,
4673 JITCompiler::NotEqual
,
4674 JITCompiler::tagFor(m_jit
.argumentsRegisterFor(node
->codeOrigin
)),
4675 TrustedImm32(JSValue::EmptyValueTag
)));
4678 ASSERT(!node
->codeOrigin
.inlineCallFrame
);
4679 m_jit
.load32(JITCompiler::payloadFor(JSStack::ArgumentCount
), resultGPR
);
4680 m_jit
.sub32(TrustedImm32(1), resultGPR
);
4681 integerResult(resultGPR
, node
);
4685 case GetMyArgumentsLengthSafe
: {
4686 GPRTemporary
resultPayload(this);
4687 GPRTemporary
resultTag(this);
4688 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4689 GPRReg resultTagGPR
= resultTag
.gpr();
4691 JITCompiler::Jump created
= m_jit
.branch32(
4692 JITCompiler::NotEqual
,
4693 JITCompiler::tagFor(m_jit
.argumentsRegisterFor(node
->codeOrigin
)),
4694 TrustedImm32(JSValue::EmptyValueTag
));
4696 if (node
->codeOrigin
.inlineCallFrame
) {
4698 Imm32(node
->codeOrigin
.inlineCallFrame
->arguments
.size() - 1),
4701 m_jit
.load32(JITCompiler::payloadFor(JSStack::ArgumentCount
), resultPayloadGPR
);
4702 m_jit
.sub32(TrustedImm32(1), resultPayloadGPR
);
4704 m_jit
.move(TrustedImm32(JSValue::Int32Tag
), resultTagGPR
);
4706 // FIXME: the slow path generator should perform a forward speculation that the
4707 // result is an integer. For now we postpone the speculation by having this return
4710 addSlowPathGenerator(
4712 created
, this, operationGetArgumentsLength
,
4713 JSValueRegs(resultTagGPR
, resultPayloadGPR
),
4714 m_jit
.argumentsRegisterFor(node
->codeOrigin
)));
4716 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4720 case GetMyArgumentByVal
: {
4721 SpeculateStrictInt32Operand
index(this, node
->child1());
4722 GPRTemporary
resultPayload(this);
4723 GPRTemporary
resultTag(this);
4724 GPRReg indexGPR
= index
.gpr();
4725 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4726 GPRReg resultTagGPR
= resultTag
.gpr();
4728 if (!isEmptySpeculation(
4729 m_state
.variables().operand(
4730 m_jit
.graph().argumentsRegisterFor(node
->codeOrigin
)).m_type
)) {
4732 ArgumentsEscaped
, JSValueRegs(), 0,
4734 JITCompiler::NotEqual
,
4735 JITCompiler::tagFor(m_jit
.argumentsRegisterFor(node
->codeOrigin
)),
4736 TrustedImm32(JSValue::EmptyValueTag
)));
4739 m_jit
.add32(TrustedImm32(1), indexGPR
, resultPayloadGPR
);
4741 if (node
->codeOrigin
.inlineCallFrame
) {
4743 Uncountable
, JSValueRegs(), 0,
4745 JITCompiler::AboveOrEqual
,
4747 Imm32(node
->codeOrigin
.inlineCallFrame
->arguments
.size())));
4750 Uncountable
, JSValueRegs(), 0,
4752 JITCompiler::AboveOrEqual
,
4754 JITCompiler::payloadFor(JSStack::ArgumentCount
)));
4757 JITCompiler::JumpList slowArgument
;
4758 JITCompiler::JumpList slowArgumentOutOfBounds
;
4759 if (const SlowArgument
* slowArguments
= m_jit
.symbolTableFor(node
->codeOrigin
)->slowArguments()) {
4760 slowArgumentOutOfBounds
.append(
4762 JITCompiler::AboveOrEqual
, indexGPR
,
4763 Imm32(m_jit
.symbolTableFor(node
->codeOrigin
)->parameterCount())));
4765 COMPILE_ASSERT(sizeof(SlowArgument
) == 8, SlowArgument_size_is_eight_bytes
);
4766 m_jit
.move(ImmPtr(slowArguments
), resultPayloadGPR
);
4768 JITCompiler::BaseIndex(
4769 resultPayloadGPR
, indexGPR
, JITCompiler::TimesEight
,
4770 OBJECT_OFFSETOF(SlowArgument
, index
)),
4774 JITCompiler::BaseIndex(
4775 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4776 m_jit
.offsetOfLocals(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)),
4779 JITCompiler::BaseIndex(
4780 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4781 m_jit
.offsetOfLocals(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)),
4783 slowArgument
.append(m_jit
.jump());
4785 slowArgumentOutOfBounds
.link(&m_jit
);
4787 m_jit
.neg32(resultPayloadGPR
);
4790 JITCompiler::BaseIndex(
4791 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4792 m_jit
.offsetOfArgumentsIncludingThis(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)),
4795 JITCompiler::BaseIndex(
4796 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4797 m_jit
.offsetOfArgumentsIncludingThis(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)),
4800 slowArgument
.link(&m_jit
);
4801 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4804 case GetMyArgumentByValSafe
: {
4805 SpeculateStrictInt32Operand
index(this, node
->child1());
4806 GPRTemporary
resultPayload(this);
4807 GPRTemporary
resultTag(this);
4808 GPRReg indexGPR
= index
.gpr();
4809 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4810 GPRReg resultTagGPR
= resultTag
.gpr();
4812 JITCompiler::JumpList slowPath
;
4815 JITCompiler::NotEqual
,
4816 JITCompiler::tagFor(m_jit
.argumentsRegisterFor(node
->codeOrigin
)),
4817 TrustedImm32(JSValue::EmptyValueTag
)));
4819 m_jit
.add32(TrustedImm32(1), indexGPR
, resultPayloadGPR
);
4820 if (node
->codeOrigin
.inlineCallFrame
) {
4823 JITCompiler::AboveOrEqual
,
4825 Imm32(node
->codeOrigin
.inlineCallFrame
->arguments
.size())));
4829 JITCompiler::AboveOrEqual
,
4831 JITCompiler::payloadFor(JSStack::ArgumentCount
)));
4834 JITCompiler::JumpList slowArgument
;
4835 JITCompiler::JumpList slowArgumentOutOfBounds
;
4836 if (const SlowArgument
* slowArguments
= m_jit
.symbolTableFor(node
->codeOrigin
)->slowArguments()) {
4837 slowArgumentOutOfBounds
.append(
4839 JITCompiler::AboveOrEqual
, indexGPR
,
4840 Imm32(m_jit
.symbolTableFor(node
->codeOrigin
)->parameterCount())));
4842 COMPILE_ASSERT(sizeof(SlowArgument
) == 8, SlowArgument_size_is_eight_bytes
);
4843 m_jit
.move(ImmPtr(slowArguments
), resultPayloadGPR
);
4845 JITCompiler::BaseIndex(
4846 resultPayloadGPR
, indexGPR
, JITCompiler::TimesEight
,
4847 OBJECT_OFFSETOF(SlowArgument
, index
)),
4850 JITCompiler::BaseIndex(
4851 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4852 m_jit
.offsetOfLocals(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)),
4855 JITCompiler::BaseIndex(
4856 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4857 m_jit
.offsetOfLocals(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)),
4859 slowArgument
.append(m_jit
.jump());
4861 slowArgumentOutOfBounds
.link(&m_jit
);
4863 m_jit
.neg32(resultPayloadGPR
);
4866 JITCompiler::BaseIndex(
4867 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4868 m_jit
.offsetOfArgumentsIncludingThis(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)),
4871 JITCompiler::BaseIndex(
4872 GPRInfo::callFrameRegister
, resultPayloadGPR
, JITCompiler::TimesEight
,
4873 m_jit
.offsetOfArgumentsIncludingThis(node
->codeOrigin
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)),
4876 if (node
->codeOrigin
.inlineCallFrame
) {
4877 addSlowPathGenerator(
4879 slowPath
, this, operationGetInlinedArgumentByVal
,
4880 JSValueRegs(resultTagGPR
, resultPayloadGPR
),
4881 m_jit
.argumentsRegisterFor(node
->codeOrigin
),
4882 node
->codeOrigin
.inlineCallFrame
, indexGPR
));
4884 addSlowPathGenerator(
4886 slowPath
, this, operationGetArgumentByVal
,
4887 JSValueRegs(resultTagGPR
, resultPayloadGPR
),
4888 m_jit
.argumentsRegisterFor(node
->codeOrigin
), indexGPR
));
4891 slowArgument
.link(&m_jit
);
4892 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4896 case NewFunctionNoCheck
:
4897 compileNewFunctionNoCheck(node
);
4901 JSValueOperand
value(this, node
->child1());
4902 GPRTemporary
resultTag(this, value
);
4903 GPRTemporary
resultPayload(this, value
, false);
4905 GPRReg valueTagGPR
= value
.tagGPR();
4906 GPRReg valuePayloadGPR
= value
.payloadGPR();
4907 GPRReg resultTagGPR
= resultTag
.gpr();
4908 GPRReg resultPayloadGPR
= resultPayload
.gpr();
4910 m_jit
.move(valuePayloadGPR
, resultPayloadGPR
);
4911 m_jit
.move(valueTagGPR
, resultTagGPR
);
4913 JITCompiler::Jump notCreated
= m_jit
.branch32(JITCompiler::Equal
, valueTagGPR
, TrustedImm32(JSValue::EmptyValueTag
));
4915 addSlowPathGenerator(
4917 notCreated
, this, operationNewFunction
, JSValueRegs(resultTagGPR
, resultPayloadGPR
),
4918 m_jit
.codeBlock()->functionDecl(node
->functionDeclIndex())));
4920 jsValueResult(resultTagGPR
, resultPayloadGPR
, node
);
4924 case NewFunctionExpression
:
4925 compileNewFunctionExpression(node
);
4929 // We should never get to the point of code emission for a GarbageValue
4933 case ForceOSRExit
: {
4934 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), 0);
4938 case CheckWatchdogTimer
:
4940 WatchdogTimerFired
, JSValueRegs(), 0,
4942 JITCompiler::NonZero
,
4943 JITCompiler::AbsoluteAddress(m_jit
.vm()->watchdog
.timerDidFireAddress())));
4946 case CountExecution
:
4947 m_jit
.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node
->executionCounter()->address()));
4951 DFG_NODE_DO_TO_CHILDREN(m_jit
.graph(), node
, speculate
);
4962 RELEASE_ASSERT_NOT_REACHED();
4966 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
4967 m_jit
.clearRegisterAllocationOffsets();
4973 if (node
->hasResult() && node
->mustGenerate())
4979 } } // namespace JSC::DFG