]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/JITPropertyAccess32_64.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / jit / JITPropertyAccess32_64.cpp
CommitLineData
4e4e5a6f 1/*
ed1e77d3 2 * Copyright (C) 2008, 2009, 2014, 2015 Apple Inc. All rights reserved.
4e4e5a6f
A
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
14957cd0 28#if ENABLE(JIT)
4e4e5a6f 29#if USE(JSVALUE32_64)
4e4e5a6f
A
30#include "JIT.h"
31
4e4e5a6f 32#include "CodeBlock.h"
ed1e77d3 33#include "DirectArguments.h"
93a37866
A
34#include "GCAwareJITStubRoutine.h"
35#include "Interpreter.h"
36#include "JITInlines.h"
4e4e5a6f 37#include "JSArray.h"
ed1e77d3 38#include "JSEnvironmentRecord.h"
4e4e5a6f 39#include "JSFunction.h"
4e4e5a6f
A
40#include "LinkBuffer.h"
41#include "RepatchBuffer.h"
42#include "ResultType.h"
43#include "SamplingTool.h"
93a37866 44#include <wtf/StringPrintStream.h>
4e4e5a6f 45
4e4e5a6f
A
46
47namespace JSC {
48
49void JIT::emit_op_put_by_index(Instruction* currentInstruction)
50{
81345200
A
51 int base = currentInstruction[1].u.operand;
52 int property = currentInstruction[2].u.operand;
53 int value = currentInstruction[3].u.operand;
54
55 emitLoad(base, regT1, regT0);
56 emitLoad(value, regT3, regT2);
57 callOperation(operationPutByIndex, regT1, regT0, property, regT3, regT2);
4e4e5a6f
A
58}
59
ed1e77d3
A
60void JIT::emit_op_put_getter_by_id(Instruction* currentInstruction)
61{
62 int base = currentInstruction[1].u.operand;
63 int property = currentInstruction[2].u.operand;
64 int getter = currentInstruction[3].u.operand;
65
66 emitLoadPayload(base, regT1);
67 emitLoadPayload(getter, regT3);
68 callOperation(operationPutGetterById, regT1, &m_codeBlock->identifier(property), regT3);
69}
70
71void JIT::emit_op_put_setter_by_id(Instruction* currentInstruction)
72{
73 int base = currentInstruction[1].u.operand;
74 int property = currentInstruction[2].u.operand;
75 int setter = currentInstruction[3].u.operand;
76
77 emitLoadPayload(base, regT1);
78 emitLoadPayload(setter, regT3);
79 callOperation(operationPutSetterById, regT1, &m_codeBlock->identifier(property), regT3);
80}
81
6fe7ccc8 82void JIT::emit_op_put_getter_setter(Instruction* currentInstruction)
4e4e5a6f 83{
81345200
A
84 int base = currentInstruction[1].u.operand;
85 int property = currentInstruction[2].u.operand;
86 int getter = currentInstruction[3].u.operand;
87 int setter = currentInstruction[4].u.operand;
88
89 emitLoadPayload(base, regT1);
90 emitLoadPayload(getter, regT3);
91 emitLoadPayload(setter, regT4);
92 callOperation(operationPutGetterSetter, regT1, &m_codeBlock->identifier(property), regT3, regT4);
4e4e5a6f
A
93}
94
95void JIT::emit_op_del_by_id(Instruction* currentInstruction)
96{
81345200
A
97 int dst = currentInstruction[1].u.operand;
98 int base = currentInstruction[2].u.operand;
99 int property = currentInstruction[3].u.operand;
100 emitLoad(base, regT1, regT0);
101 callOperation(operationDeleteById, dst, regT1, regT0, &m_codeBlock->identifier(property));
4e4e5a6f
A
102}
103
93a37866 104JIT::CodeRef JIT::stringGetByValStubGenerator(VM* vm)
4e4e5a6f 105{
81345200 106 JSInterfaceJIT jit(vm);
4e4e5a6f 107 JumpList failures;
81345200 108 failures.append(JSC::branchStructure(jit, NotEqual, Address(regT0, JSCell::structureIDOffset()), vm->stringStructure.get()));
4e4e5a6f
A
109
110 // Load string length to regT1, and start the process of loading the data pointer into regT0
111 jit.load32(Address(regT0, ThunkHelpers::jsStringLengthOffset()), regT1);
112 jit.loadPtr(Address(regT0, ThunkHelpers::jsStringValueOffset()), regT0);
6fe7ccc8 113 failures.append(jit.branchTest32(Zero, regT0));
4e4e5a6f
A
114
115 // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
116 failures.append(jit.branch32(AboveOrEqual, regT2, regT1));
117
118 // Load the character
6fe7ccc8
A
119 JumpList is16Bit;
120 JumpList cont8Bit;
121 // Load the string flags
93a37866
A
122 jit.loadPtr(Address(regT0, StringImpl::flagsOffset()), regT1);
123 jit.loadPtr(Address(regT0, StringImpl::dataOffset()), regT0);
124 is16Bit.append(jit.branchTest32(Zero, regT1, TrustedImm32(StringImpl::flagIs8Bit())));
6fe7ccc8
A
125 jit.load8(BaseIndex(regT0, regT2, TimesOne, 0), regT0);
126 cont8Bit.append(jit.jump());
127 is16Bit.link(&jit);
4e4e5a6f 128 jit.load16(BaseIndex(regT0, regT2, TimesTwo, 0), regT0);
6fe7ccc8
A
129
130 cont8Bit.link(&jit);
4e4e5a6f 131
14957cd0 132 failures.append(jit.branch32(AboveOrEqual, regT0, TrustedImm32(0x100)));
93a37866 133 jit.move(TrustedImmPtr(vm->smallStrings.singleCharacterStrings()), regT1);
4e4e5a6f 134 jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0);
14957cd0 135 jit.move(TrustedImm32(JSValue::CellTag), regT1); // We null check regT0 on return so this is safe
4e4e5a6f
A
136 jit.ret();
137
138 failures.link(&jit);
14957cd0 139 jit.move(TrustedImm32(0), regT0);
4e4e5a6f
A
140 jit.ret();
141
81345200 142 LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
93a37866 143 return FINALIZE_CODE(patchBuffer, ("String get_by_val stub"));
4e4e5a6f
A
144}
145
146void JIT::emit_op_get_by_val(Instruction* currentInstruction)
147{
81345200
A
148 int dst = currentInstruction[1].u.operand;
149 int base = currentInstruction[2].u.operand;
150 int property = currentInstruction[3].u.operand;
93a37866 151 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
4e4e5a6f
A
152
153 emitLoad2(base, regT1, regT0, property, regT3, regT2);
154
14957cd0 155 addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
4e4e5a6f 156 emitJumpSlowCaseIfNotJSCell(base, regT1);
81345200 157 emitArrayProfilingSiteWithCell(regT0, regT1, profile);
93a37866
A
158 and32(TrustedImm32(IndexingShapeMask), regT1);
159
160 PatchableJump badType;
161 JumpList slowCases;
162
163 JITArrayMode mode = chooseArrayMode(profile);
164 switch (mode) {
165 case JITInt32:
166 slowCases = emitInt32GetByVal(currentInstruction, badType);
167 break;
168 case JITDouble:
169 slowCases = emitDoubleGetByVal(currentInstruction, badType);
170 break;
171 case JITContiguous:
172 slowCases = emitContiguousGetByVal(currentInstruction, badType);
173 break;
174 case JITArrayStorage:
175 slowCases = emitArrayStorageGetByVal(currentInstruction, badType);
176 break;
177 default:
178 CRASH();
179 }
4e4e5a6f 180
93a37866
A
181 addSlowCase(badType);
182 addSlowCase(slowCases);
4e4e5a6f 183
93a37866
A
184 Label done = label();
185
81345200
A
186 if (!ASSERT_DISABLED) {
187 Jump resultOK = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag));
188 abortWithReason(JITGetByValResultIsNotEmpty);
189 resultOK.link(this);
190 }
93a37866 191
6fe7ccc8 192 emitValueProfilingSite();
4e4e5a6f 193 emitStore(dst, regT1, regT0);
93a37866
A
194
195 m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
196}
197
ed1e77d3 198JIT::JumpList JIT::emitContiguousLoad(Instruction*, PatchableJump& badType, IndexingType expectedShape)
93a37866
A
199{
200 JumpList slowCases;
201
202 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(expectedShape));
93a37866
A
203 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
204 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
93a37866
A
205 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
206 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
207 slowCases.append(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
208
209 return slowCases;
4e4e5a6f
A
210}
211
ed1e77d3 212JIT::JumpList JIT::emitDoubleLoad(Instruction*, PatchableJump& badType)
93a37866
A
213{
214 JumpList slowCases;
215
216 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(DoubleShape));
93a37866
A
217 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
218 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
93a37866
A
219 loadDouble(BaseIndex(regT3, regT2, TimesEight), fpRegT0);
220 slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
93a37866
A
221
222 return slowCases;
223}
224
ed1e77d3 225JIT::JumpList JIT::emitArrayStorageLoad(Instruction*, PatchableJump& badType)
93a37866
A
226{
227 JumpList slowCases;
228
229 add32(TrustedImm32(-ArrayStorageShape), regT1, regT3);
230 badType = patchableBranch32(Above, regT3, TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape));
93a37866
A
231 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
232 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset())));
93a37866
A
233 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
234 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
235 slowCases.append(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
236
237 return slowCases;
238}
239
4e4e5a6f
A
240void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
241{
81345200
A
242 int dst = currentInstruction[1].u.operand;
243 int base = currentInstruction[2].u.operand;
244 int property = currentInstruction[3].u.operand;
93a37866 245 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
4e4e5a6f
A
246
247 linkSlowCase(iter); // property int32 check
248 linkSlowCaseIfNotJSCell(iter, base); // base cell check
249
250 Jump nonCell = jump();
251 linkSlowCase(iter); // base array check
81345200 252 Jump notString = branchStructure(NotEqual, Address(regT0, JSCell::structureIDOffset()), m_vm->stringStructure.get());
93a37866 253 emitNakedCall(m_vm->getCTIStub(stringGetByValStubGenerator).code());
4e4e5a6f
A
254 Jump failed = branchTestPtr(Zero, regT0);
255 emitStore(dst, regT1, regT0);
256 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
257 failed.link(this);
258 notString.link(this);
259 nonCell.link(this);
260
261 linkSlowCase(iter); // vector length check
262 linkSlowCase(iter); // empty value
263
93a37866
A
264 Label slowPath = label();
265
81345200
A
266 emitLoad(base, regT1, regT0);
267 emitLoad(property, regT3, regT2);
ed1e77d3 268 Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2, profile);
93a37866
A
269
270 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
271 m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
272 m_byValInstructionIndex++;
6fe7ccc8
A
273
274 emitValueProfilingSite();
4e4e5a6f
A
275}
276
277void JIT::emit_op_put_by_val(Instruction* currentInstruction)
278{
81345200
A
279 int base = currentInstruction[1].u.operand;
280 int property = currentInstruction[2].u.operand;
93a37866 281 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
4e4e5a6f
A
282
283 emitLoad2(base, regT1, regT0, property, regT3, regT2);
284
14957cd0 285 addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
4e4e5a6f 286 emitJumpSlowCaseIfNotJSCell(base, regT1);
81345200 287 emitArrayProfilingSiteWithCell(regT0, regT1, profile);
93a37866
A
288 and32(TrustedImm32(IndexingShapeMask), regT1);
289
290 PatchableJump badType;
291 JumpList slowCases;
292
293 JITArrayMode mode = chooseArrayMode(profile);
294 switch (mode) {
295 case JITInt32:
296 slowCases = emitInt32PutByVal(currentInstruction, badType);
297 break;
298 case JITDouble:
299 slowCases = emitDoublePutByVal(currentInstruction, badType);
300 break;
301 case JITContiguous:
302 slowCases = emitContiguousPutByVal(currentInstruction, badType);
303 break;
304 case JITArrayStorage:
305 slowCases = emitArrayStoragePutByVal(currentInstruction, badType);
306 break;
307 default:
308 CRASH();
309 break;
310 }
311
312 addSlowCase(badType);
313 addSlowCase(slowCases);
314
315 Label done = label();
316
317 m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
318}
6fe7ccc8 319
93a37866
A
320JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
321{
81345200
A
322 int base = currentInstruction[1].u.operand;
323 int value = currentInstruction[3].u.operand;
93a37866
A
324 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
325
326 JumpList slowCases;
327
328 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ContiguousShape));
329
330 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
331 Jump outOfBounds = branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength()));
332
333 Label storeResult = label();
334 emitLoad(value, regT1, regT0);
335 switch (indexingShape) {
336 case Int32Shape:
337 slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
81345200
A
338 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
339 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
340 break;
93a37866
A
341 case ContiguousShape:
342 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
343 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
81345200
A
344 emitLoad(base, regT2, regT3);
345 emitWriteBarrier(base, value, ShouldFilterValue);
93a37866
A
346 break;
347 case DoubleShape: {
348 Jump notInt = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
349 convertInt32ToDouble(regT0, fpRegT0);
350 Jump ready = jump();
351 notInt.link(this);
352 moveIntsToDouble(regT0, regT1, fpRegT0, fpRegT1);
353 slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
354 ready.link(this);
355 storeDouble(fpRegT0, BaseIndex(regT3, regT2, TimesEight));
356 break;
357 }
358 default:
359 CRASH();
360 break;
361 }
362
363 Jump done = jump();
364
365 outOfBounds.link(this);
366 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfVectorLength())));
367
368 emitArrayProfileStoreToHoleSpecialCase(profile);
369
370 add32(TrustedImm32(1), regT2, regT1);
371 store32(regT1, Address(regT3, Butterfly::offsetOfPublicLength()));
372 jump().linkTo(storeResult, this);
373
374 done.link(this);
375
93a37866
A
376 return slowCases;
377}
378
379JIT::JumpList JIT::emitArrayStoragePutByVal(Instruction* currentInstruction, PatchableJump& badType)
380{
81345200
A
381 int base = currentInstruction[1].u.operand;
382 int value = currentInstruction[3].u.operand;
93a37866
A
383 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
384
385 JumpList slowCases;
386
387 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ArrayStorageShape));
388
389 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
390 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset())));
391
14957cd0 392 Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
4e4e5a6f
A
393
394 Label storeResult(this);
395 emitLoad(value, regT1, regT0);
14957cd0
A
396 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload
397 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag
4e4e5a6f
A
398 Jump end = jump();
399
400 empty.link(this);
93a37866 401 emitArrayProfileStoreToHoleSpecialCase(profile);
14957cd0 402 add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
93a37866 403 branch32(Below, regT2, Address(regT3, ArrayStorage::lengthOffset())).linkTo(storeResult, this);
4e4e5a6f 404
14957cd0 405 add32(TrustedImm32(1), regT2, regT0);
93a37866 406 store32(regT0, Address(regT3, ArrayStorage::lengthOffset()));
4e4e5a6f
A
407 jump().linkTo(storeResult, this);
408
409 end.link(this);
93a37866 410
81345200 411 emitWriteBarrier(base, value, ShouldFilterValue);
93a37866
A
412
413 return slowCases;
4e4e5a6f
A
414}
415
416void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
417{
81345200
A
418 int base = currentInstruction[1].u.operand;
419 int property = currentInstruction[2].u.operand;
420 int value = currentInstruction[3].u.operand;
93a37866 421 ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
4e4e5a6f
A
422
423 linkSlowCase(iter); // property int32 check
424 linkSlowCaseIfNotJSCell(iter, base); // base cell check
425 linkSlowCase(iter); // base not array check
93a37866
A
426
427 JITArrayMode mode = chooseArrayMode(profile);
428 switch (mode) {
429 case JITInt32:
430 case JITDouble:
431 linkSlowCase(iter); // value type check
432 break;
433 default:
434 break;
435 }
436
437 Jump skipProfiling = jump();
438 linkSlowCase(iter); // out of bounds
439 emitArrayProfileOutOfBoundsSpecialCase(profile);
440 skipProfiling.link(this);
441
442 Label slowPath = label();
4e4e5a6f 443
81345200
A
444 bool isDirect = m_interpreter->getOpcodeID(currentInstruction->u.opcode) == op_put_by_val_direct;
445
446#if CPU(X86)
447 // FIXME: We only have 5 temp registers, but need 6 to make this call, therefore we materialize
448 // our own call. When we finish moving JSC to the C call stack, we'll get another register so
449 // we can use the normal case.
450 resetCallArguments();
451 addCallArgument(GPRInfo::callFrameRegister);
452 emitLoad(base, regT0, regT1);
453 addCallArgument(regT1);
454 addCallArgument(regT0);
455 emitLoad(property, regT0, regT1);
456 addCallArgument(regT1);
457 addCallArgument(regT0);
458 emitLoad(value, regT0, regT1);
459 addCallArgument(regT1);
460 addCallArgument(regT0);
ed1e77d3 461 addCallArgument(TrustedImmPtr(profile));
81345200
A
462 Call call = appendCallWithExceptionCheck(isDirect ? operationDirectPutByVal : operationPutByVal);
463#else
464 // The register selection below is chosen to reduce register swapping on ARM.
465 // Swapping shouldn't happen on other platforms.
466 emitLoad(base, regT2, regT1);
467 emitLoad(property, regT3, regT0);
468 emitLoad(value, regT5, regT4);
ed1e77d3 469 Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, profile);
81345200
A
470#endif
471
93a37866
A
472 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
473 m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
474 m_byValInstructionIndex++;
4e4e5a6f
A
475}
476
477void JIT::emit_op_get_by_id(Instruction* currentInstruction)
478{
479 int dst = currentInstruction[1].u.operand;
480 int base = currentInstruction[2].u.operand;
81345200 481 const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
4e4e5a6f
A
482
483 emitLoad(base, regT1, regT0);
484 emitJumpSlowCaseIfNotJSCell(base, regT1);
4e4e5a6f 485
81345200
A
486 if (*ident == m_vm->propertyNames->length && shouldEmitProfiling())
487 emitArrayProfilingSiteForBytecodeIndexWithCell(regT0, regT2, m_bytecodeOffset);
93a37866 488
81345200
A
489 JITGetByIdGenerator gen(
490 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
491 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill);
492 gen.generateFastPath(*this);
493 addSlowCase(gen.slowPathJump());
494 m_getByIds.append(gen);
6fe7ccc8 495
81345200
A
496 emitValueProfilingSite();
497 emitStore(dst, regT1, regT0);
4e4e5a6f
A
498}
499
500void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
501{
81345200
A
502 int resultVReg = currentInstruction[1].u.operand;
503 int baseVReg = currentInstruction[2].u.operand;
504 const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
4e4e5a6f 505
81345200 506 linkSlowCaseIfNotJSCell(iter, baseVReg);
4e4e5a6f 507 linkSlowCase(iter);
81345200
A
508
509 JITGetByIdGenerator& gen = m_getByIds[m_getByIdIndex++];
4e4e5a6f 510
81345200 511 Label coldPathBegin = label();
4e4e5a6f 512
81345200 513 Call call = callOperation(WithProfile, operationGetByIdOptimize, resultVReg, gen.stubInfo(), regT1, regT0, ident->impl());
4e4e5a6f 514
81345200 515 gen.reportSlowPathCall(coldPathBegin, call);
4e4e5a6f
A
516}
517
518void JIT::emit_op_put_by_id(Instruction* currentInstruction)
519{
520 // In order to be able to patch both the Structure, and the object offset, we store one pointer,
521 // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
522 // such that the Structure & offset are always at the same distance from this.
523
524 int base = currentInstruction[1].u.operand;
525 int value = currentInstruction[3].u.operand;
81345200 526 int direct = currentInstruction[8].u.operand;
4e4e5a6f 527
81345200
A
528 emitWriteBarrier(base, value, ShouldFilterBase);
529
4e4e5a6f
A
530 emitLoad2(base, regT1, regT0, value, regT3, regT2);
531
532 emitJumpSlowCaseIfNotJSCell(base, regT1);
81345200
A
533
534 JITPutByIdGenerator gen(
535 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
536 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2),
537 regT1, DontSpill, m_codeBlock->ecmaMode(), direct ? Direct : NotDirect);
4e4e5a6f 538
81345200
A
539 gen.generateFastPath(*this);
540 addSlowCase(gen.slowPathJump());
4e4e5a6f 541
81345200 542 m_putByIds.append(gen);
4e4e5a6f
A
543}
544
545void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
546{
547 int base = currentInstruction[1].u.operand;
81345200 548 const Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand));
4e4e5a6f
A
549
550 linkSlowCaseIfNotJSCell(iter, base);
551 linkSlowCase(iter);
552
81345200 553 Label coldPathBegin(this);
ed1e77d3
A
554
555 // JITPutByIdGenerator only preserve the value and the base's payload, we have to reload the tag.
556 emitLoadTag(base, regT1);
557
81345200 558 JITPutByIdGenerator& gen = m_putByIds[m_putByIdIndex++];
4e4e5a6f 559
81345200
A
560 Call call = callOperation(
561 gen.slowPathFunction(), gen.stubInfo(), regT3, regT2, regT1, regT0, ident->impl());
562
563 gen.reportSlowPathCall(coldPathBegin, call);
4e4e5a6f
A
564}
565
566// Compile a store into an object's property storage. May overwrite base.
93a37866 567void JIT::compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, PropertyOffset cachedOffset)
4e4e5a6f 568{
93a37866
A
569 if (isOutOfLineOffset(cachedOffset))
570 loadPtr(Address(base, JSObject::butterflyOffset()), base);
571 emitStore(indexRelativeToBase(cachedOffset), valueTag, valuePayload, base);
4e4e5a6f
A
572}
573
574// Compile a load from an object's property storage. May overwrite base.
93a37866 575void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset)
4e4e5a6f 576{
93a37866
A
577 if (isInlineOffset(cachedOffset)) {
578 emitLoad(indexRelativeToBase(cachedOffset), resultTag, resultPayload, base);
579 return;
580 }
581
6fe7ccc8 582 RegisterID temp = resultPayload;
93a37866
A
583 loadPtr(Address(base, JSObject::butterflyOffset()), temp);
584 emitLoad(indexRelativeToBase(cachedOffset), resultTag, resultPayload, temp);
4e4e5a6f
A
585}
586
93a37866 587void JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset)
4e4e5a6f 588{
93a37866
A
589 if (isInlineOffset(cachedOffset)) {
590 move(TrustedImmPtr(base->locationForOffset(cachedOffset)), resultTag);
591 load32(Address(resultTag, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
592 load32(Address(resultTag, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
593 return;
594 }
595
596 loadPtr(base->butterflyAddress(), resultTag);
597 load32(Address(resultTag, offsetInButterfly(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
598 load32(Address(resultTag, offsetInButterfly(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
4e4e5a6f
A
599}
600
93a37866 601void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset, FinalObjectMode finalObjectMode)
4e4e5a6f 602{
4e4e5a6f
A
603 ASSERT(sizeof(JSValue) == 8);
604
93a37866
A
605 if (finalObjectMode == MayBeFinal) {
606 Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
607 loadPtr(Address(base, JSObject::butterflyOffset()), base);
608 neg32(offset);
609 Jump done = jump();
610 isInline.link(this);
611 addPtr(TrustedImmPtr(JSObject::offsetOfInlineStorage() - (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), base);
612 done.link(this);
613 } else {
81345200
A
614 if (!ASSERT_DISABLED) {
615 Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(firstOutOfLineOffset));
616 abortWithReason(JITOffsetIsNotOutOfLine);
617 isOutOfLine.link(this);
618 }
93a37866
A
619 loadPtr(Address(base, JSObject::butterflyOffset()), base);
620 neg32(offset);
621 }
622 load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), resultPayload);
623 load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), resultTag);
4e4e5a6f
A
624}
625
81345200
A
626void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
627{
628 if (!needsVarInjectionChecks)
629 return;
630 addSlowCase(branch8(Equal, AbsoluteAddress(m_codeBlock->globalObject()->varInjectionWatchpoint()->addressOfState()), TrustedImm32(IsInvalidated)));
4e4e5a6f
A
631}
632
ed1e77d3 633void JIT::emitResolveClosure(int dst, int scope, bool needsVarInjectionChecks, unsigned depth)
81345200
A
634{
635 emitVarInjectionCheck(needsVarInjectionChecks);
636 move(TrustedImm32(JSValue::CellTag), regT1);
ed1e77d3 637 emitLoadPayload(scope, regT0);
81345200
A
638 for (unsigned i = 0; i < depth; ++i)
639 loadPtr(Address(regT0, JSScope::offsetOfNext()), regT0);
640 emitStore(dst, regT1, regT0);
641}
642
643void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
6fe7ccc8
A
644{
645 int dst = currentInstruction[1].u.operand;
ed1e77d3
A
646 int scope = currentInstruction[2].u.operand;
647 ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
648 unsigned depth = currentInstruction[5].u.operand;
81345200
A
649
650 switch (resolveType) {
651 case GlobalProperty:
652 case GlobalVar:
653 case GlobalPropertyWithVarInjectionChecks:
654 case GlobalVarWithVarInjectionChecks:
655 emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
656 move(TrustedImm32(JSValue::CellTag), regT1);
657 move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
658 emitStore(dst, regT1, regT0);
659 break;
660 case ClosureVar:
661 case ClosureVarWithVarInjectionChecks:
ed1e77d3 662 emitResolveClosure(dst, scope, needsVarInjectionChecks(resolveType), depth);
81345200
A
663 break;
664 case Dynamic:
665 addSlowCase(jump());
666 break;
ed1e77d3
A
667 case LocalClosureVar:
668 RELEASE_ASSERT_NOT_REACHED();
6fe7ccc8 669 }
81345200 670}
6fe7ccc8 671
81345200
A
672void JIT::emitSlow_op_resolve_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
673{
674 int dst = currentInstruction[1].u.operand;
ed1e77d3 675 ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
6fe7ccc8 676
81345200
A
677 if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar)
678 return;
679
680 linkSlowCase(iter);
ed1e77d3
A
681 int32_t scope = currentInstruction[2].u.operand;
682 int32_t identifierIndex = currentInstruction[3].u.operand;
683 callOperation(operationResolveScope, dst, scope, identifierIndex);
6fe7ccc8
A
684}
685
81345200 686void JIT::emitLoadWithStructureCheck(int scope, Structure** structureSlot)
6fe7ccc8 687{
81345200
A
688 emitLoad(scope, regT1, regT0);
689 loadPtr(structureSlot, regT2);
690 addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), regT2));
691}
6fe7ccc8 692
81345200
A
693void JIT::emitGetGlobalProperty(uintptr_t* operandSlot)
694{
695 move(regT0, regT2);
696 load32(operandSlot, regT3);
697 compileGetDirectOffset(regT2, regT1, regT0, regT3, KnownNotFinal);
698}
6fe7ccc8 699
81345200
A
700void JIT::emitGetGlobalVar(uintptr_t operand)
701{
702 load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag), regT1);
703 load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), regT0);
704}
6fe7ccc8 705
81345200
A
706void JIT::emitGetClosureVar(int scope, uintptr_t operand)
707{
708 emitLoad(scope, regT1, regT0);
ed1e77d3
A
709 load32(Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + TagOffset), regT1);
710 load32(Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + PayloadOffset), regT0);
6fe7ccc8
A
711}
712
81345200 713void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
6fe7ccc8 714{
81345200
A
715 int dst = currentInstruction[1].u.operand;
716 int scope = currentInstruction[2].u.operand;
717 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
718 Structure** structureSlot = currentInstruction[5].u.structure.slot();
719 uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
720
721 switch (resolveType) {
722 case GlobalProperty:
723 case GlobalPropertyWithVarInjectionChecks:
724 emitLoadWithStructureCheck(scope, structureSlot); // Structure check covers var injection.
725 emitGetGlobalProperty(operandSlot);
726 break;
727 case GlobalVar:
728 case GlobalVarWithVarInjectionChecks:
729 emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
730 emitGetGlobalVar(*operandSlot);
731 break;
732 case ClosureVar:
733 case ClosureVarWithVarInjectionChecks:
734 emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
735 emitGetClosureVar(scope, *operandSlot);
736 break;
737 case Dynamic:
738 addSlowCase(jump());
739 break;
ed1e77d3
A
740 case LocalClosureVar:
741 RELEASE_ASSERT_NOT_REACHED();
81345200
A
742 }
743 emitValueProfilingSite();
744 emitStore(dst, regT1, regT0);
745}
93a37866 746
81345200
A
747void JIT::emitSlow_op_get_from_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
748{
749 int dst = currentInstruction[1].u.operand;
750 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
6fe7ccc8 751
81345200
A
752 if (resolveType == GlobalVar || resolveType == ClosureVar)
753 return;
6fe7ccc8 754
81345200
A
755 linkSlowCase(iter);
756 callOperation(WithProfile, operationGetFromScope, dst, currentInstruction);
6fe7ccc8
A
757}
758
81345200 759void JIT::emitPutGlobalProperty(uintptr_t* operandSlot, int value)
6fe7ccc8 760{
81345200 761 emitLoad(value, regT3, regT2);
93a37866 762
81345200
A
763 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
764 loadPtr(operandSlot, regT1);
765 negPtr(regT1);
766 store32(regT3, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
767 store32(regT2, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
768}
769
ed1e77d3 770void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set)
81345200 771{
6fe7ccc8 772 emitLoad(value, regT1, regT0);
ed1e77d3 773 emitNotifyWrite(set);
81345200
A
774 store32(regT1, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
775 store32(regT0, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
93a37866 776}
6fe7ccc8 777
ed1e77d3 778void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value, WatchpointSet* set)
93a37866 779{
81345200
A
780 emitLoad(value, regT3, regT2);
781 emitLoad(scope, regT1, regT0);
ed1e77d3
A
782 emitNotifyWrite(set);
783 store32(regT3, Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + TagOffset));
784 store32(regT2, Address(regT0, JSEnvironmentRecord::offsetOfVariables() + operand * sizeof(Register) + PayloadOffset));
81345200
A
785}
786
787void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
788{
789 int scope = currentInstruction[1].u.operand;
790 int value = currentInstruction[3].u.operand;
791 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
792 Structure** structureSlot = currentInstruction[5].u.structure.slot();
793 uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
794
795 switch (resolveType) {
796 case GlobalProperty:
797 case GlobalPropertyWithVarInjectionChecks:
798 emitWriteBarrier(m_codeBlock->globalObject(), value, ShouldFilterValue);
799 emitLoadWithStructureCheck(scope, structureSlot); // Structure check covers var injection.
800 emitPutGlobalProperty(operandSlot, value);
801 break;
802 case GlobalVar:
803 case GlobalVarWithVarInjectionChecks:
804 emitWriteBarrier(m_codeBlock->globalObject(), value, ShouldFilterValue);
805 emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
806 emitPutGlobalVar(*operandSlot, value, currentInstruction[5].u.watchpointSet);
807 break;
ed1e77d3 808 case LocalClosureVar:
81345200
A
809 case ClosureVar:
810 case ClosureVarWithVarInjectionChecks:
811 emitWriteBarrier(scope, value, ShouldFilterValue);
812 emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
ed1e77d3 813 emitPutClosureVar(scope, *operandSlot, value, currentInstruction[5].u.watchpointSet);
81345200
A
814 break;
815 case Dynamic:
816 addSlowCase(jump());
817 break;
818 }
6fe7ccc8
A
819}
820
81345200 821void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
6fe7ccc8 822{
81345200
A
823 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
824 unsigned linkCount = 0;
ed1e77d3 825 if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar)
81345200 826 linkCount++;
ed1e77d3 827 if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
81345200 828 && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
ed1e77d3 829 linkCount++;
81345200
A
830 if (!linkCount)
831 return;
832 while (linkCount--)
833 linkSlowCase(iter);
834 callOperation(operationPutToScope, currentInstruction);
6fe7ccc8
A
835}
836
ed1e77d3
A
837void JIT::emit_op_get_from_arguments(Instruction* currentInstruction)
838{
839 int dst = currentInstruction[1].u.operand;
840 int arguments = currentInstruction[2].u.operand;
841 int index = currentInstruction[3].u.operand;
842
843 emitLoadPayload(arguments, regT0);
844 load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + TagOffset), regT1);
845 load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset), regT0);
846 emitValueProfilingSite();
847 emitStore(dst, regT1, regT0);
848}
849
850void JIT::emit_op_put_to_arguments(Instruction* currentInstruction)
851{
852 int arguments = currentInstruction[1].u.operand;
853 int index = currentInstruction[2].u.operand;
854 int value = currentInstruction[3].u.operand;
855
856 emitWriteBarrier(arguments, value, ShouldFilterValue);
857
858 emitLoadPayload(arguments, regT0);
859 emitLoad(value, regT1, regT2);
860 store32(regT1, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + TagOffset));
861 store32(regT2, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset));
862}
863
81345200 864void JIT::emit_op_init_global_const(Instruction* currentInstruction)
6fe7ccc8 865{
ed1e77d3 866 WriteBarrier<Unknown>* variablePointer = currentInstruction[1].u.variablePointer;
81345200
A
867 int value = currentInstruction[2].u.operand;
868
869 JSGlobalObject* globalObject = m_codeBlock->globalObject();
870
871 emitWriteBarrier(globalObject, value, ShouldFilterValue);
872
873 emitLoad(value, regT1, regT0);
874
ed1e77d3
A
875 store32(regT1, variablePointer->tagPointer());
876 store32(regT0, variablePointer->payloadPointer());
6fe7ccc8
A
877}
878
4e4e5a6f
A
879} // namespace JSC
880
14957cd0 881#endif // USE(JSVALUE32_64)
4e4e5a6f 882#endif // ENABLE(JIT)