Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "jit/CodeGenerator.h"
8 :
9 : #include "mozilla/Assertions.h"
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/Casting.h"
12 : #include "mozilla/DebugOnly.h"
13 : #include "mozilla/EnumeratedArray.h"
14 : #include "mozilla/EnumeratedRange.h"
15 : #include "mozilla/MathAlgorithms.h"
16 : #include "mozilla/ScopeExit.h"
17 : #include "mozilla/SizePrintfMacros.h"
18 :
19 : #include "jslibmath.h"
20 : #include "jsmath.h"
21 : #include "jsnum.h"
22 : #include "jsprf.h"
23 : #include "jsstr.h"
24 :
25 : #include "builtin/Eval.h"
26 : #include "builtin/RegExp.h"
27 : #include "builtin/SelfHostingDefines.h"
28 : #include "builtin/TypedObject.h"
29 : #include "gc/Nursery.h"
30 : #include "irregexp/NativeRegExpMacroAssembler.h"
31 : #include "jit/AtomicOperations.h"
32 : #include "jit/BaselineCompiler.h"
33 : #include "jit/IonBuilder.h"
34 : #include "jit/IonCaches.h"
35 : #include "jit/IonIC.h"
36 : #include "jit/IonOptimizationLevels.h"
37 : #include "jit/JitcodeMap.h"
38 : #include "jit/JitSpewer.h"
39 : #include "jit/Linker.h"
40 : #include "jit/Lowering.h"
41 : #include "jit/MIRGenerator.h"
42 : #include "jit/MoveEmitter.h"
43 : #include "jit/RangeAnalysis.h"
44 : #include "jit/SharedICHelpers.h"
45 : #include "vm/AsyncFunction.h"
46 : #include "vm/AsyncIteration.h"
47 : #include "vm/MatchPairs.h"
48 : #include "vm/RegExpObject.h"
49 : #include "vm/RegExpStatics.h"
50 : #include "vm/TraceLogging.h"
51 : #include "vm/Unicode.h"
52 : #include "vtune/VTuneWrapper.h"
53 :
54 : #include "jsboolinlines.h"
55 :
56 : #include "jit/MacroAssembler-inl.h"
57 : #include "jit/shared/CodeGenerator-shared-inl.h"
58 : #include "jit/shared/Lowering-shared-inl.h"
59 : #include "vm/Interpreter-inl.h"
60 :
61 : using namespace js;
62 : using namespace js::jit;
63 :
64 : using mozilla::AssertedCast;
65 : using mozilla::DebugOnly;
66 : using mozilla::FloatingPoint;
67 : using mozilla::Maybe;
68 : using mozilla::NegativeInfinity;
69 : using mozilla::PositiveInfinity;
70 : using JS::GenericNaN;
71 :
72 : namespace js {
73 : namespace jit {
74 :
75 : class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
76 : {
77 : private:
78 : LInstruction* lir_;
79 : size_t cacheIndex_;
80 : size_t cacheInfoIndex_;
81 :
82 : public:
83 35 : OutOfLineICFallback(LInstruction* lir, size_t cacheIndex, size_t cacheInfoIndex)
84 35 : : lir_(lir),
85 : cacheIndex_(cacheIndex),
86 35 : cacheInfoIndex_(cacheInfoIndex)
87 35 : { }
88 :
89 35 : void bind(MacroAssembler* masm) {
90 : // The binding of the initial jump is done in
91 : // CodeGenerator::visitOutOfLineICFallback.
92 35 : }
93 :
94 35 : size_t cacheIndex() const {
95 35 : return cacheIndex_;
96 : }
97 35 : size_t cacheInfoIndex() const {
98 35 : return cacheInfoIndex_;
99 : }
100 35 : LInstruction* lir() const {
101 35 : return lir_;
102 : }
103 :
104 35 : void accept(CodeGenerator* codegen) {
105 35 : codegen->visitOutOfLineICFallback(this);
106 35 : }
107 : };
108 :
109 : void
110 35 : CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
111 : {
112 35 : if (cacheIndex == SIZE_MAX) {
113 0 : masm.setOOM();
114 0 : return;
115 : }
116 :
117 35 : DataPtr<IonIC> cache(this, cacheIndex);
118 35 : MInstruction* mir = lir->mirRaw()->toInstruction();
119 35 : if (mir->resumePoint()) {
120 32 : cache->setScriptedLocation(mir->block()->info().script(),
121 32 : mir->resumePoint()->pc());
122 : } else {
123 3 : cache->setIdempotent();
124 : }
125 :
126 35 : Register temp = cache->scratchRegisterForEntryJump();
127 35 : icInfo_.back().icOffsetForJump = masm.movWithPatch(ImmWord(-1), temp);
128 35 : masm.jump(Address(temp, 0));
129 :
130 35 : MOZ_ASSERT(!icInfo_.empty());
131 :
132 35 : OutOfLineICFallback* ool = new(alloc()) OutOfLineICFallback(lir, cacheIndex, icInfo_.length() - 1);
133 35 : addOutOfLineCode(ool, mir);
134 :
135 35 : masm.bind(ool->rejoin());
136 35 : cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset()));
137 : }
138 :
139 : typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue,
140 : MutableHandleValue);
141 3 : static const VMFunction IonGetPropertyICInfo =
142 6 : FunctionInfo<IonGetPropertyICFn>(IonGetPropertyIC::update, "IonGetPropertyIC::update");
143 :
144 : typedef bool (*IonSetPropertyICFn)(JSContext*, HandleScript, IonSetPropertyIC*, HandleObject,
145 : HandleValue, HandleValue);
146 3 : static const VMFunction IonSetPropertyICInfo =
147 6 : FunctionInfo<IonSetPropertyICFn>(IonSetPropertyIC::update, "IonSetPropertyIC::update");
148 :
149 : typedef bool (*IonGetNameICFn)(JSContext*, HandleScript, IonGetNameIC*, HandleObject,
150 : MutableHandleValue);
151 3 : static const VMFunction IonGetNameICInfo =
152 6 : FunctionInfo<IonGetNameICFn>(IonGetNameIC::update, "IonGetNameIC::update");
153 :
154 : typedef bool (*IonHasOwnICFn)(JSContext*, HandleScript, IonHasOwnIC*, HandleValue, HandleValue,
155 : int32_t*);
156 3 : static const VMFunction IonHasOwnICInfo =
157 6 : FunctionInfo<IonHasOwnICFn>(IonHasOwnIC::update, "IonHasOwnIC::update");
158 :
159 : typedef JSObject* (*IonBindNameICFn)(JSContext*, HandleScript, IonBindNameIC*, HandleObject);
160 3 : static const VMFunction IonBindNameICInfo =
161 6 : FunctionInfo<IonBindNameICFn>(IonBindNameIC::update, "IonBindNameIC::update");
162 :
163 : typedef bool (*IonInICFn)(JSContext*, HandleScript, IonInIC*, HandleValue, HandleObject, bool*);
164 3 : static const VMFunction IonInICInfo =
165 6 : FunctionInfo<IonInICFn>(IonInIC::update, "IonInIC::update");
166 :
167 : void
168 35 : CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
169 : {
170 35 : LInstruction* lir = ool->lir();
171 35 : size_t cacheIndex = ool->cacheIndex();
172 35 : size_t cacheInfoIndex = ool->cacheInfoIndex();
173 :
174 35 : DataPtr<IonIC> ic(this, cacheIndex);
175 :
176 : // Register the location of the OOL path in the IC.
177 35 : ic->setFallbackLabel(masm.labelForPatch());
178 :
179 35 : switch (ic->kind()) {
180 : case CacheKind::GetProp:
181 : case CacheKind::GetElem: {
182 23 : IonGetPropertyIC* getPropIC = ic->asGetPropertyIC();
183 :
184 23 : saveLive(lir);
185 :
186 23 : pushArg(getPropIC->id());
187 23 : pushArg(getPropIC->value());
188 23 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
189 23 : pushArg(ImmGCPtr(gen->info().script()));
190 :
191 23 : callVM(IonGetPropertyICInfo, lir);
192 :
193 23 : StoreValueTo(getPropIC->output()).generate(this);
194 23 : restoreLiveIgnore(lir, StoreValueTo(getPropIC->output()).clobbered());
195 :
196 23 : masm.jump(ool->rejoin());
197 23 : return;
198 : }
199 : case CacheKind::SetProp:
200 : case CacheKind::SetElem: {
201 6 : IonSetPropertyIC* setPropIC = ic->asSetPropertyIC();
202 :
203 6 : saveLive(lir);
204 :
205 6 : pushArg(setPropIC->rhs());
206 6 : pushArg(setPropIC->id());
207 6 : pushArg(setPropIC->object());
208 6 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
209 6 : pushArg(ImmGCPtr(gen->info().script()));
210 :
211 6 : callVM(IonSetPropertyICInfo, lir);
212 :
213 6 : restoreLive(lir);
214 :
215 6 : masm.jump(ool->rejoin());
216 6 : return;
217 : }
218 : case CacheKind::GetName: {
219 4 : IonGetNameIC* getNameIC = ic->asGetNameIC();
220 :
221 4 : saveLive(lir);
222 :
223 4 : pushArg(getNameIC->environment());
224 4 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
225 4 : pushArg(ImmGCPtr(gen->info().script()));
226 :
227 4 : callVM(IonGetNameICInfo, lir);
228 :
229 4 : StoreValueTo(getNameIC->output()).generate(this);
230 4 : restoreLiveIgnore(lir, StoreValueTo(getNameIC->output()).clobbered());
231 :
232 4 : masm.jump(ool->rejoin());
233 4 : return;
234 : }
235 : case CacheKind::BindName: {
236 0 : IonBindNameIC* bindNameIC = ic->asBindNameIC();
237 :
238 0 : saveLive(lir);
239 :
240 0 : pushArg(bindNameIC->environment());
241 0 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
242 0 : pushArg(ImmGCPtr(gen->info().script()));
243 :
244 0 : callVM(IonBindNameICInfo, lir);
245 :
246 0 : StoreRegisterTo(bindNameIC->output()).generate(this);
247 0 : restoreLiveIgnore(lir, StoreRegisterTo(bindNameIC->output()).clobbered());
248 :
249 0 : masm.jump(ool->rejoin());
250 0 : return;
251 : }
252 : case CacheKind::In: {
253 2 : IonInIC* inIC = ic->asInIC();
254 :
255 2 : saveLive(lir);
256 :
257 2 : pushArg(inIC->object());
258 2 : pushArg(inIC->key());
259 2 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
260 2 : pushArg(ImmGCPtr(gen->info().script()));
261 :
262 2 : callVM(IonInICInfo, lir);
263 :
264 2 : StoreRegisterTo(inIC->output()).generate(this);
265 2 : restoreLiveIgnore(lir, StoreRegisterTo(inIC->output()).clobbered());
266 :
267 2 : masm.jump(ool->rejoin());
268 2 : return;
269 : }
270 : case CacheKind::HasOwn: {
271 0 : IonHasOwnIC* hasOwnIC = ic->asHasOwnIC();
272 :
273 0 : saveLive(lir);
274 :
275 0 : pushArg(hasOwnIC->id());
276 0 : pushArg(hasOwnIC->value());
277 0 : icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
278 0 : pushArg(ImmGCPtr(gen->info().script()));
279 :
280 0 : callVM(IonHasOwnICInfo, lir);
281 :
282 0 : StoreRegisterTo(hasOwnIC->output()).generate(this);
283 0 : restoreLiveIgnore(lir, StoreRegisterTo(hasOwnIC->output()).clobbered());
284 :
285 0 : masm.jump(ool->rejoin());
286 0 : return;
287 : }
288 : case CacheKind::Call:
289 : case CacheKind::Compare:
290 : case CacheKind::TypeOf:
291 : case CacheKind::GetPropSuper:
292 : case CacheKind::GetElemSuper:
293 0 : MOZ_CRASH("Unsupported IC");
294 : }
295 0 : MOZ_CRASH();
296 : }
297 :
298 : StringObject*
299 0 : MNewStringObject::templateObj() const
300 : {
301 0 : return &templateObj_->as<StringObject>();
302 : }
303 :
304 8 : CodeGenerator::CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
305 : : CodeGeneratorSpecific(gen, graph, masm)
306 : , ionScriptLabels_(gen->alloc())
307 : , scriptCounts_(nullptr)
308 8 : , simdRefreshTemplatesDuringLink_(0)
309 : {
310 8 : }
311 :
312 16 : CodeGenerator::~CodeGenerator()
313 : {
314 8 : MOZ_ASSERT_IF(!gen->compilingWasm(), masm.numSymbolicAccesses() == 0);
315 8 : js_delete(scriptCounts_);
316 8 : }
317 :
318 : typedef bool (*StringToNumberFn)(JSContext*, JSString*, double*);
319 3 : static const VMFunction StringToNumberInfo =
320 6 : FunctionInfo<StringToNumberFn>(StringToNumber, "StringToNumber");
321 :
322 : void
323 2 : CodeGenerator::visitValueToInt32(LValueToInt32* lir)
324 : {
325 2 : ValueOperand operand = ToValue(lir, LValueToInt32::Input);
326 2 : Register output = ToRegister(lir->output());
327 2 : FloatRegister temp = ToFloatRegister(lir->tempFloat());
328 :
329 : MDefinition* input;
330 2 : if (lir->mode() == LValueToInt32::NORMAL)
331 1 : input = lir->mirNormal()->input();
332 : else
333 1 : input = lir->mirTruncate()->input();
334 :
335 4 : Label fails;
336 2 : if (lir->mode() == LValueToInt32::TRUNCATE) {
337 1 : OutOfLineCode* oolDouble = oolTruncateDouble(temp, output, lir->mir());
338 :
339 : // We can only handle strings in truncation contexts, like bitwise
340 : // operations.
341 : Label* stringEntry;
342 : Label* stringRejoin;
343 1 : Register stringReg;
344 1 : if (input->mightBeType(MIRType::String)) {
345 0 : stringReg = ToRegister(lir->temp());
346 0 : OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(stringReg),
347 0 : StoreFloatRegisterTo(temp));
348 0 : stringEntry = oolString->entry();
349 0 : stringRejoin = oolString->rejoin();
350 : } else {
351 1 : stringReg = InvalidReg;
352 1 : stringEntry = nullptr;
353 1 : stringRejoin = nullptr;
354 : }
355 :
356 1 : masm.truncateValueToInt32(operand, input, stringEntry, stringRejoin, oolDouble->entry(),
357 1 : stringReg, temp, output, &fails);
358 1 : masm.bind(oolDouble->rejoin());
359 : } else {
360 2 : masm.convertValueToInt32(operand, input, temp, output, &fails,
361 1 : lir->mirNormal()->canBeNegativeZero(),
362 1 : lir->mirNormal()->conversion());
363 : }
364 :
365 2 : bailoutFrom(&fails, lir->snapshot());
366 2 : }
367 :
368 : void
369 0 : CodeGenerator::visitValueToDouble(LValueToDouble* lir)
370 : {
371 0 : MToDouble* mir = lir->mir();
372 0 : ValueOperand operand = ToValue(lir, LValueToDouble::Input);
373 0 : FloatRegister output = ToFloatRegister(lir->output());
374 :
375 0 : Register tag = masm.splitTagForTest(operand);
376 :
377 0 : Label isDouble, isInt32, isBool, isNull, isUndefined, done;
378 0 : bool hasBoolean = false, hasNull = false, hasUndefined = false;
379 :
380 0 : masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
381 0 : masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
382 :
383 0 : if (mir->conversion() != MToFPInstruction::NumbersOnly) {
384 0 : masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
385 0 : masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
386 0 : hasBoolean = true;
387 0 : hasUndefined = true;
388 0 : if (mir->conversion() != MToFPInstruction::NonNullNonStringPrimitives) {
389 0 : masm.branchTestNull(Assembler::Equal, tag, &isNull);
390 0 : hasNull = true;
391 : }
392 : }
393 :
394 0 : bailout(lir->snapshot());
395 :
396 0 : if (hasNull) {
397 0 : masm.bind(&isNull);
398 0 : masm.loadConstantDouble(0.0, output);
399 0 : masm.jump(&done);
400 : }
401 :
402 0 : if (hasUndefined) {
403 0 : masm.bind(&isUndefined);
404 0 : masm.loadConstantDouble(GenericNaN(), output);
405 0 : masm.jump(&done);
406 : }
407 :
408 0 : if (hasBoolean) {
409 0 : masm.bind(&isBool);
410 0 : masm.boolValueToDouble(operand, output);
411 0 : masm.jump(&done);
412 : }
413 :
414 0 : masm.bind(&isInt32);
415 0 : masm.int32ValueToDouble(operand, output);
416 0 : masm.jump(&done);
417 :
418 0 : masm.bind(&isDouble);
419 0 : masm.unboxDouble(operand, output);
420 0 : masm.bind(&done);
421 0 : }
422 :
423 : void
424 0 : CodeGenerator::visitValueToFloat32(LValueToFloat32* lir)
425 : {
426 0 : MToFloat32* mir = lir->mir();
427 0 : ValueOperand operand = ToValue(lir, LValueToFloat32::Input);
428 0 : FloatRegister output = ToFloatRegister(lir->output());
429 :
430 0 : Register tag = masm.splitTagForTest(operand);
431 :
432 0 : Label isDouble, isInt32, isBool, isNull, isUndefined, done;
433 0 : bool hasBoolean = false, hasNull = false, hasUndefined = false;
434 :
435 0 : masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
436 0 : masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
437 :
438 0 : if (mir->conversion() != MToFPInstruction::NumbersOnly) {
439 0 : masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
440 0 : masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
441 0 : hasBoolean = true;
442 0 : hasUndefined = true;
443 0 : if (mir->conversion() != MToFPInstruction::NonNullNonStringPrimitives) {
444 0 : masm.branchTestNull(Assembler::Equal, tag, &isNull);
445 0 : hasNull = true;
446 : }
447 : }
448 :
449 0 : bailout(lir->snapshot());
450 :
451 0 : if (hasNull) {
452 0 : masm.bind(&isNull);
453 0 : masm.loadConstantFloat32(0.0f, output);
454 0 : masm.jump(&done);
455 : }
456 :
457 0 : if (hasUndefined) {
458 0 : masm.bind(&isUndefined);
459 0 : masm.loadConstantFloat32(float(GenericNaN()), output);
460 0 : masm.jump(&done);
461 : }
462 :
463 0 : if (hasBoolean) {
464 0 : masm.bind(&isBool);
465 0 : masm.boolValueToFloat32(operand, output);
466 0 : masm.jump(&done);
467 : }
468 :
469 0 : masm.bind(&isInt32);
470 0 : masm.int32ValueToFloat32(operand, output);
471 0 : masm.jump(&done);
472 :
473 0 : masm.bind(&isDouble);
474 : // ARM and MIPS may not have a double register available if we've
475 : // allocated output as a float32.
476 : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
477 : masm.unboxDouble(operand, ScratchDoubleReg);
478 : masm.convertDoubleToFloat32(ScratchDoubleReg, output);
479 : #else
480 0 : masm.unboxDouble(operand, output);
481 0 : masm.convertDoubleToFloat32(output, output);
482 : #endif
483 0 : masm.bind(&done);
484 0 : }
485 :
486 : void
487 0 : CodeGenerator::visitInt32ToDouble(LInt32ToDouble* lir)
488 : {
489 0 : masm.convertInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
490 0 : }
491 :
492 : void
493 0 : CodeGenerator::visitFloat32ToDouble(LFloat32ToDouble* lir)
494 : {
495 0 : masm.convertFloat32ToDouble(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
496 0 : }
497 :
498 : void
499 0 : CodeGenerator::visitDoubleToFloat32(LDoubleToFloat32* lir)
500 : {
501 0 : masm.convertDoubleToFloat32(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
502 0 : }
503 :
504 : void
505 0 : CodeGenerator::visitInt32ToFloat32(LInt32ToFloat32* lir)
506 : {
507 0 : masm.convertInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
508 0 : }
509 :
510 : void
511 0 : CodeGenerator::visitDoubleToInt32(LDoubleToInt32* lir)
512 : {
513 0 : Label fail;
514 0 : FloatRegister input = ToFloatRegister(lir->input());
515 0 : Register output = ToRegister(lir->output());
516 0 : masm.convertDoubleToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
517 0 : bailoutFrom(&fail, lir->snapshot());
518 0 : }
519 :
520 : void
521 0 : CodeGenerator::visitFloat32ToInt32(LFloat32ToInt32* lir)
522 : {
523 0 : Label fail;
524 0 : FloatRegister input = ToFloatRegister(lir->input());
525 0 : Register output = ToRegister(lir->output());
526 0 : masm.convertFloat32ToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
527 0 : bailoutFrom(&fail, lir->snapshot());
528 0 : }
529 :
530 : void
531 0 : CodeGenerator::emitOOLTestObject(Register objreg,
532 : Label* ifEmulatesUndefined,
533 : Label* ifDoesntEmulateUndefined,
534 : Register scratch)
535 : {
536 0 : saveVolatile(scratch);
537 0 : masm.setupUnalignedABICall(scratch);
538 0 : masm.passABIArg(objreg);
539 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::EmulatesUndefined));
540 0 : masm.storeCallBoolResult(scratch);
541 0 : restoreVolatile(scratch);
542 :
543 0 : masm.branchIfTrueBool(scratch, ifEmulatesUndefined);
544 0 : masm.jump(ifDoesntEmulateUndefined);
545 0 : }
546 :
547 : // Base out-of-line code generator for all tests of the truthiness of an
548 : // object, where the object might not be truthy. (Recall that per spec all
549 : // objects are truthy, but we implement the JSCLASS_EMULATES_UNDEFINED class
550 : // flag to permit objects to look like |undefined| in certain contexts,
551 : // including in object truthiness testing.) We check truthiness inline except
552 : // when we're testing it on a proxy (or if TI guarantees us that the specified
553 : // object will never emulate |undefined|), in which case out-of-line code will
554 : // call EmulatesUndefined for a conclusive answer.
555 : class OutOfLineTestObject : public OutOfLineCodeBase<CodeGenerator>
556 : {
557 : Register objreg_;
558 : Register scratch_;
559 :
560 : Label* ifEmulatesUndefined_;
561 : Label* ifDoesntEmulateUndefined_;
562 :
563 : #ifdef DEBUG
564 0 : bool initialized() { return ifEmulatesUndefined_ != nullptr; }
565 : #endif
566 :
567 : public:
568 0 : OutOfLineTestObject()
569 : #ifdef DEBUG
570 0 : : ifEmulatesUndefined_(nullptr), ifDoesntEmulateUndefined_(nullptr)
571 : #endif
572 0 : { }
573 :
574 0 : void accept(CodeGenerator* codegen) final override {
575 0 : MOZ_ASSERT(initialized());
576 0 : codegen->emitOOLTestObject(objreg_, ifEmulatesUndefined_, ifDoesntEmulateUndefined_,
577 0 : scratch_);
578 0 : }
579 :
580 : // Specify the register where the object to be tested is found, labels to
581 : // jump to if the object is truthy or falsy, and a scratch register for
582 : // use in the out-of-line path.
583 0 : void setInputAndTargets(Register objreg, Label* ifEmulatesUndefined, Label* ifDoesntEmulateUndefined,
584 : Register scratch)
585 : {
586 0 : MOZ_ASSERT(!initialized());
587 0 : MOZ_ASSERT(ifEmulatesUndefined);
588 0 : objreg_ = objreg;
589 0 : scratch_ = scratch;
590 0 : ifEmulatesUndefined_ = ifEmulatesUndefined;
591 0 : ifDoesntEmulateUndefined_ = ifDoesntEmulateUndefined;
592 0 : }
593 : };
594 :
595 : // A subclass of OutOfLineTestObject containing two extra labels, for use when
596 : // the ifTruthy/ifFalsy labels are needed in inline code as well as out-of-line
597 : // code. The user should bind these labels in inline code, and specify them as
598 : // targets via setInputAndTargets, as appropriate.
599 : class OutOfLineTestObjectWithLabels : public OutOfLineTestObject
600 : {
601 : Label label1_;
602 : Label label2_;
603 :
604 : public:
605 0 : OutOfLineTestObjectWithLabels() { }
606 :
607 0 : Label* label1() { return &label1_; }
608 0 : Label* label2() { return &label2_; }
609 : };
610 :
611 : void
612 0 : CodeGenerator::testObjectEmulatesUndefinedKernel(Register objreg,
613 : Label* ifEmulatesUndefined,
614 : Label* ifDoesntEmulateUndefined,
615 : Register scratch, OutOfLineTestObject* ool)
616 : {
617 0 : ool->setInputAndTargets(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined, scratch);
618 :
619 : // Perform a fast-path check of the object's class flags if the object's
620 : // not a proxy. Let out-of-line code handle the slow cases that require
621 : // saving registers, making a function call, and restoring registers.
622 0 : masm.branchIfObjectEmulatesUndefined(objreg, scratch, ool->entry(), ifEmulatesUndefined);
623 0 : }
624 :
625 : void
626 0 : CodeGenerator::branchTestObjectEmulatesUndefined(Register objreg,
627 : Label* ifEmulatesUndefined,
628 : Label* ifDoesntEmulateUndefined,
629 : Register scratch, OutOfLineTestObject* ool)
630 : {
631 0 : MOZ_ASSERT(!ifDoesntEmulateUndefined->bound(),
632 : "ifDoesntEmulateUndefined will be bound to the fallthrough path");
633 :
634 : testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
635 0 : scratch, ool);
636 0 : masm.bind(ifDoesntEmulateUndefined);
637 0 : }
638 :
639 : void
640 0 : CodeGenerator::testObjectEmulatesUndefined(Register objreg,
641 : Label* ifEmulatesUndefined,
642 : Label* ifDoesntEmulateUndefined,
643 : Register scratch, OutOfLineTestObject* ool)
644 : {
645 : testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
646 0 : scratch, ool);
647 0 : masm.jump(ifDoesntEmulateUndefined);
648 0 : }
649 :
650 : void
651 32 : CodeGenerator::testValueTruthyKernel(const ValueOperand& value,
652 : const LDefinition* scratch1, const LDefinition* scratch2,
653 : FloatRegister fr,
654 : Label* ifTruthy, Label* ifFalsy,
655 : OutOfLineTestObject* ool,
656 : MDefinition* valueMIR)
657 : {
658 : // Count the number of possible type tags we might have, so we'll know when
659 : // we've checked them all and hence can avoid emitting a tag check for the
660 : // last one. In particular, whenever tagCount is 1 that means we've tried
661 : // all but one of them already so we know exactly what's left based on the
662 : // mightBe* booleans.
663 32 : bool mightBeUndefined = valueMIR->mightBeType(MIRType::Undefined);
664 32 : bool mightBeNull = valueMIR->mightBeType(MIRType::Null);
665 32 : bool mightBeBoolean = valueMIR->mightBeType(MIRType::Boolean);
666 32 : bool mightBeInt32 = valueMIR->mightBeType(MIRType::Int32);
667 32 : bool mightBeObject = valueMIR->mightBeType(MIRType::Object);
668 32 : bool mightBeString = valueMIR->mightBeType(MIRType::String);
669 32 : bool mightBeSymbol = valueMIR->mightBeType(MIRType::Symbol);
670 32 : bool mightBeDouble = valueMIR->mightBeType(MIRType::Double);
671 32 : int tagCount = int(mightBeUndefined) + int(mightBeNull) +
672 32 : int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
673 32 : int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble);
674 :
675 32 : MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
676 :
677 : // If we know we're null or undefined, we're definitely falsy, no
678 : // need to even check the tag.
679 32 : if (int(mightBeNull) + int(mightBeUndefined) == tagCount) {
680 1 : masm.jump(ifFalsy);
681 1 : return;
682 : }
683 :
684 31 : Register tag = masm.splitTagForTest(value);
685 :
686 31 : if (mightBeUndefined) {
687 31 : MOZ_ASSERT(tagCount > 1);
688 31 : masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
689 31 : --tagCount;
690 : }
691 :
692 31 : if (mightBeNull) {
693 0 : MOZ_ASSERT(tagCount > 1);
694 0 : masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
695 0 : --tagCount;
696 : }
697 :
698 31 : if (mightBeBoolean) {
699 31 : MOZ_ASSERT(tagCount != 0);
700 62 : Label notBoolean;
701 31 : if (tagCount != 1)
702 3 : masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
703 31 : masm.branchTestBooleanTruthy(false, value, ifFalsy);
704 31 : if (tagCount != 1)
705 3 : masm.jump(ifTruthy);
706 : // Else just fall through to truthiness.
707 31 : masm.bind(¬Boolean);
708 31 : --tagCount;
709 : }
710 :
711 31 : if (mightBeInt32) {
712 0 : MOZ_ASSERT(tagCount != 0);
713 0 : Label notInt32;
714 0 : if (tagCount != 1)
715 0 : masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
716 0 : masm.branchTestInt32Truthy(false, value, ifFalsy);
717 0 : if (tagCount != 1)
718 0 : masm.jump(ifTruthy);
719 : // Else just fall through to truthiness.
720 0 : masm.bind(¬Int32);
721 0 : --tagCount;
722 : }
723 :
724 31 : if (mightBeObject) {
725 0 : MOZ_ASSERT(tagCount != 0);
726 0 : if (ool) {
727 0 : Label notObject;
728 :
729 0 : if (tagCount != 1)
730 0 : masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
731 :
732 0 : Register objreg = masm.extractObject(value, ToRegister(scratch1));
733 0 : testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
734 :
735 0 : masm.bind(¬Object);
736 : } else {
737 0 : if (tagCount != 1)
738 0 : masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
739 : // Else just fall through to truthiness.
740 : }
741 0 : --tagCount;
742 : } else {
743 31 : MOZ_ASSERT(!ool,
744 : "We better not have an unused OOL path, since the code generator will try to "
745 : "generate code for it but we never set up its labels, which will cause null "
746 : "derefs of those labels.");
747 : }
748 :
749 31 : if (mightBeString) {
750 : // Test if a string is non-empty.
751 3 : MOZ_ASSERT(tagCount != 0);
752 6 : Label notString;
753 3 : if (tagCount != 1)
754 0 : masm.branchTestString(Assembler::NotEqual, tag, ¬String);
755 3 : masm.branchTestStringTruthy(false, value, ifFalsy);
756 3 : if (tagCount != 1)
757 0 : masm.jump(ifTruthy);
758 : // Else just fall through to truthiness.
759 3 : masm.bind(¬String);
760 3 : --tagCount;
761 : }
762 :
763 31 : if (mightBeSymbol) {
764 : // All symbols are truthy.
765 0 : MOZ_ASSERT(tagCount != 0);
766 0 : if (tagCount != 1)
767 0 : masm.branchTestSymbol(Assembler::Equal, tag, ifTruthy);
768 : // Else fall through to ifTruthy.
769 0 : --tagCount;
770 : }
771 :
772 31 : if (mightBeDouble) {
773 0 : MOZ_ASSERT(tagCount == 1);
774 : // If we reach here the value is a double.
775 0 : masm.unboxDouble(value, fr);
776 0 : masm.branchTestDoubleTruthy(false, fr, ifFalsy);
777 0 : --tagCount;
778 : }
779 :
780 31 : MOZ_ASSERT(tagCount == 0);
781 :
782 : // Fall through for truthy.
783 : }
784 :
785 : void
786 30 : CodeGenerator::testValueTruthy(const ValueOperand& value,
787 : const LDefinition* scratch1, const LDefinition* scratch2,
788 : FloatRegister fr,
789 : Label* ifTruthy, Label* ifFalsy,
790 : OutOfLineTestObject* ool,
791 : MDefinition* valueMIR)
792 : {
793 30 : testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool, valueMIR);
794 30 : masm.jump(ifTruthy);
795 30 : }
796 :
797 : void
798 0 : CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir)
799 : {
800 0 : MIRType inputType = lir->mir()->input()->type();
801 0 : MOZ_ASSERT(inputType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
802 : "If the object couldn't emulate undefined, this should have been folded.");
803 :
804 0 : Label* truthy = getJumpLabelForBranch(lir->ifTruthy());
805 0 : Label* falsy = getJumpLabelForBranch(lir->ifFalsy());
806 0 : Register input = ToRegister(lir->input());
807 :
808 0 : if (lir->mir()->operandMightEmulateUndefined()) {
809 0 : if (inputType == MIRType::ObjectOrNull)
810 0 : masm.branchTestPtr(Assembler::Zero, input, input, falsy);
811 :
812 0 : OutOfLineTestObject* ool = new(alloc()) OutOfLineTestObject();
813 0 : addOutOfLineCode(ool, lir->mir());
814 :
815 0 : testObjectEmulatesUndefined(input, falsy, truthy, ToRegister(lir->temp()), ool);
816 : } else {
817 0 : MOZ_ASSERT(inputType == MIRType::ObjectOrNull);
818 0 : testZeroEmitBranch(Assembler::NotEqual, input, lir->ifTruthy(), lir->ifFalsy());
819 : }
820 0 : }
821 :
822 : void
823 30 : CodeGenerator::visitTestVAndBranch(LTestVAndBranch* lir)
824 : {
825 30 : OutOfLineTestObject* ool = nullptr;
826 30 : MDefinition* input = lir->mir()->input();
827 : // Unfortunately, it's possible that someone (e.g. phi elimination) switched
828 : // out our input after we did cacheOperandMightEmulateUndefined. So we
829 : // might think it can emulate undefined _and_ know that it can't be an
830 : // object.
831 30 : if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType::Object)) {
832 0 : ool = new(alloc()) OutOfLineTestObject();
833 0 : addOutOfLineCode(ool, lir->mir());
834 : }
835 :
836 30 : Label* truthy = getJumpLabelForBranch(lir->ifTruthy());
837 30 : Label* falsy = getJumpLabelForBranch(lir->ifFalsy());
838 :
839 60 : testValueTruthy(ToValue(lir, LTestVAndBranch::Input),
840 : lir->temp1(), lir->temp2(),
841 : ToFloatRegister(lir->tempFloat()),
842 30 : truthy, falsy, ool, input);
843 30 : }
844 :
845 : void
846 3 : CodeGenerator::visitFunctionDispatch(LFunctionDispatch* lir)
847 : {
848 3 : MFunctionDispatch* mir = lir->mir();
849 3 : Register input = ToRegister(lir->input());
850 : Label* lastLabel;
851 : size_t casesWithFallback;
852 :
853 : // Determine if the last case is fallback or an ordinary case.
854 3 : if (!mir->hasFallback()) {
855 0 : MOZ_ASSERT(mir->numCases() > 0);
856 0 : casesWithFallback = mir->numCases();
857 0 : lastLabel = skipTrivialBlocks(mir->getCaseBlock(mir->numCases() - 1))->lir()->label();
858 : } else {
859 3 : casesWithFallback = mir->numCases() + 1;
860 3 : lastLabel = skipTrivialBlocks(mir->getFallback())->lir()->label();
861 : }
862 :
863 : // Compare function pointers, except for the last case.
864 6 : for (size_t i = 0; i < casesWithFallback - 1; i++) {
865 3 : MOZ_ASSERT(i < mir->numCases());
866 3 : LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
867 3 : if (ObjectGroup* funcGroup = mir->getCaseObjectGroup(i)) {
868 6 : masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfGroup()),
869 3 : ImmGCPtr(funcGroup), target->label());
870 : } else {
871 0 : JSFunction* func = mir->getCase(i);
872 0 : masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
873 : }
874 : }
875 :
876 : // Jump to the last case.
877 3 : masm.jump(lastLabel);
878 3 : }
879 :
880 : void
881 0 : CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch* lir)
882 : {
883 0 : MObjectGroupDispatch* mir = lir->mir();
884 0 : Register input = ToRegister(lir->input());
885 0 : Register temp = ToRegister(lir->temp());
886 :
887 : // Load the incoming ObjectGroup in temp.
888 0 : masm.loadPtr(Address(input, JSObject::offsetOfGroup()), temp);
889 :
890 : // Compare ObjectGroups.
891 0 : MacroAssembler::BranchGCPtr lastBranch;
892 0 : LBlock* lastBlock = nullptr;
893 0 : InlinePropertyTable* propTable = mir->propTable();
894 0 : for (size_t i = 0; i < mir->numCases(); i++) {
895 0 : JSFunction* func = mir->getCase(i);
896 0 : LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
897 :
898 0 : DebugOnly<bool> found = false;
899 0 : for (size_t j = 0; j < propTable->numEntries(); j++) {
900 0 : if (propTable->getFunction(j) != func)
901 0 : continue;
902 :
903 0 : if (lastBranch.isInitialized())
904 0 : lastBranch.emit(masm);
905 :
906 0 : ObjectGroup* group = propTable->getObjectGroup(j);
907 0 : lastBranch = MacroAssembler::BranchGCPtr(Assembler::Equal, temp, ImmGCPtr(group),
908 0 : target->label());
909 0 : lastBlock = target;
910 0 : found = true;
911 : }
912 0 : MOZ_ASSERT(found);
913 : }
914 :
915 : // Jump to fallback block if we have an unknown ObjectGroup. If there's no
916 : // fallback block, we should have handled all cases.
917 :
918 0 : if (!mir->hasFallback()) {
919 0 : MOZ_ASSERT(lastBranch.isInitialized());
920 : #ifdef DEBUG
921 0 : Label ok;
922 0 : lastBranch.relink(&ok);
923 0 : lastBranch.emit(masm);
924 0 : masm.assumeUnreachable("Unexpected ObjectGroup");
925 0 : masm.bind(&ok);
926 : #endif
927 0 : if (!isNextBlock(lastBlock))
928 0 : masm.jump(lastBlock->label());
929 0 : return;
930 : }
931 :
932 0 : LBlock* fallback = skipTrivialBlocks(mir->getFallback())->lir();
933 0 : if (!lastBranch.isInitialized()) {
934 0 : if (!isNextBlock(fallback))
935 0 : masm.jump(fallback->label());
936 0 : return;
937 : }
938 :
939 0 : lastBranch.invertCondition();
940 0 : lastBranch.relink(fallback->label());
941 0 : lastBranch.emit(masm);
942 :
943 0 : if (!isNextBlock(lastBlock))
944 0 : masm.jump(lastBlock->label());
945 : }
946 :
947 : void
948 0 : CodeGenerator::visitBooleanToString(LBooleanToString* lir)
949 : {
950 0 : Register input = ToRegister(lir->input());
951 0 : Register output = ToRegister(lir->output());
952 0 : const JSAtomState& names = GetJitContext()->runtime->names();
953 0 : Label true_, done;
954 :
955 0 : masm.branchTest32(Assembler::NonZero, input, input, &true_);
956 0 : masm.movePtr(ImmGCPtr(names.false_), output);
957 0 : masm.jump(&done);
958 :
959 0 : masm.bind(&true_);
960 0 : masm.movePtr(ImmGCPtr(names.true_), output);
961 :
962 0 : masm.bind(&done);
963 0 : }
964 :
965 : void
966 0 : CodeGenerator::emitIntToString(Register input, Register output, Label* ool)
967 : {
968 0 : masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
969 :
970 : // Fast path for small integers.
971 0 : masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().intStaticTable), output);
972 0 : masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
973 0 : }
974 :
975 : typedef JSFlatString* (*IntToStringFn)(JSContext*, int);
976 3 : static const VMFunction IntToStringInfo =
977 6 : FunctionInfo<IntToStringFn>(Int32ToString<CanGC>, "Int32ToString");
978 :
979 : void
980 0 : CodeGenerator::visitIntToString(LIntToString* lir)
981 : {
982 0 : Register input = ToRegister(lir->input());
983 0 : Register output = ToRegister(lir->output());
984 :
985 0 : OutOfLineCode* ool = oolCallVM(IntToStringInfo, lir, ArgList(input),
986 0 : StoreRegisterTo(output));
987 :
988 0 : emitIntToString(input, output, ool->entry());
989 :
990 0 : masm.bind(ool->rejoin());
991 0 : }
992 :
993 : typedef JSString* (*DoubleToStringFn)(JSContext*, double);
994 3 : static const VMFunction DoubleToStringInfo =
995 6 : FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>, "NumberToString");
996 :
997 : void
998 0 : CodeGenerator::visitDoubleToString(LDoubleToString* lir)
999 : {
1000 0 : FloatRegister input = ToFloatRegister(lir->input());
1001 0 : Register temp = ToRegister(lir->tempInt());
1002 0 : Register output = ToRegister(lir->output());
1003 :
1004 0 : OutOfLineCode* ool = oolCallVM(DoubleToStringInfo, lir, ArgList(input),
1005 0 : StoreRegisterTo(output));
1006 :
1007 : // Try double to integer conversion and run integer to string code.
1008 0 : masm.convertDoubleToInt32(input, temp, ool->entry(), true);
1009 0 : emitIntToString(temp, output, ool->entry());
1010 :
1011 0 : masm.bind(ool->rejoin());
1012 0 : }
1013 :
1014 : typedef JSString* (*PrimitiveToStringFn)(JSContext*, HandleValue);
1015 3 : static const VMFunction PrimitiveToStringInfo =
1016 6 : FunctionInfo<PrimitiveToStringFn>(ToStringSlow, "ToStringSlow");
1017 :
1018 : void
1019 4 : CodeGenerator::visitValueToString(LValueToString* lir)
1020 : {
1021 4 : ValueOperand input = ToValue(lir, LValueToString::Input);
1022 4 : Register output = ToRegister(lir->output());
1023 :
1024 8 : OutOfLineCode* ool = oolCallVM(PrimitiveToStringInfo, lir, ArgList(input),
1025 12 : StoreRegisterTo(output));
1026 :
1027 8 : Label done;
1028 4 : Register tag = masm.splitTagForTest(input);
1029 4 : const JSAtomState& names = GetJitContext()->runtime->names();
1030 :
1031 : // String
1032 4 : if (lir->mir()->input()->mightBeType(MIRType::String)) {
1033 8 : Label notString;
1034 4 : masm.branchTestString(Assembler::NotEqual, tag, ¬String);
1035 4 : masm.unboxString(input, output);
1036 4 : masm.jump(&done);
1037 4 : masm.bind(¬String);
1038 : }
1039 :
1040 : // Integer
1041 4 : if (lir->mir()->input()->mightBeType(MIRType::Int32)) {
1042 0 : Label notInteger;
1043 0 : masm.branchTestInt32(Assembler::NotEqual, tag, ¬Integer);
1044 0 : Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
1045 0 : unboxed = masm.extractInt32(input, unboxed);
1046 0 : emitIntToString(unboxed, output, ool->entry());
1047 0 : masm.jump(&done);
1048 0 : masm.bind(¬Integer);
1049 : }
1050 :
1051 : // Double
1052 4 : if (lir->mir()->input()->mightBeType(MIRType::Double)) {
1053 : // Note: no fastpath. Need two extra registers and can only convert doubles
1054 : // that fit integers and are smaller than StaticStrings::INT_STATIC_LIMIT.
1055 0 : masm.branchTestDouble(Assembler::Equal, tag, ool->entry());
1056 : }
1057 :
1058 : // Undefined
1059 4 : if (lir->mir()->input()->mightBeType(MIRType::Undefined)) {
1060 8 : Label notUndefined;
1061 4 : masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined);
1062 4 : masm.movePtr(ImmGCPtr(names.undefined), output);
1063 4 : masm.jump(&done);
1064 4 : masm.bind(¬Undefined);
1065 : }
1066 :
1067 : // Null
1068 4 : if (lir->mir()->input()->mightBeType(MIRType::Null)) {
1069 0 : Label notNull;
1070 0 : masm.branchTestNull(Assembler::NotEqual, tag, ¬Null);
1071 0 : masm.movePtr(ImmGCPtr(names.null), output);
1072 0 : masm.jump(&done);
1073 0 : masm.bind(¬Null);
1074 : }
1075 :
1076 : // Boolean
1077 4 : if (lir->mir()->input()->mightBeType(MIRType::Boolean)) {
1078 0 : Label notBoolean, true_;
1079 0 : masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
1080 0 : masm.branchTestBooleanTruthy(true, input, &true_);
1081 0 : masm.movePtr(ImmGCPtr(names.false_), output);
1082 0 : masm.jump(&done);
1083 0 : masm.bind(&true_);
1084 0 : masm.movePtr(ImmGCPtr(names.true_), output);
1085 0 : masm.jump(&done);
1086 0 : masm.bind(¬Boolean);
1087 : }
1088 :
1089 : // Object
1090 4 : if (lir->mir()->input()->mightBeType(MIRType::Object)) {
1091 : // Bail.
1092 0 : MOZ_ASSERT(lir->mir()->fallible());
1093 0 : Label bail;
1094 0 : masm.branchTestObject(Assembler::Equal, tag, &bail);
1095 0 : bailoutFrom(&bail, lir->snapshot());
1096 : }
1097 :
1098 : // Symbol
1099 4 : if (lir->mir()->input()->mightBeType(MIRType::Symbol)) {
1100 : // Bail.
1101 0 : MOZ_ASSERT(lir->mir()->fallible());
1102 0 : Label bail;
1103 0 : masm.branchTestSymbol(Assembler::Equal, tag, &bail);
1104 0 : bailoutFrom(&bail, lir->snapshot());
1105 : }
1106 :
1107 : #ifdef DEBUG
1108 4 : masm.assumeUnreachable("Unexpected type for MValueToString.");
1109 : #endif
1110 :
1111 4 : masm.bind(&done);
1112 4 : masm.bind(ool->rejoin());
1113 4 : }
1114 :
1115 : typedef JSObject* (*ToObjectFn)(JSContext*, HandleValue, bool);
1116 3 : static const VMFunction ToObjectInfo =
1117 6 : FunctionInfo<ToObjectFn>(ToObjectSlow, "ToObjectSlow");
1118 :
1119 : void
1120 0 : CodeGenerator::visitValueToObjectOrNull(LValueToObjectOrNull* lir)
1121 : {
1122 0 : ValueOperand input = ToValue(lir, LValueToObjectOrNull::Input);
1123 0 : Register output = ToRegister(lir->output());
1124 :
1125 0 : OutOfLineCode* ool = oolCallVM(ToObjectInfo, lir, ArgList(input, Imm32(0)),
1126 0 : StoreRegisterTo(output));
1127 :
1128 0 : Label done;
1129 0 : masm.branchTestObject(Assembler::Equal, input, &done);
1130 0 : masm.branchTestNull(Assembler::NotEqual, input, ool->entry());
1131 :
1132 0 : masm.bind(&done);
1133 0 : masm.unboxNonDouble(input, output);
1134 :
1135 0 : masm.bind(ool->rejoin());
1136 0 : }
1137 :
1138 : typedef JSObject* (*CloneRegExpObjectFn)(JSContext*, Handle<RegExpObject*>);
1139 3 : static const VMFunction CloneRegExpObjectInfo =
1140 6 : FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject, "CloneRegExpObject");
1141 :
1142 : void
1143 0 : CodeGenerator::visitRegExp(LRegExp* lir)
1144 : {
1145 0 : Register output = ToRegister(lir->output());
1146 0 : Register temp = ToRegister(lir->temp());
1147 0 : JSObject* templateObject = lir->mir()->source();
1148 :
1149 0 : OutOfLineCode *ool = oolCallVM(CloneRegExpObjectInfo, lir, ArgList(ImmGCPtr(lir->mir()->source())),
1150 0 : StoreRegisterTo(output));
1151 0 : if (lir->mir()->hasShared())
1152 0 : masm.createGCObject(output, temp, templateObject, gc::DefaultHeap, ool->entry());
1153 : else
1154 0 : masm.jump(ool->entry());
1155 0 : masm.bind(ool->rejoin());
1156 0 : }
1157 :
1158 : // Amount of space to reserve on the stack when executing RegExps inline.
1159 : static const size_t RegExpReservedStack = sizeof(irregexp::InputOutputData)
1160 : + sizeof(MatchPairs)
1161 : + RegExpObject::MaxPairCount * sizeof(MatchPair);
1162 :
1163 : static size_t
1164 0 : RegExpPairsVectorStartOffset(size_t inputOutputDataStartOffset)
1165 : {
1166 0 : return inputOutputDataStartOffset + sizeof(irregexp::InputOutputData) + sizeof(MatchPairs);
1167 : }
1168 :
1169 : static Address
1170 0 : RegExpPairCountAddress(MacroAssembler& masm, size_t inputOutputDataStartOffset)
1171 : {
1172 0 : return Address(masm.getStackPointer(), inputOutputDataStartOffset
1173 : + sizeof(irregexp::InputOutputData)
1174 0 : + MatchPairs::offsetOfPairCount());
1175 : }
1176 :
1177 : // Prepare an InputOutputData and optional MatchPairs which space has been
1178 : // allocated for on the stack, and try to execute a RegExp on a string input.
1179 : // If the RegExp was successfully executed and matched the input, fallthrough,
1180 : // otherwise jump to notFound or failure.
1181 : static bool
1182 0 : PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Register input,
1183 : Register lastIndex,
1184 : Register temp1, Register temp2, Register temp3,
1185 : size_t inputOutputDataStartOffset,
1186 : RegExpShared::CompilationMode mode,
1187 : Label* notFound, Label* failure)
1188 : {
1189 0 : size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
1190 0 : size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
1191 :
1192 : Address inputStartAddress(masm.getStackPointer(),
1193 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputStart));
1194 : Address inputEndAddress(masm.getStackPointer(),
1195 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputEnd));
1196 : Address matchesPointerAddress(masm.getStackPointer(),
1197 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, matches));
1198 : Address startIndexAddress(masm.getStackPointer(),
1199 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, startIndex));
1200 : Address endIndexAddress(masm.getStackPointer(),
1201 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, endIndex));
1202 : Address matchResultAddress(masm.getStackPointer(),
1203 0 : inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, result));
1204 :
1205 0 : Address pairCountAddress = RegExpPairCountAddress(masm, inputOutputDataStartOffset);
1206 : Address pairsPointerAddress(masm.getStackPointer(),
1207 0 : matchPairsStartOffset + MatchPairs::offsetOfPairs());
1208 :
1209 0 : Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset);
1210 :
1211 0 : RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global());
1212 0 : if (!res)
1213 0 : return false;
1214 : #ifdef JS_USE_LINK_REGISTER
1215 : if (mode != RegExpShared::MatchOnly)
1216 : masm.pushReturnAddress();
1217 : #endif
1218 0 : if (mode == RegExpShared::Normal) {
1219 : // First, fill in a skeletal MatchPairs instance on the stack. This will be
1220 : // passed to the OOL stub in the caller if we aren't able to execute the
1221 : // RegExp inline, and that stub needs to be able to determine whether the
1222 : // execution finished successfully.
1223 0 : masm.store32(Imm32(1), pairCountAddress);
1224 0 : masm.store32(Imm32(-1), pairsVectorAddress);
1225 0 : masm.computeEffectiveAddress(pairsVectorAddress, temp1);
1226 0 : masm.storePtr(temp1, pairsPointerAddress);
1227 : }
1228 :
1229 : // Check for a linear input string.
1230 0 : masm.branchIfRopeOrExternal(input, temp1, failure);
1231 :
1232 : // Get the RegExpShared for the RegExp.
1233 0 : masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp1);
1234 0 : masm.branchPtr(Assembler::Equal, temp1, ImmWord(0), failure);
1235 :
1236 : // ES6 21.2.2.2 step 2.
1237 : // See RegExp.cpp ExecuteRegExp for more detail.
1238 : {
1239 0 : Label done;
1240 :
1241 0 : masm.branchTest32(Assembler::Zero, Address(temp1, RegExpShared::offsetOfFlags()),
1242 0 : Imm32(UnicodeFlag), &done);
1243 :
1244 : // If input is latin1, there should not be surrogate pair.
1245 0 : masm.branchLatin1String(input, &done);
1246 :
1247 : // Check if |lastIndex > 0 && lastIndex < input->length()|.
1248 : // lastIndex should already have no sign here.
1249 0 : masm.branchTest32(Assembler::Zero, lastIndex, lastIndex, &done);
1250 0 : masm.loadStringLength(input, temp2);
1251 0 : masm.branch32(Assembler::AboveOrEqual, lastIndex, temp2, &done);
1252 :
1253 : // Check if input[lastIndex] is trail surrogate.
1254 0 : masm.loadStringChars(input, temp2);
1255 0 : masm.computeEffectiveAddress(BaseIndex(temp2, lastIndex, TimesTwo), temp3);
1256 0 : masm.load16ZeroExtend(Address(temp3, 0), temp3);
1257 :
1258 0 : masm.branch32(Assembler::Below, temp3, Imm32(unicode::TrailSurrogateMin), &done);
1259 0 : masm.branch32(Assembler::Above, temp3, Imm32(unicode::TrailSurrogateMax), &done);
1260 :
1261 : // Check if input[lastIndex-1] is lead surrogate.
1262 0 : masm.move32(lastIndex, temp3);
1263 0 : masm.sub32(Imm32(1), temp3);
1264 0 : masm.computeEffectiveAddress(BaseIndex(temp2, temp3, TimesTwo), temp3);
1265 0 : masm.load16ZeroExtend(Address(temp3, 0), temp3);
1266 :
1267 0 : masm.branch32(Assembler::Below, temp3, Imm32(unicode::LeadSurrogateMin), &done);
1268 0 : masm.branch32(Assembler::Above, temp3, Imm32(unicode::LeadSurrogateMax), &done);
1269 :
1270 : // Move lastIndex to lead surrogate.
1271 0 : masm.subPtr(Imm32(1), lastIndex);
1272 :
1273 0 : masm.bind(&done);
1274 : }
1275 :
1276 0 : if (mode == RegExpShared::Normal) {
1277 : // Don't handle RegExps with excessive parens.
1278 0 : masm.load32(Address(temp1, RegExpShared::offsetOfParenCount()), temp2);
1279 0 : masm.branch32(Assembler::AboveOrEqual, temp2, Imm32(RegExpObject::MaxPairCount), failure);
1280 :
1281 : // Fill in the paren count in the MatchPairs on the stack.
1282 0 : masm.add32(Imm32(1), temp2);
1283 0 : masm.store32(temp2, pairCountAddress);
1284 : }
1285 :
1286 : // Load the code pointer for the type of input string we have, and compute
1287 : // the input start/end pointers in the InputOutputData.
1288 0 : Register codePointer = temp1;
1289 : {
1290 0 : masm.loadStringChars(input, temp2);
1291 0 : masm.storePtr(temp2, inputStartAddress);
1292 0 : masm.loadStringLength(input, temp3);
1293 :
1294 0 : Label isLatin1, done;
1295 0 : masm.branchLatin1String(input, &isLatin1);
1296 : {
1297 0 : masm.lshiftPtr(Imm32(1), temp3);
1298 0 : masm.loadPtr(Address(temp1, RegExpShared::offsetOfTwoByteJitCode(mode)),
1299 0 : codePointer);
1300 : }
1301 0 : masm.jump(&done);
1302 : {
1303 0 : masm.bind(&isLatin1);
1304 0 : masm.loadPtr(Address(temp1, RegExpShared::offsetOfLatin1JitCode(mode)),
1305 0 : codePointer);
1306 : }
1307 0 : masm.bind(&done);
1308 :
1309 0 : masm.addPtr(temp3, temp2);
1310 0 : masm.storePtr(temp2, inputEndAddress);
1311 : }
1312 :
1313 : // Check the RegExpShared has been compiled for this type of input.
1314 0 : masm.branchPtr(Assembler::Equal, codePointer, ImmWord(0), failure);
1315 0 : masm.loadPtr(Address(codePointer, JitCode::offsetOfCode()), codePointer);
1316 :
1317 : // Finish filling in the InputOutputData instance on the stack.
1318 0 : if (mode == RegExpShared::Normal) {
1319 0 : masm.computeEffectiveAddress(Address(masm.getStackPointer(), matchPairsStartOffset), temp2);
1320 0 : masm.storePtr(temp2, matchesPointerAddress);
1321 : } else {
1322 : // Use InputOutputData.endIndex itself for output.
1323 0 : masm.computeEffectiveAddress(endIndexAddress, temp2);
1324 0 : masm.storePtr(temp2, endIndexAddress);
1325 : }
1326 0 : masm.storePtr(lastIndex, startIndexAddress);
1327 0 : masm.store32(Imm32(0), matchResultAddress);
1328 :
1329 : // Save any volatile inputs.
1330 0 : LiveGeneralRegisterSet volatileRegs;
1331 0 : if (lastIndex.volatile_())
1332 0 : volatileRegs.add(lastIndex);
1333 0 : if (input.volatile_())
1334 0 : volatileRegs.add(input);
1335 0 : if (regexp.volatile_())
1336 0 : volatileRegs.add(regexp);
1337 :
1338 : #ifdef JS_TRACE_LOGGING
1339 0 : if (TraceLogTextIdEnabled(TraceLogger_IrregexpExecute)) {
1340 0 : masm.push(temp1);
1341 0 : masm.loadTraceLogger(temp1);
1342 0 : masm.tracelogStartId(temp1, TraceLogger_IrregexpExecute);
1343 0 : masm.pop(temp1);
1344 : }
1345 : #endif
1346 :
1347 : // Execute the RegExp.
1348 0 : masm.computeEffectiveAddress(Address(masm.getStackPointer(), inputOutputDataStartOffset), temp2);
1349 0 : masm.PushRegsInMask(volatileRegs);
1350 0 : masm.setupUnalignedABICall(temp3);
1351 0 : masm.passABIArg(temp2);
1352 0 : masm.callWithABI(codePointer);
1353 0 : masm.PopRegsInMask(volatileRegs);
1354 :
1355 : #ifdef JS_TRACE_LOGGING
1356 0 : if (TraceLogTextIdEnabled(TraceLogger_IrregexpExecute)) {
1357 0 : masm.loadTraceLogger(temp1);
1358 0 : masm.tracelogStopId(temp1, TraceLogger_IrregexpExecute);
1359 : }
1360 : #endif
1361 :
1362 0 : Label success;
1363 0 : masm.branch32(Assembler::Equal, matchResultAddress,
1364 0 : Imm32(RegExpRunStatus_Success_NotFound), notFound);
1365 0 : masm.branch32(Assembler::Equal, matchResultAddress,
1366 0 : Imm32(RegExpRunStatus_Error), failure);
1367 :
1368 : // Lazily update the RegExpStatics.
1369 0 : masm.movePtr(ImmPtr(res), temp1);
1370 :
1371 0 : Address pendingInputAddress(temp1, RegExpStatics::offsetOfPendingInput());
1372 0 : Address matchesInputAddress(temp1, RegExpStatics::offsetOfMatchesInput());
1373 0 : Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource());
1374 0 : Address lazyIndexAddress(temp1, RegExpStatics::offsetOfLazyIndex());
1375 :
1376 0 : masm.guardedCallPreBarrier(pendingInputAddress, MIRType::String);
1377 0 : masm.guardedCallPreBarrier(matchesInputAddress, MIRType::String);
1378 0 : masm.guardedCallPreBarrier(lazySourceAddress, MIRType::String);
1379 :
1380 0 : masm.storePtr(input, pendingInputAddress);
1381 0 : masm.storePtr(input, matchesInputAddress);
1382 0 : masm.storePtr(lastIndex, Address(temp1, RegExpStatics::offsetOfLazyIndex()));
1383 0 : masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
1384 :
1385 0 : masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp2);
1386 0 : masm.loadPtr(Address(temp2, RegExpShared::offsetOfSource()), temp3);
1387 0 : masm.storePtr(temp3, lazySourceAddress);
1388 0 : masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3);
1389 0 : masm.store32(temp3, Address(temp1, RegExpStatics::offsetOfLazyFlags()));
1390 :
1391 0 : if (mode == RegExpShared::MatchOnly) {
1392 : // endIndex is passed via temp3.
1393 0 : masm.load32(endIndexAddress, temp3);
1394 : }
1395 :
1396 0 : return true;
1397 : }
1398 :
1399 : static void
1400 : CopyStringChars(MacroAssembler& masm, Register to, Register from, Register len,
1401 : Register byteOpScratch, size_t fromWidth, size_t toWidth);
1402 :
1403 0 : class CreateDependentString
1404 : {
1405 : Register string_;
1406 : Register temp_;
1407 : Label* failure_;
1408 : enum class FallbackKind : uint8_t {
1409 : InlineString,
1410 : FatInlineString,
1411 : NotInlineString,
1412 : Count
1413 : };
1414 : mozilla::EnumeratedArray<FallbackKind, FallbackKind::Count, Label> fallbacks_, joins_;
1415 :
1416 : public:
1417 : // Generate code that creates DependentString.
1418 : // Caller should call generateFallback after masm.ret(), to generate
1419 : // fallback path.
1420 : void generate(MacroAssembler& masm, const JSAtomState& names,
1421 : bool latin1, Register string,
1422 : Register base, Register temp1, Register temp2,
1423 : BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
1424 : Label* failure);
1425 :
1426 : // Generate fallback path for creating DependentString.
1427 : void generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave);
1428 : };
1429 :
1430 : void
1431 0 : CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
1432 : bool latin1, Register string,
1433 : Register base, Register temp1, Register temp2,
1434 : BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
1435 : Label* failure)
1436 : {
1437 0 : string_ = string;
1438 0 : temp_ = temp2;
1439 0 : failure_ = failure;
1440 :
1441 : // Compute the string length.
1442 0 : masm.load32(startIndexAddress, temp2);
1443 0 : masm.load32(limitIndexAddress, temp1);
1444 0 : masm.sub32(temp2, temp1);
1445 :
1446 0 : Label done, nonEmpty;
1447 :
1448 : // Zero length matches use the empty string.
1449 0 : masm.branchTest32(Assembler::NonZero, temp1, temp1, &nonEmpty);
1450 0 : masm.movePtr(ImmGCPtr(names.empty), string);
1451 0 : masm.jump(&done);
1452 :
1453 0 : masm.bind(&nonEmpty);
1454 :
1455 0 : Label notInline;
1456 :
1457 : int32_t maxInlineLength = latin1
1458 0 : ? (int32_t) JSFatInlineString::MAX_LENGTH_LATIN1
1459 0 : : (int32_t) JSFatInlineString::MAX_LENGTH_TWO_BYTE;
1460 0 : masm.branch32(Assembler::Above, temp1, Imm32(maxInlineLength), ¬Inline);
1461 :
1462 : {
1463 : // Make a thin or fat inline string.
1464 0 : Label stringAllocated, fatInline;
1465 :
1466 : int32_t maxThinInlineLength = latin1
1467 0 : ? (int32_t) JSThinInlineString::MAX_LENGTH_LATIN1
1468 0 : : (int32_t) JSThinInlineString::MAX_LENGTH_TWO_BYTE;
1469 0 : masm.branch32(Assembler::Above, temp1, Imm32(maxThinInlineLength), &fatInline);
1470 :
1471 0 : int32_t thinFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_THIN_INLINE_FLAGS;
1472 0 : masm.newGCString(string, temp2, &fallbacks_[FallbackKind::InlineString]);
1473 0 : masm.bind(&joins_[FallbackKind::InlineString]);
1474 0 : masm.store32(Imm32(thinFlags), Address(string, JSString::offsetOfFlags()));
1475 0 : masm.jump(&stringAllocated);
1476 :
1477 0 : masm.bind(&fatInline);
1478 :
1479 0 : int32_t fatFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_FAT_INLINE_FLAGS;
1480 0 : masm.newGCFatInlineString(string, temp2, &fallbacks_[FallbackKind::FatInlineString]);
1481 0 : masm.bind(&joins_[FallbackKind::FatInlineString]);
1482 0 : masm.store32(Imm32(fatFlags), Address(string, JSString::offsetOfFlags()));
1483 :
1484 0 : masm.bind(&stringAllocated);
1485 0 : masm.store32(temp1, Address(string, JSString::offsetOfLength()));
1486 :
1487 0 : masm.push(string);
1488 0 : masm.push(base);
1489 :
1490 : // Adjust the start index address for the above pushes.
1491 0 : MOZ_ASSERT(startIndexAddress.base == masm.getStackPointer());
1492 0 : BaseIndex newStartIndexAddress = startIndexAddress;
1493 0 : newStartIndexAddress.offset += 2 * sizeof(void*);
1494 :
1495 : // Load chars pointer for the new string.
1496 0 : masm.addPtr(ImmWord(JSInlineString::offsetOfInlineStorage()), string);
1497 :
1498 : // Load the source characters pointer.
1499 0 : masm.loadStringChars(base, base);
1500 0 : masm.load32(newStartIndexAddress, temp2);
1501 0 : if (latin1)
1502 0 : masm.addPtr(temp2, base);
1503 : else
1504 0 : masm.computeEffectiveAddress(BaseIndex(base, temp2, TimesTwo), base);
1505 :
1506 0 : CopyStringChars(masm, string, base, temp1, temp2, latin1 ? 1 : 2, latin1 ? 1 : 2);
1507 :
1508 : // Null-terminate.
1509 0 : if (latin1)
1510 0 : masm.store8(Imm32(0), Address(string, 0));
1511 : else
1512 0 : masm.store16(Imm32(0), Address(string, 0));
1513 :
1514 0 : masm.pop(base);
1515 0 : masm.pop(string);
1516 : }
1517 :
1518 0 : masm.jump(&done);
1519 0 : masm.bind(¬Inline);
1520 :
1521 : {
1522 : // Make a dependent string.
1523 0 : int32_t flags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::DEPENDENT_FLAGS;
1524 :
1525 0 : masm.newGCString(string, temp2, &fallbacks_[FallbackKind::NotInlineString]);
1526 0 : masm.bind(&joins_[FallbackKind::NotInlineString]);
1527 0 : masm.store32(Imm32(flags), Address(string, JSString::offsetOfFlags()));
1528 0 : masm.store32(temp1, Address(string, JSString::offsetOfLength()));
1529 :
1530 0 : masm.loadPtr(Address(base, JSString::offsetOfNonInlineChars()), temp1);
1531 0 : masm.load32(startIndexAddress, temp2);
1532 0 : if (latin1)
1533 0 : masm.addPtr(temp2, temp1);
1534 : else
1535 0 : masm.computeEffectiveAddress(BaseIndex(temp1, temp2, TimesTwo), temp1);
1536 0 : masm.storePtr(temp1, Address(string, JSString::offsetOfNonInlineChars()));
1537 0 : masm.storePtr(base, Address(string, JSDependentString::offsetOfBase()));
1538 :
1539 : // Follow any base pointer if the input is itself a dependent string.
1540 : // Watch for undepended strings, which have a base pointer but don't
1541 : // actually share their characters with it.
1542 0 : Label noBase;
1543 0 : masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
1544 0 : Imm32(JSString::HAS_BASE_BIT), &noBase);
1545 0 : masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
1546 0 : Imm32(JSString::FLAT_BIT), &noBase);
1547 0 : masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
1548 0 : masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
1549 0 : masm.bind(&noBase);
1550 : }
1551 :
1552 0 : masm.bind(&done);
1553 0 : }
1554 :
1555 : static void*
1556 0 : AllocateString(JSContext* cx)
1557 : {
1558 0 : return js::Allocate<JSString, NoGC>(cx);
1559 : }
1560 :
1561 : static void*
1562 0 : AllocateFatInlineString(JSContext* cx)
1563 : {
1564 0 : return js::Allocate<JSFatInlineString, NoGC>(cx);
1565 : }
1566 :
1567 : void
1568 0 : CreateDependentString::generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave)
1569 : {
1570 0 : regsToSave.take(string_);
1571 0 : regsToSave.take(temp_);
1572 0 : for (FallbackKind kind : mozilla::MakeEnumeratedRange(FallbackKind::Count)) {
1573 0 : masm.bind(&fallbacks_[kind]);
1574 :
1575 0 : masm.PushRegsInMask(regsToSave);
1576 :
1577 0 : masm.setupUnalignedABICall(string_);
1578 0 : masm.loadJSContext(string_);
1579 0 : masm.passABIArg(string_);
1580 : masm.callWithABI(kind == FallbackKind::FatInlineString
1581 0 : ? JS_FUNC_TO_DATA_PTR(void*, AllocateFatInlineString)
1582 0 : : JS_FUNC_TO_DATA_PTR(void*, AllocateString));
1583 0 : masm.storeCallWordResult(string_);
1584 :
1585 0 : masm.PopRegsInMask(regsToSave);
1586 :
1587 0 : masm.branchPtr(Assembler::Equal, string_, ImmWord(0), failure_);
1588 :
1589 0 : masm.jump(&joins_[kind]);
1590 : }
1591 0 : }
1592 :
1593 : static void*
1594 0 : CreateMatchResultFallbackFunc(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots)
1595 : {
1596 : return js::Allocate<JSObject, NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
1597 0 : &ArrayObject::class_);
1598 : }
1599 :
1600 : static void
1601 0 : CreateMatchResultFallback(MacroAssembler& masm, LiveRegisterSet regsToSave,
1602 : Register object, Register temp2, Register temp5,
1603 : ArrayObject* templateObj, Label* fail)
1604 : {
1605 0 : MOZ_ASSERT(templateObj->group()->clasp() == &ArrayObject::class_);
1606 :
1607 0 : regsToSave.take(object);
1608 0 : regsToSave.take(temp2);
1609 0 : regsToSave.take(temp5);
1610 0 : masm.PushRegsInMask(regsToSave);
1611 :
1612 0 : masm.setupUnalignedABICall(object);
1613 :
1614 0 : masm.loadJSContext(object);
1615 0 : masm.passABIArg(object);
1616 0 : masm.move32(Imm32(int32_t(templateObj->asTenured().getAllocKind())), temp2);
1617 0 : masm.passABIArg(temp2);
1618 0 : masm.move32(Imm32(int32_t(templateObj->as<NativeObject>().numDynamicSlots())), temp5);
1619 0 : masm.passABIArg(temp5);
1620 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, CreateMatchResultFallbackFunc));
1621 0 : masm.storeCallWordResult(object);
1622 :
1623 0 : masm.PopRegsInMask(regsToSave);
1624 :
1625 0 : masm.branchPtr(Assembler::Equal, object, ImmWord(0), fail);
1626 :
1627 0 : masm.initGCThing(object, temp2, templateObj, true, false);
1628 0 : }
1629 :
1630 : JitCode*
1631 0 : JitCompartment::generateRegExpMatcherStub(JSContext* cx)
1632 : {
1633 0 : Register regexp = RegExpMatcherRegExpReg;
1634 0 : Register input = RegExpMatcherStringReg;
1635 0 : Register lastIndex = RegExpMatcherLastIndexReg;
1636 0 : ValueOperand result = JSReturnOperand;
1637 :
1638 : // We are free to clobber all registers, as LRegExpMatcher is a call instruction.
1639 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
1640 0 : regs.take(input);
1641 0 : regs.take(regexp);
1642 0 : regs.take(lastIndex);
1643 :
1644 : // temp5 is used in single byte instructions when creating dependent
1645 : // strings, and has restrictions on which register it can be on some
1646 : // platforms.
1647 0 : Register temp5;
1648 : {
1649 0 : AllocatableGeneralRegisterSet oregs = regs;
1650 0 : do {
1651 0 : temp5 = oregs.takeAny();
1652 0 : } while (!MacroAssembler::canUseInSingleByteInstruction(temp5));
1653 0 : regs.take(temp5);
1654 : }
1655 :
1656 0 : Register temp1 = regs.takeAny();
1657 0 : Register temp2 = regs.takeAny();
1658 0 : Register temp3 = regs.takeAny();
1659 :
1660 0 : Register maybeTemp4 = InvalidReg;
1661 0 : if (!regs.empty()) {
1662 : // There are not enough registers on x86.
1663 0 : maybeTemp4 = regs.takeAny();
1664 : }
1665 :
1666 0 : ArrayObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
1667 0 : if (!templateObject)
1668 0 : return nullptr;
1669 :
1670 : // The template object should have enough space for the maximum number of
1671 : // pairs this stub can handle.
1672 0 : MOZ_ASSERT(ObjectElements::VALUES_PER_HEADER + RegExpObject::MaxPairCount ==
1673 : gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()));
1674 :
1675 0 : MacroAssembler masm(cx);
1676 :
1677 : // The InputOutputData is placed above the return address on the stack.
1678 0 : size_t inputOutputDataStartOffset = sizeof(void*);
1679 :
1680 0 : Label notFound, oolEntry;
1681 0 : if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
1682 : temp1, temp2, temp5, inputOutputDataStartOffset,
1683 : RegExpShared::Normal, ¬Found, &oolEntry))
1684 : {
1685 0 : return nullptr;
1686 : }
1687 :
1688 : // Construct the result.
1689 0 : Register object = temp1;
1690 0 : Label matchResultFallback, matchResultJoin;
1691 0 : masm.createGCObject(object, temp2, templateObject, gc::DefaultHeap, &matchResultFallback);
1692 0 : masm.bind(&matchResultJoin);
1693 :
1694 : // Initialize slots of result object.
1695 0 : masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
1696 0 : masm.storeValue(templateObject->getSlot(0), Address(temp2, 0));
1697 0 : masm.storeValue(templateObject->getSlot(1), Address(temp2, sizeof(Value)));
1698 :
1699 0 : size_t elementsOffset = NativeObject::offsetOfFixedElements();
1700 :
1701 : #ifdef DEBUG
1702 : // Assert the initial value of initializedLength and length to make sure
1703 : // restoration on failure case works.
1704 : {
1705 0 : Label initLengthOK, lengthOK;
1706 0 : masm.branch32(Assembler::Equal,
1707 0 : Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()),
1708 0 : Imm32(templateObject->getDenseInitializedLength()),
1709 0 : &initLengthOK);
1710 0 : masm.assumeUnreachable("Initial value of the match object's initializedLength does not match to restoration.");
1711 0 : masm.bind(&initLengthOK);
1712 :
1713 0 : masm.branch32(Assembler::Equal,
1714 0 : Address(object, elementsOffset + ObjectElements::offsetOfLength()),
1715 0 : Imm32(templateObject->length()),
1716 0 : &lengthOK);
1717 0 : masm.assumeUnreachable("Initial value of The match object's length does not match to restoration.");
1718 0 : masm.bind(&lengthOK);
1719 : }
1720 : #endif
1721 :
1722 0 : Register matchIndex = temp2;
1723 0 : masm.move32(Imm32(0), matchIndex);
1724 :
1725 0 : size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
1726 0 : Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset);
1727 0 : Address pairCountAddress = RegExpPairCountAddress(masm, inputOutputDataStartOffset);
1728 :
1729 0 : BaseIndex stringAddress(object, matchIndex, TimesEight, elementsOffset);
1730 :
1731 : JS_STATIC_ASSERT(sizeof(MatchPair) == 8);
1732 : BaseIndex stringIndexAddress(masm.getStackPointer(), matchIndex, TimesEight,
1733 0 : pairsVectorStartOffset + offsetof(MatchPair, start));
1734 : BaseIndex stringLimitAddress(masm.getStackPointer(), matchIndex, TimesEight,
1735 0 : pairsVectorStartOffset + offsetof(MatchPair, limit));
1736 :
1737 : // Loop to construct the match strings. There are two different loops,
1738 : // depending on whether the input is latin1.
1739 0 : CreateDependentString depStr[2];
1740 : {
1741 0 : Label isLatin1, done;
1742 0 : masm.branchLatin1String(input, &isLatin1);
1743 :
1744 0 : Label* failure = &oolEntry;
1745 0 : Register temp4 = (maybeTemp4 == InvalidReg) ? lastIndex : maybeTemp4;
1746 :
1747 0 : Label failureRestore;
1748 0 : if (maybeTemp4 == InvalidReg) {
1749 0 : failure = &failureRestore;
1750 :
1751 : // Save lastIndex value to temporary space.
1752 0 : masm.store32(lastIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
1753 : }
1754 :
1755 0 : for (int isLatin = 0; isLatin <= 1; isLatin++) {
1756 0 : if (isLatin)
1757 0 : masm.bind(&isLatin1);
1758 :
1759 0 : Label matchLoop;
1760 0 : masm.bind(&matchLoop);
1761 :
1762 0 : Label isUndefined, storeDone;
1763 0 : masm.branch32(Assembler::LessThan, stringIndexAddress, Imm32(0), &isUndefined);
1764 :
1765 0 : depStr[isLatin].generate(masm, cx->names(), isLatin, temp3, input, temp4, temp5,
1766 0 : stringIndexAddress, stringLimitAddress, failure);
1767 :
1768 0 : masm.storeValue(JSVAL_TYPE_STRING, temp3, stringAddress);
1769 :
1770 0 : masm.jump(&storeDone);
1771 0 : masm.bind(&isUndefined);
1772 :
1773 0 : masm.storeValue(UndefinedValue(), stringAddress);
1774 0 : masm.bind(&storeDone);
1775 :
1776 0 : masm.add32(Imm32(1), matchIndex);
1777 0 : masm.branch32(Assembler::LessThanOrEqual, pairCountAddress, matchIndex, &done);
1778 0 : masm.jump(&matchLoop);
1779 : }
1780 :
1781 0 : if (maybeTemp4 == InvalidReg) {
1782 : // Restore lastIndex value from temporary space, both for success
1783 : // and failure cases.
1784 :
1785 0 : masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
1786 0 : masm.jump(&done);
1787 :
1788 0 : masm.bind(&failureRestore);
1789 0 : masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
1790 :
1791 : // Restore the match object for failure case.
1792 0 : masm.store32(Imm32(templateObject->getDenseInitializedLength()),
1793 0 : Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
1794 0 : masm.store32(Imm32(templateObject->length()),
1795 0 : Address(object, elementsOffset + ObjectElements::offsetOfLength()));
1796 0 : masm.jump(&oolEntry);
1797 : }
1798 :
1799 0 : masm.bind(&done);
1800 : }
1801 :
1802 : // Fill in the rest of the output object.
1803 0 : masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
1804 0 : masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
1805 :
1806 0 : masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
1807 :
1808 0 : MOZ_ASSERT(templateObject->numFixedSlots() == 0);
1809 0 : MOZ_ASSERT(templateObject->lookupPure(cx->names().index)->slot() == 0);
1810 0 : MOZ_ASSERT(templateObject->lookupPure(cx->names().input)->slot() == 1);
1811 :
1812 0 : masm.load32(pairsVectorAddress, temp3);
1813 0 : masm.storeValue(JSVAL_TYPE_INT32, temp3, Address(temp2, 0));
1814 0 : masm.storeValue(JSVAL_TYPE_STRING, input, Address(temp2, sizeof(Value)));
1815 :
1816 : // All done!
1817 0 : masm.tagValue(JSVAL_TYPE_OBJECT, object, result);
1818 0 : masm.ret();
1819 :
1820 0 : masm.bind(¬Found);
1821 0 : masm.moveValue(NullValue(), result);
1822 0 : masm.ret();
1823 :
1824 : // Fallback paths for CreateDependentString and createGCObject.
1825 : // Need to save all registers in use when they were called.
1826 0 : LiveRegisterSet regsToSave(RegisterSet::Volatile());
1827 0 : regsToSave.addUnchecked(regexp);
1828 0 : regsToSave.addUnchecked(input);
1829 0 : regsToSave.addUnchecked(lastIndex);
1830 0 : regsToSave.addUnchecked(temp1);
1831 0 : regsToSave.addUnchecked(temp2);
1832 0 : regsToSave.addUnchecked(temp3);
1833 0 : if (maybeTemp4 != InvalidReg)
1834 0 : regsToSave.addUnchecked(maybeTemp4);
1835 0 : regsToSave.addUnchecked(temp5);
1836 :
1837 0 : for (int isLatin = 0; isLatin <= 1; isLatin++)
1838 0 : depStr[isLatin].generateFallback(masm, regsToSave);
1839 :
1840 0 : masm.bind(&matchResultFallback);
1841 0 : CreateMatchResultFallback(masm, regsToSave, object, temp2, temp5, templateObject, &oolEntry);
1842 0 : masm.jump(&matchResultJoin);
1843 :
1844 : // Use an undefined value to signal to the caller that the OOL stub needs to be called.
1845 0 : masm.bind(&oolEntry);
1846 0 : masm.moveValue(UndefinedValue(), result);
1847 0 : masm.ret();
1848 :
1849 0 : Linker linker(masm);
1850 0 : AutoFlushICache afc("RegExpMatcherStub");
1851 0 : JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
1852 0 : if (!code)
1853 0 : return nullptr;
1854 :
1855 : #ifdef JS_ION_PERF
1856 : writePerfSpewerJitCodeProfile(code, "RegExpMatcherStub");
1857 : #endif
1858 : #ifdef MOZ_VTUNE
1859 0 : vtune::MarkStub(code, "RegExpMatcherStub");
1860 : #endif
1861 :
1862 0 : return code;
1863 : }
1864 :
1865 : class OutOfLineRegExpMatcher : public OutOfLineCodeBase<CodeGenerator>
1866 : {
1867 : LRegExpMatcher* lir_;
1868 :
1869 : public:
1870 0 : explicit OutOfLineRegExpMatcher(LRegExpMatcher* lir)
1871 0 : : lir_(lir)
1872 0 : { }
1873 :
1874 0 : void accept(CodeGenerator* codegen) {
1875 0 : codegen->visitOutOfLineRegExpMatcher(this);
1876 0 : }
1877 :
1878 0 : LRegExpMatcher* lir() const {
1879 0 : return lir_;
1880 : }
1881 : };
1882 :
1883 : typedef bool (*RegExpMatcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
1884 : int32_t lastIndex,
1885 : MatchPairs* pairs, MutableHandleValue output);
1886 3 : static const VMFunction RegExpMatcherRawInfo =
1887 6 : FunctionInfo<RegExpMatcherRawFn>(RegExpMatcherRaw, "RegExpMatcherRaw");
1888 :
1889 : void
1890 0 : CodeGenerator::visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool)
1891 : {
1892 0 : LRegExpMatcher* lir = ool->lir();
1893 0 : Register lastIndex = ToRegister(lir->lastIndex());
1894 0 : Register input = ToRegister(lir->string());
1895 0 : Register regexp = ToRegister(lir->regexp());
1896 :
1897 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
1898 0 : regs.take(lastIndex);
1899 0 : regs.take(input);
1900 0 : regs.take(regexp);
1901 0 : Register temp = regs.takeAny();
1902 :
1903 0 : masm.computeEffectiveAddress(Address(masm.getStackPointer(),
1904 0 : sizeof(irregexp::InputOutputData)), temp);
1905 :
1906 0 : pushArg(temp);
1907 0 : pushArg(lastIndex);
1908 0 : pushArg(input);
1909 0 : pushArg(regexp);
1910 :
1911 : // We are not using oolCallVM because we are in a Call, and that live
1912 : // registers are already saved by the the register allocator.
1913 0 : callVM(RegExpMatcherRawInfo, lir);
1914 :
1915 0 : masm.jump(ool->rejoin());
1916 0 : }
1917 :
1918 : void
1919 0 : CodeGenerator::visitRegExpMatcher(LRegExpMatcher* lir)
1920 : {
1921 0 : MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpMatcherRegExpReg);
1922 0 : MOZ_ASSERT(ToRegister(lir->string()) == RegExpMatcherStringReg);
1923 0 : MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpMatcherLastIndexReg);
1924 0 : MOZ_ASSERT(GetValueOutput(lir) == JSReturnOperand);
1925 :
1926 : #if defined(JS_NUNBOX32)
1927 : MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Type);
1928 : MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Data);
1929 : MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Type);
1930 : MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Data);
1931 : MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Type);
1932 : MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Data);
1933 : #elif defined(JS_PUNBOX64)
1934 0 : MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg);
1935 0 : MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg);
1936 0 : MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg);
1937 : #endif
1938 :
1939 0 : masm.reserveStack(RegExpReservedStack);
1940 :
1941 0 : OutOfLineRegExpMatcher* ool = new(alloc()) OutOfLineRegExpMatcher(lir);
1942 0 : addOutOfLineCode(ool, lir->mir());
1943 :
1944 0 : JitCode* regExpMatcherStub = gen->compartment->jitCompartment()->regExpMatcherStubNoBarrier();
1945 0 : masm.call(regExpMatcherStub);
1946 0 : masm.branchTestUndefined(Assembler::Equal, JSReturnOperand, ool->entry());
1947 0 : masm.bind(ool->rejoin());
1948 :
1949 0 : masm.freeStack(RegExpReservedStack);
1950 0 : }
1951 :
1952 : static const int32_t RegExpSearcherResultNotFound = -1;
1953 : static const int32_t RegExpSearcherResultFailed = -2;
1954 :
1955 : JitCode*
1956 0 : JitCompartment::generateRegExpSearcherStub(JSContext* cx)
1957 : {
1958 0 : Register regexp = RegExpTesterRegExpReg;
1959 0 : Register input = RegExpTesterStringReg;
1960 0 : Register lastIndex = RegExpTesterLastIndexReg;
1961 0 : Register result = ReturnReg;
1962 :
1963 : // We are free to clobber all registers, as LRegExpSearcher is a call instruction.
1964 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
1965 0 : regs.take(input);
1966 0 : regs.take(regexp);
1967 0 : regs.take(lastIndex);
1968 :
1969 0 : Register temp1 = regs.takeAny();
1970 0 : Register temp2 = regs.takeAny();
1971 0 : Register temp3 = regs.takeAny();
1972 :
1973 0 : MacroAssembler masm(cx);
1974 :
1975 : // The InputOutputData is placed above the return address on the stack.
1976 0 : size_t inputOutputDataStartOffset = sizeof(void*);
1977 :
1978 0 : Label notFound, oolEntry;
1979 0 : if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
1980 : temp1, temp2, temp3, inputOutputDataStartOffset,
1981 : RegExpShared::Normal, ¬Found, &oolEntry))
1982 : {
1983 0 : return nullptr;
1984 : }
1985 :
1986 0 : size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
1987 : Address stringIndexAddress(masm.getStackPointer(),
1988 0 : pairsVectorStartOffset + offsetof(MatchPair, start));
1989 : Address stringLimitAddress(masm.getStackPointer(),
1990 0 : pairsVectorStartOffset + offsetof(MatchPair, limit));
1991 :
1992 0 : masm.load32(stringIndexAddress, result);
1993 0 : masm.load32(stringLimitAddress, input);
1994 0 : masm.lshiftPtr(Imm32(15), input);
1995 0 : masm.or32(input, result);
1996 0 : masm.ret();
1997 :
1998 0 : masm.bind(¬Found);
1999 0 : masm.move32(Imm32(RegExpSearcherResultNotFound), result);
2000 0 : masm.ret();
2001 :
2002 0 : masm.bind(&oolEntry);
2003 0 : masm.move32(Imm32(RegExpSearcherResultFailed), result);
2004 0 : masm.ret();
2005 :
2006 0 : Linker linker(masm);
2007 0 : AutoFlushICache afc("RegExpSearcherStub");
2008 0 : JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
2009 0 : if (!code)
2010 0 : return nullptr;
2011 :
2012 : #ifdef JS_ION_PERF
2013 : writePerfSpewerJitCodeProfile(code, "RegExpSearcherStub");
2014 : #endif
2015 : #ifdef MOZ_VTUNE
2016 0 : vtune::MarkStub(code, "RegExpSearcherStub");
2017 : #endif
2018 :
2019 0 : return code;
2020 : }
2021 :
2022 : class OutOfLineRegExpSearcher : public OutOfLineCodeBase<CodeGenerator>
2023 : {
2024 : LRegExpSearcher* lir_;
2025 :
2026 : public:
2027 0 : explicit OutOfLineRegExpSearcher(LRegExpSearcher* lir)
2028 0 : : lir_(lir)
2029 0 : { }
2030 :
2031 0 : void accept(CodeGenerator* codegen) {
2032 0 : codegen->visitOutOfLineRegExpSearcher(this);
2033 0 : }
2034 :
2035 0 : LRegExpSearcher* lir() const {
2036 0 : return lir_;
2037 : }
2038 : };
2039 :
2040 : typedef bool (*RegExpSearcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
2041 : int32_t lastIndex,
2042 : MatchPairs* pairs, int32_t* result);
2043 3 : static const VMFunction RegExpSearcherRawInfo =
2044 6 : FunctionInfo<RegExpSearcherRawFn>(RegExpSearcherRaw, "RegExpSearcherRaw");
2045 :
2046 : void
2047 0 : CodeGenerator::visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool)
2048 : {
2049 0 : LRegExpSearcher* lir = ool->lir();
2050 0 : Register lastIndex = ToRegister(lir->lastIndex());
2051 0 : Register input = ToRegister(lir->string());
2052 0 : Register regexp = ToRegister(lir->regexp());
2053 :
2054 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
2055 0 : regs.take(lastIndex);
2056 0 : regs.take(input);
2057 0 : regs.take(regexp);
2058 0 : Register temp = regs.takeAny();
2059 :
2060 0 : masm.computeEffectiveAddress(Address(masm.getStackPointer(),
2061 0 : sizeof(irregexp::InputOutputData)), temp);
2062 :
2063 0 : pushArg(temp);
2064 0 : pushArg(lastIndex);
2065 0 : pushArg(input);
2066 0 : pushArg(regexp);
2067 :
2068 : // We are not using oolCallVM because we are in a Call, and that live
2069 : // registers are already saved by the the register allocator.
2070 0 : callVM(RegExpSearcherRawInfo, lir);
2071 :
2072 0 : masm.jump(ool->rejoin());
2073 0 : }
2074 :
2075 : void
2076 0 : CodeGenerator::visitRegExpSearcher(LRegExpSearcher* lir)
2077 : {
2078 0 : MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
2079 0 : MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
2080 0 : MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
2081 0 : MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
2082 :
2083 0 : MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
2084 0 : MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
2085 0 : MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
2086 :
2087 0 : masm.reserveStack(RegExpReservedStack);
2088 :
2089 0 : OutOfLineRegExpSearcher* ool = new(alloc()) OutOfLineRegExpSearcher(lir);
2090 0 : addOutOfLineCode(ool, lir->mir());
2091 :
2092 0 : JitCode* regExpSearcherStub = gen->compartment->jitCompartment()->regExpSearcherStubNoBarrier();
2093 0 : masm.call(regExpSearcherStub);
2094 0 : masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpSearcherResultFailed), ool->entry());
2095 0 : masm.bind(ool->rejoin());
2096 :
2097 0 : masm.freeStack(RegExpReservedStack);
2098 0 : }
2099 :
2100 : static const int32_t RegExpTesterResultNotFound = -1;
2101 : static const int32_t RegExpTesterResultFailed = -2;
2102 :
2103 : JitCode*
2104 0 : JitCompartment::generateRegExpTesterStub(JSContext* cx)
2105 : {
2106 0 : Register regexp = RegExpTesterRegExpReg;
2107 0 : Register input = RegExpTesterStringReg;
2108 0 : Register lastIndex = RegExpTesterLastIndexReg;
2109 0 : Register result = ReturnReg;
2110 :
2111 0 : MacroAssembler masm(cx);
2112 :
2113 : #ifdef JS_USE_LINK_REGISTER
2114 : masm.pushReturnAddress();
2115 : #endif
2116 :
2117 : // We are free to clobber all registers, as LRegExpTester is a call instruction.
2118 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
2119 0 : regs.take(input);
2120 0 : regs.take(regexp);
2121 0 : regs.take(lastIndex);
2122 :
2123 0 : Register temp1 = regs.takeAny();
2124 0 : Register temp2 = regs.takeAny();
2125 0 : Register temp3 = regs.takeAny();
2126 :
2127 0 : masm.reserveStack(sizeof(irregexp::InputOutputData));
2128 :
2129 0 : Label notFound, oolEntry;
2130 0 : if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
2131 : temp1, temp2, temp3, 0,
2132 : RegExpShared::MatchOnly, ¬Found, &oolEntry))
2133 : {
2134 0 : return nullptr;
2135 : }
2136 :
2137 0 : Label done;
2138 :
2139 : // temp3 contains endIndex.
2140 0 : masm.move32(temp3, result);
2141 0 : masm.jump(&done);
2142 :
2143 0 : masm.bind(¬Found);
2144 0 : masm.move32(Imm32(RegExpTesterResultNotFound), result);
2145 0 : masm.jump(&done);
2146 :
2147 0 : masm.bind(&oolEntry);
2148 0 : masm.move32(Imm32(RegExpTesterResultFailed), result);
2149 :
2150 0 : masm.bind(&done);
2151 0 : masm.freeStack(sizeof(irregexp::InputOutputData));
2152 0 : masm.ret();
2153 :
2154 0 : Linker linker(masm);
2155 0 : AutoFlushICache afc("RegExpTesterStub");
2156 0 : JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
2157 0 : if (!code)
2158 0 : return nullptr;
2159 :
2160 : #ifdef JS_ION_PERF
2161 : writePerfSpewerJitCodeProfile(code, "RegExpTesterStub");
2162 : #endif
2163 : #ifdef MOZ_VTUNE
2164 0 : vtune::MarkStub(code, "RegExpTesterStub");
2165 : #endif
2166 :
2167 0 : return code;
2168 : }
2169 :
2170 : class OutOfLineRegExpTester : public OutOfLineCodeBase<CodeGenerator>
2171 : {
2172 : LRegExpTester* lir_;
2173 :
2174 : public:
2175 0 : explicit OutOfLineRegExpTester(LRegExpTester* lir)
2176 0 : : lir_(lir)
2177 0 : { }
2178 :
2179 0 : void accept(CodeGenerator* codegen) {
2180 0 : codegen->visitOutOfLineRegExpTester(this);
2181 0 : }
2182 :
2183 0 : LRegExpTester* lir() const {
2184 0 : return lir_;
2185 : }
2186 : };
2187 :
2188 : typedef bool (*RegExpTesterRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
2189 : int32_t lastIndex, int32_t* result);
2190 3 : static const VMFunction RegExpTesterRawInfo =
2191 6 : FunctionInfo<RegExpTesterRawFn>(RegExpTesterRaw, "RegExpTesterRaw");
2192 :
2193 : void
2194 0 : CodeGenerator::visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool)
2195 : {
2196 0 : LRegExpTester* lir = ool->lir();
2197 0 : Register lastIndex = ToRegister(lir->lastIndex());
2198 0 : Register input = ToRegister(lir->string());
2199 0 : Register regexp = ToRegister(lir->regexp());
2200 :
2201 0 : pushArg(lastIndex);
2202 0 : pushArg(input);
2203 0 : pushArg(regexp);
2204 :
2205 : // We are not using oolCallVM because we are in a Call, and that live
2206 : // registers are already saved by the the register allocator.
2207 0 : callVM(RegExpTesterRawInfo, lir);
2208 :
2209 0 : masm.jump(ool->rejoin());
2210 0 : }
2211 :
2212 : void
2213 0 : CodeGenerator::visitRegExpTester(LRegExpTester* lir)
2214 : {
2215 0 : MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
2216 0 : MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
2217 0 : MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
2218 0 : MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
2219 :
2220 0 : MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
2221 0 : MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
2222 0 : MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
2223 :
2224 0 : OutOfLineRegExpTester* ool = new(alloc()) OutOfLineRegExpTester(lir);
2225 0 : addOutOfLineCode(ool, lir->mir());
2226 :
2227 0 : JitCode* regExpTesterStub = gen->compartment->jitCompartment()->regExpTesterStubNoBarrier();
2228 0 : masm.call(regExpTesterStub);
2229 :
2230 0 : masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpTesterResultFailed), ool->entry());
2231 0 : masm.bind(ool->rejoin());
2232 0 : }
2233 :
2234 : class OutOfLineRegExpPrototypeOptimizable : public OutOfLineCodeBase<CodeGenerator>
2235 : {
2236 : LRegExpPrototypeOptimizable* ins_;
2237 :
2238 : public:
2239 0 : explicit OutOfLineRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
2240 0 : : ins_(ins)
2241 0 : { }
2242 :
2243 0 : void accept(CodeGenerator* codegen) {
2244 0 : codegen->visitOutOfLineRegExpPrototypeOptimizable(this);
2245 0 : }
2246 0 : LRegExpPrototypeOptimizable* ins() const {
2247 0 : return ins_;
2248 : }
2249 : };
2250 :
2251 : void
2252 0 : CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
2253 : {
2254 0 : Register object = ToRegister(ins->object());
2255 0 : Register output = ToRegister(ins->output());
2256 0 : Register temp = ToRegister(ins->temp());
2257 :
2258 0 : OutOfLineRegExpPrototypeOptimizable* ool = new(alloc()) OutOfLineRegExpPrototypeOptimizable(ins);
2259 0 : addOutOfLineCode(ool, ins->mir());
2260 :
2261 0 : masm.loadJSContext(temp);
2262 0 : masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
2263 0 : size_t offset = JSCompartment::offsetOfRegExps() +
2264 0 : RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape();
2265 0 : masm.loadPtr(Address(temp, offset), temp);
2266 :
2267 0 : masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
2268 0 : masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
2269 0 : masm.move32(Imm32(0x1), output);
2270 :
2271 0 : masm.bind(ool->rejoin());
2272 0 : }
2273 :
2274 : void
2275 0 : CodeGenerator::visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool)
2276 : {
2277 0 : LRegExpPrototypeOptimizable* ins = ool->ins();
2278 0 : Register object = ToRegister(ins->object());
2279 0 : Register output = ToRegister(ins->output());
2280 :
2281 0 : saveVolatile(output);
2282 :
2283 0 : masm.setupUnalignedABICall(output);
2284 0 : masm.loadJSContext(output);
2285 0 : masm.passABIArg(output);
2286 0 : masm.passABIArg(object);
2287 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpPrototypeOptimizableRaw));
2288 0 : masm.storeCallBoolResult(output);
2289 :
2290 0 : restoreVolatile(output);
2291 :
2292 0 : masm.jump(ool->rejoin());
2293 0 : }
2294 :
2295 : class OutOfLineRegExpInstanceOptimizable : public OutOfLineCodeBase<CodeGenerator>
2296 : {
2297 : LRegExpInstanceOptimizable* ins_;
2298 :
2299 : public:
2300 0 : explicit OutOfLineRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
2301 0 : : ins_(ins)
2302 0 : { }
2303 :
2304 0 : void accept(CodeGenerator* codegen) {
2305 0 : codegen->visitOutOfLineRegExpInstanceOptimizable(this);
2306 0 : }
2307 0 : LRegExpInstanceOptimizable* ins() const {
2308 0 : return ins_;
2309 : }
2310 : };
2311 :
2312 : void
2313 0 : CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
2314 : {
2315 0 : Register object = ToRegister(ins->object());
2316 0 : Register output = ToRegister(ins->output());
2317 0 : Register temp = ToRegister(ins->temp());
2318 :
2319 0 : OutOfLineRegExpInstanceOptimizable* ool = new(alloc()) OutOfLineRegExpInstanceOptimizable(ins);
2320 0 : addOutOfLineCode(ool, ins->mir());
2321 :
2322 0 : masm.loadJSContext(temp);
2323 0 : masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
2324 0 : size_t offset = JSCompartment::offsetOfRegExps() +
2325 0 : RegExpCompartment::offsetOfOptimizableRegExpInstanceShape();
2326 0 : masm.loadPtr(Address(temp, offset), temp);
2327 :
2328 0 : masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
2329 0 : masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
2330 0 : masm.move32(Imm32(0x1), output);
2331 :
2332 0 : masm.bind(ool->rejoin());
2333 0 : }
2334 :
2335 : void
2336 0 : CodeGenerator::visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool)
2337 : {
2338 0 : LRegExpInstanceOptimizable* ins = ool->ins();
2339 0 : Register object = ToRegister(ins->object());
2340 0 : Register proto = ToRegister(ins->proto());
2341 0 : Register output = ToRegister(ins->output());
2342 :
2343 0 : saveVolatile(output);
2344 :
2345 0 : masm.setupUnalignedABICall(output);
2346 0 : masm.loadJSContext(output);
2347 0 : masm.passABIArg(output);
2348 0 : masm.passABIArg(object);
2349 0 : masm.passABIArg(proto);
2350 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpInstanceOptimizableRaw));
2351 0 : masm.storeCallBoolResult(output);
2352 :
2353 0 : restoreVolatile(output);
2354 :
2355 0 : masm.jump(ool->rejoin());
2356 0 : }
2357 :
2358 : static void
2359 0 : FindFirstDollarIndex(MacroAssembler& masm, Register str, Register len, Register chars,
2360 : Register temp, Register output, bool isLatin1)
2361 : {
2362 0 : masm.loadStringChars(str, chars);
2363 :
2364 0 : masm.move32(Imm32(0), output);
2365 :
2366 0 : Label start, done;
2367 0 : masm.bind(&start);
2368 0 : if (isLatin1)
2369 0 : masm.load8ZeroExtend(BaseIndex(chars, output, TimesOne), temp);
2370 : else
2371 0 : masm.load16ZeroExtend(BaseIndex(chars, output, TimesTwo), temp);
2372 :
2373 0 : masm.branch32(Assembler::Equal, temp, Imm32('$'), &done);
2374 :
2375 0 : masm.add32(Imm32(1), output);
2376 0 : masm.branch32(Assembler::NotEqual, output, len, &start);
2377 :
2378 0 : masm.move32(Imm32(-1), output);
2379 :
2380 0 : masm.bind(&done);
2381 0 : }
2382 :
2383 : typedef bool (*GetFirstDollarIndexRawFn)(JSContext*, HandleString, int32_t*);
2384 3 : static const VMFunction GetFirstDollarIndexRawInfo =
2385 6 : FunctionInfo<GetFirstDollarIndexRawFn>(GetFirstDollarIndexRaw, "GetFirstDollarIndexRaw");
2386 :
2387 : void
2388 0 : CodeGenerator::visitGetFirstDollarIndex(LGetFirstDollarIndex* ins)
2389 : {
2390 0 : Register str = ToRegister(ins->str());
2391 0 : Register output = ToRegister(ins->output());
2392 0 : Register temp0 = ToRegister(ins->temp0());
2393 0 : Register temp1 = ToRegister(ins->temp1());
2394 0 : Register len = ToRegister(ins->temp2());
2395 :
2396 0 : OutOfLineCode* ool = oolCallVM(GetFirstDollarIndexRawInfo, ins, ArgList(str),
2397 0 : StoreRegisterTo(output));
2398 :
2399 0 : masm.branchIfRope(str, ool->entry());
2400 0 : masm.loadStringLength(str, len);
2401 :
2402 0 : Label isLatin1, done;
2403 0 : masm.branchLatin1String(str, &isLatin1);
2404 : {
2405 0 : FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ false);
2406 : }
2407 0 : masm.jump(&done);
2408 : {
2409 0 : masm.bind(&isLatin1);
2410 0 : FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ true);
2411 : }
2412 0 : masm.bind(&done);
2413 0 : masm.bind(ool->rejoin());
2414 0 : }
2415 :
2416 : typedef JSString* (*StringReplaceFn)(JSContext*, HandleString, HandleString, HandleString);
2417 3 : static const VMFunction StringFlatReplaceInfo =
2418 6 : FunctionInfo<StringReplaceFn>(js::str_flat_replace_string, "str_flat_replace_string");
2419 3 : static const VMFunction StringReplaceInfo =
2420 6 : FunctionInfo<StringReplaceFn>(StringReplace, "StringReplace");
2421 :
2422 : void
2423 0 : CodeGenerator::visitStringReplace(LStringReplace* lir)
2424 : {
2425 0 : if (lir->replacement()->isConstant())
2426 0 : pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
2427 : else
2428 0 : pushArg(ToRegister(lir->replacement()));
2429 :
2430 0 : if (lir->pattern()->isConstant())
2431 0 : pushArg(ImmGCPtr(lir->pattern()->toConstant()->toString()));
2432 : else
2433 0 : pushArg(ToRegister(lir->pattern()));
2434 :
2435 0 : if (lir->string()->isConstant())
2436 0 : pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
2437 : else
2438 0 : pushArg(ToRegister(lir->string()));
2439 :
2440 0 : if (lir->mir()->isFlatReplacement())
2441 0 : callVM(StringFlatReplaceInfo, lir);
2442 : else
2443 0 : callVM(StringReplaceInfo, lir);
2444 0 : }
2445 :
2446 : void
2447 0 : CodeGenerator::emitSharedStub(ICStub::Kind kind, LInstruction* lir)
2448 : {
2449 0 : JSScript* script = lir->mirRaw()->block()->info().script();
2450 0 : jsbytecode* pc = lir->mirRaw()->toInstruction()->resumePoint()->pc();
2451 :
2452 : #ifdef JS_USE_LINK_REGISTER
2453 : // Some architectures don't push the return address on the stack but
2454 : // use the link register. In that case the stack isn't aligned. Push
2455 : // to make sure we are aligned.
2456 : masm.Push(Imm32(0));
2457 : #endif
2458 :
2459 : // Create descriptor signifying end of Ion frame.
2460 0 : uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
2461 0 : JitStubFrameLayout::Size());
2462 0 : masm.Push(Imm32(descriptor));
2463 :
2464 : // Call into the stubcode.
2465 0 : CodeOffset patchOffset;
2466 0 : IonICEntry entry(script->pcToOffset(pc), ICEntry::Kind_Op, script);
2467 0 : EmitCallIC(&patchOffset, masm);
2468 0 : entry.setReturnOffset(CodeOffset(masm.currentOffset()));
2469 :
2470 0 : SharedStub sharedStub(kind, entry, patchOffset);
2471 0 : masm.propagateOOM(sharedStubs_.append(sharedStub));
2472 :
2473 : // Fix up upon return.
2474 0 : uint32_t callOffset = masm.currentOffset();
2475 : #ifdef JS_USE_LINK_REGISTER
2476 : masm.freeStack(sizeof(intptr_t) * 2);
2477 : #else
2478 0 : masm.freeStack(sizeof(intptr_t));
2479 : #endif
2480 0 : markSafepointAt(callOffset, lir);
2481 0 : }
2482 :
2483 : void
2484 0 : CodeGenerator::visitBinarySharedStub(LBinarySharedStub* lir)
2485 : {
2486 0 : JSOp jsop = JSOp(*lir->mirRaw()->toInstruction()->resumePoint()->pc());
2487 0 : switch (jsop) {
2488 : case JSOP_ADD:
2489 : case JSOP_SUB:
2490 : case JSOP_MUL:
2491 : case JSOP_DIV:
2492 : case JSOP_MOD:
2493 : case JSOP_POW:
2494 0 : emitSharedStub(ICStub::Kind::BinaryArith_Fallback, lir);
2495 0 : break;
2496 : case JSOP_LT:
2497 : case JSOP_LE:
2498 : case JSOP_GT:
2499 : case JSOP_GE:
2500 : case JSOP_EQ:
2501 : case JSOP_NE:
2502 : case JSOP_STRICTEQ:
2503 : case JSOP_STRICTNE:
2504 0 : emitSharedStub(ICStub::Kind::Compare_Fallback, lir);
2505 0 : break;
2506 : default:
2507 0 : MOZ_CRASH("Unsupported jsop in shared stubs.");
2508 : }
2509 0 : }
2510 :
2511 : void
2512 0 : CodeGenerator::visitUnarySharedStub(LUnarySharedStub* lir)
2513 : {
2514 0 : JSOp jsop = JSOp(*lir->mir()->resumePoint()->pc());
2515 0 : switch (jsop) {
2516 : case JSOP_BITNOT:
2517 : case JSOP_NEG:
2518 0 : emitSharedStub(ICStub::Kind::UnaryArith_Fallback, lir);
2519 0 : break;
2520 : case JSOP_CALLPROP:
2521 : case JSOP_GETPROP:
2522 : case JSOP_LENGTH:
2523 0 : emitSharedStub(ICStub::Kind::GetProp_Fallback, lir);
2524 0 : break;
2525 : default:
2526 0 : MOZ_CRASH("Unsupported jsop in shared stubs.");
2527 : }
2528 0 : }
2529 :
2530 : void
2531 0 : CodeGenerator::visitNullarySharedStub(LNullarySharedStub* lir)
2532 : {
2533 0 : jsbytecode* pc = lir->mir()->resumePoint()->pc();
2534 0 : JSOp jsop = JSOp(*pc);
2535 0 : switch (jsop) {
2536 : case JSOP_NEWARRAY: {
2537 0 : uint32_t length = GET_UINT32(pc);
2538 0 : MOZ_ASSERT(length <= INT32_MAX,
2539 : "the bytecode emitter must fail to compile code that would "
2540 : "produce JSOP_NEWARRAY with a length exceeding int32_t range");
2541 :
2542 : // Pass length in R0.
2543 0 : masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
2544 0 : emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
2545 0 : break;
2546 : }
2547 : case JSOP_NEWOBJECT:
2548 0 : emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
2549 0 : break;
2550 : case JSOP_NEWINIT: {
2551 0 : JSProtoKey key = JSProtoKey(GET_UINT8(pc));
2552 0 : if (key == JSProto_Array) {
2553 0 : masm.move32(Imm32(0), R0.scratchReg());
2554 0 : emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
2555 : } else {
2556 0 : emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
2557 : }
2558 0 : break;
2559 : }
2560 : default:
2561 0 : MOZ_CRASH("Unsupported jsop in shared stubs.");
2562 : }
2563 0 : }
2564 :
2565 : typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
2566 3 : static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda, "Lambda");
2567 :
2568 : void
2569 0 : CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton* lir)
2570 : {
2571 0 : pushArg(ToRegister(lir->environmentChain()));
2572 0 : pushArg(ImmGCPtr(lir->mir()->info().fun));
2573 0 : callVM(LambdaInfo, lir);
2574 0 : }
2575 :
2576 : void
2577 10 : CodeGenerator::visitLambda(LLambda* lir)
2578 : {
2579 10 : Register envChain = ToRegister(lir->environmentChain());
2580 10 : Register output = ToRegister(lir->output());
2581 10 : Register tempReg = ToRegister(lir->temp());
2582 10 : const LambdaFunctionInfo& info = lir->mir()->info();
2583 :
2584 20 : OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, ArgList(ImmGCPtr(info.fun), envChain),
2585 30 : StoreRegisterTo(output));
2586 :
2587 10 : MOZ_ASSERT(!info.singletonType);
2588 :
2589 10 : masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
2590 :
2591 10 : emitLambdaInit(output, envChain, info);
2592 :
2593 10 : if (info.flags & JSFunction::EXTENDED) {
2594 0 : MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
2595 : info.fun->isAsync());
2596 : static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
2597 0 : masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
2598 0 : masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
2599 : }
2600 :
2601 10 : masm.bind(ool->rejoin());
2602 10 : }
2603 :
2604 : class OutOfLineLambdaArrow : public OutOfLineCodeBase<CodeGenerator>
2605 : {
2606 : public:
2607 : LLambdaArrow* lir;
2608 : Label entryNoPop_;
2609 :
2610 0 : explicit OutOfLineLambdaArrow(LLambdaArrow* lir)
2611 0 : : lir(lir)
2612 0 : { }
2613 :
2614 0 : void accept(CodeGenerator* codegen) {
2615 0 : codegen->visitOutOfLineLambdaArrow(this);
2616 0 : }
2617 :
2618 0 : Label* entryNoPop() {
2619 0 : return &entryNoPop_;
2620 : }
2621 : };
2622 :
2623 : typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
2624 3 : static const VMFunction LambdaArrowInfo =
2625 6 : FunctionInfo<LambdaArrowFn>(js::LambdaArrow, "LambdaArrow");
2626 :
2627 : void
2628 0 : CodeGenerator::visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool)
2629 : {
2630 0 : Register envChain = ToRegister(ool->lir->environmentChain());
2631 0 : ValueOperand newTarget = ToValue(ool->lir, LLambdaArrow::NewTargetValue);
2632 0 : Register output = ToRegister(ool->lir->output());
2633 0 : const LambdaFunctionInfo& info = ool->lir->mir()->info();
2634 :
2635 : // When we get here, we may need to restore part of the newTarget,
2636 : // which has been conscripted into service as a temp register.
2637 0 : masm.pop(newTarget.scratchReg());
2638 :
2639 0 : masm.bind(ool->entryNoPop());
2640 :
2641 0 : saveLive(ool->lir);
2642 :
2643 0 : pushArg(newTarget);
2644 0 : pushArg(envChain);
2645 0 : pushArg(ImmGCPtr(info.fun));
2646 :
2647 0 : callVM(LambdaArrowInfo, ool->lir);
2648 0 : StoreRegisterTo(output).generate(this);
2649 :
2650 0 : restoreLiveIgnore(ool->lir, StoreRegisterTo(output).clobbered());
2651 :
2652 0 : masm.jump(ool->rejoin());
2653 0 : }
2654 :
2655 : void
2656 0 : CodeGenerator::visitLambdaArrow(LLambdaArrow* lir)
2657 : {
2658 0 : Register envChain = ToRegister(lir->environmentChain());
2659 0 : ValueOperand newTarget = ToValue(lir, LLambdaArrow::NewTargetValue);
2660 0 : Register output = ToRegister(lir->output());
2661 0 : const LambdaFunctionInfo& info = lir->mir()->info();
2662 :
2663 0 : OutOfLineLambdaArrow* ool = new (alloc()) OutOfLineLambdaArrow(lir);
2664 0 : addOutOfLineCode(ool, lir->mir());
2665 :
2666 0 : MOZ_ASSERT(!info.useSingletonForClone);
2667 :
2668 0 : if (info.singletonType) {
2669 : // If the function has a singleton type, this instruction will only be
2670 : // executed once so we don't bother inlining it.
2671 0 : masm.jump(ool->entryNoPop());
2672 0 : masm.bind(ool->rejoin());
2673 0 : return;
2674 : }
2675 :
2676 : // There's not enough registers on x86 with the profiler enabled to request
2677 : // a temp. Instead, spill part of one of the values, being prepared to
2678 : // restore it if necessary on the out of line path.
2679 0 : Register tempReg = newTarget.scratchReg();
2680 0 : masm.push(newTarget.scratchReg());
2681 :
2682 0 : masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
2683 :
2684 0 : masm.pop(newTarget.scratchReg());
2685 :
2686 0 : emitLambdaInit(output, envChain, info);
2687 :
2688 : // Initialize extended slots. Lexical |this| is stored in the first one.
2689 0 : MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
2690 : static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
2691 : static_assert(FunctionExtended::ARROW_NEWTARGET_SLOT == 0,
2692 : "|new.target| must be stored in first slot");
2693 0 : masm.storeValue(newTarget, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
2694 0 : masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
2695 :
2696 0 : masm.bind(ool->rejoin());
2697 : }
2698 :
2699 : void
2700 10 : CodeGenerator::emitLambdaInit(Register output, Register envChain,
2701 : const LambdaFunctionInfo& info)
2702 : {
2703 : // Initialize nargs and flags. We do this with a single uint32 to avoid
2704 : // 16-bit writes.
2705 : union {
2706 : struct S {
2707 : uint16_t nargs;
2708 : uint16_t flags;
2709 : } s;
2710 : uint32_t word;
2711 : } u;
2712 10 : u.s.nargs = info.nargs;
2713 10 : u.s.flags = info.flags;
2714 :
2715 10 : MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
2716 10 : masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));
2717 20 : masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
2718 20 : Address(output, JSFunction::offsetOfNativeOrScript()));
2719 10 : masm.storePtr(envChain, Address(output, JSFunction::offsetOfEnvironment()));
2720 10 : masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
2721 10 : }
2722 :
2723 : typedef bool (*SetFunNameFn)(JSContext*, HandleFunction, HandleValue, FunctionPrefixKind);
2724 3 : static const VMFunction SetFunNameInfo =
2725 6 : FunctionInfo<SetFunNameFn>(js::SetFunctionNameIfNoOwnName, "SetFunName");
2726 :
2727 : void
2728 0 : CodeGenerator::visitSetFunName(LSetFunName* lir)
2729 : {
2730 0 : pushArg(Imm32(lir->mir()->prefixKind()));
2731 0 : pushArg(ToValue(lir, LSetFunName::NameValue));
2732 0 : pushArg(ToRegister(lir->fun()));
2733 :
2734 0 : callVM(SetFunNameInfo, lir);
2735 0 : }
2736 :
2737 : void
2738 134 : CodeGenerator::visitOsiPoint(LOsiPoint* lir)
2739 : {
2740 : // Note: markOsiPoint ensures enough space exists between the last
2741 : // LOsiPoint and this one to patch adjacent call instructions.
2742 :
2743 134 : MOZ_ASSERT(masm.framePushed() == frameSize());
2744 :
2745 134 : uint32_t osiCallPointOffset = markOsiPoint(lir);
2746 :
2747 134 : LSafepoint* safepoint = lir->associatedSafepoint();
2748 134 : MOZ_ASSERT(!safepoint->osiCallPointOffset());
2749 134 : safepoint->setOsiCallPointOffset(osiCallPointOffset);
2750 :
2751 : #ifdef DEBUG
2752 : // There should be no movegroups or other instructions between
2753 : // an instruction and its OsiPoint. This is necessary because
2754 : // we use the OsiPoint's snapshot from within VM calls.
2755 268 : for (LInstructionReverseIterator iter(current->rbegin(lir)); iter != current->rend(); iter++) {
2756 268 : if (*iter == lir)
2757 134 : continue;
2758 134 : MOZ_ASSERT(!iter->isMoveGroup());
2759 134 : MOZ_ASSERT(iter->safepoint() == safepoint);
2760 134 : break;
2761 : }
2762 : #endif
2763 :
2764 : #ifdef CHECK_OSIPOINT_REGISTERS
2765 134 : if (shouldVerifyOsiPointRegs(safepoint))
2766 0 : verifyOsiPointRegs(safepoint);
2767 : #endif
2768 134 : }
2769 :
2770 : void
2771 149 : CodeGenerator::visitGoto(LGoto* lir)
2772 : {
2773 149 : jumpToBlock(lir->target());
2774 149 : }
2775 :
2776 : // Out-of-line path to execute any move groups between the start of a loop
2777 : // header and its interrupt check, then invoke the interrupt handler.
2778 : class OutOfLineInterruptCheckImplicit : public OutOfLineCodeBase<CodeGenerator>
2779 : {
2780 : public:
2781 : LBlock* block;
2782 : LInterruptCheck* lir;
2783 :
2784 0 : OutOfLineInterruptCheckImplicit(LBlock* block, LInterruptCheck* lir)
2785 0 : : block(block), lir(lir)
2786 0 : { }
2787 :
2788 0 : void accept(CodeGenerator* codegen) {
2789 0 : codegen->visitOutOfLineInterruptCheckImplicit(this);
2790 0 : }
2791 : };
2792 :
2793 : typedef bool (*InterruptCheckFn)(JSContext*);
2794 3 : static const VMFunction InterruptCheckInfo =
2795 6 : FunctionInfo<InterruptCheckFn>(InterruptCheck, "InterruptCheck");
2796 :
2797 : void
2798 0 : CodeGenerator::visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ool)
2799 : {
2800 : #ifdef CHECK_OSIPOINT_REGISTERS
2801 : // This is path is entered from the patched back-edge of the loop. This
2802 : // means that the JitAtivation flags used for checking the validity of the
2803 : // OSI points are not reseted by the path generated by generateBody, so we
2804 : // have to reset it here.
2805 0 : resetOsiPointRegs(ool->lir->safepoint());
2806 : #endif
2807 :
2808 0 : LInstructionIterator iter = ool->block->begin();
2809 0 : for (; iter != ool->block->end(); iter++) {
2810 0 : if (iter->isMoveGroup()) {
2811 : // Replay this move group that preceds the interrupt check at the
2812 : // start of the loop header. Any incoming jumps here will be from
2813 : // the backedge and will skip over the move group emitted inline.
2814 0 : visitMoveGroup(iter->toMoveGroup());
2815 : } else {
2816 0 : break;
2817 : }
2818 : }
2819 0 : MOZ_ASSERT(*iter == ool->lir);
2820 :
2821 0 : saveLive(ool->lir);
2822 0 : callVM(InterruptCheckInfo, ool->lir);
2823 0 : restoreLive(ool->lir);
2824 0 : masm.jump(ool->rejoin());
2825 0 : }
2826 :
2827 : void
2828 0 : CodeGenerator::visitTableSwitch(LTableSwitch* ins)
2829 : {
2830 0 : MTableSwitch* mir = ins->mir();
2831 0 : Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
2832 : const LAllocation* temp;
2833 :
2834 0 : if (mir->getOperand(0)->type() != MIRType::Int32) {
2835 0 : temp = ins->tempInt()->output();
2836 :
2837 : // The input is a double, so try and convert it to an integer.
2838 : // If it does not fit in an integer, take the default case.
2839 0 : masm.convertDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
2840 : } else {
2841 0 : temp = ins->index();
2842 : }
2843 :
2844 0 : emitTableSwitchDispatch(mir, ToRegister(temp), ToRegisterOrInvalid(ins->tempPointer()));
2845 0 : }
2846 :
2847 : void
2848 0 : CodeGenerator::visitTableSwitchV(LTableSwitchV* ins)
2849 : {
2850 0 : MTableSwitch* mir = ins->mir();
2851 0 : Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
2852 :
2853 0 : Register index = ToRegister(ins->tempInt());
2854 0 : ValueOperand value = ToValue(ins, LTableSwitchV::InputValue);
2855 0 : Register tag = masm.extractTag(value, index);
2856 0 : masm.branchTestNumber(Assembler::NotEqual, tag, defaultcase);
2857 :
2858 0 : Label unboxInt, isInt;
2859 0 : masm.branchTestInt32(Assembler::Equal, tag, &unboxInt);
2860 : {
2861 0 : FloatRegister floatIndex = ToFloatRegister(ins->tempFloat());
2862 0 : masm.unboxDouble(value, floatIndex);
2863 0 : masm.convertDoubleToInt32(floatIndex, index, defaultcase, false);
2864 0 : masm.jump(&isInt);
2865 : }
2866 :
2867 0 : masm.bind(&unboxInt);
2868 0 : masm.unboxInt32(value, index);
2869 :
2870 0 : masm.bind(&isInt);
2871 :
2872 0 : emitTableSwitchDispatch(mir, index, ToRegisterOrInvalid(ins->tempPointer()));
2873 0 : }
2874 :
2875 : typedef JSObject* (*DeepCloneObjectLiteralFn)(JSContext*, HandleObject, NewObjectKind);
2876 3 : static const VMFunction DeepCloneObjectLiteralInfo =
2877 6 : FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral, "DeepCloneObjectLiteral");
2878 :
2879 : void
2880 0 : CodeGenerator::visitCloneLiteral(LCloneLiteral* lir)
2881 : {
2882 0 : pushArg(ImmWord(TenuredObject));
2883 0 : pushArg(ToRegister(lir->getObjectLiteral()));
2884 0 : callVM(DeepCloneObjectLiteralInfo, lir);
2885 0 : }
2886 :
2887 : void
2888 36 : CodeGenerator::visitParameter(LParameter* lir)
2889 : {
2890 36 : }
2891 :
2892 : void
2893 3 : CodeGenerator::visitCallee(LCallee* lir)
2894 : {
2895 3 : Register callee = ToRegister(lir->output());
2896 3 : Address ptr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
2897 :
2898 3 : masm.loadFunctionFromCalleeToken(ptr, callee);
2899 3 : }
2900 :
2901 : void
2902 0 : CodeGenerator::visitIsConstructing(LIsConstructing* lir)
2903 : {
2904 0 : Register output = ToRegister(lir->output());
2905 0 : Address calleeToken(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
2906 0 : masm.loadPtr(calleeToken, output);
2907 :
2908 : // We must be inside a function.
2909 0 : MOZ_ASSERT(current->mir()->info().script()->functionNonDelazifying());
2910 :
2911 : // The low bit indicates whether this call is constructing, just clear the
2912 : // other bits.
2913 : static_assert(CalleeToken_Function == 0x0, "CalleeTokenTag value should match");
2914 : static_assert(CalleeToken_FunctionConstructing == 0x1, "CalleeTokenTag value should match");
2915 0 : masm.andPtr(Imm32(0x1), output);
2916 0 : }
2917 :
2918 : void
2919 11 : CodeGenerator::visitStart(LStart* lir)
2920 : {
2921 11 : }
2922 :
2923 : void
2924 17 : CodeGenerator::visitReturn(LReturn* lir)
2925 : {
2926 : #if defined(JS_NUNBOX32)
2927 : DebugOnly<LAllocation*> type = lir->getOperand(TYPE_INDEX);
2928 : DebugOnly<LAllocation*> payload = lir->getOperand(PAYLOAD_INDEX);
2929 : MOZ_ASSERT(ToRegister(type) == JSReturnReg_Type);
2930 : MOZ_ASSERT(ToRegister(payload) == JSReturnReg_Data);
2931 : #elif defined(JS_PUNBOX64)
2932 34 : DebugOnly<LAllocation*> result = lir->getOperand(0);
2933 17 : MOZ_ASSERT(ToRegister(result) == JSReturnReg);
2934 : #endif
2935 : // Don't emit a jump to the return label if this is the last block.
2936 17 : if (current->mir() != *gen->graph().poBegin())
2937 11 : masm.jump(&returnLabel_);
2938 17 : }
2939 :
2940 : void
2941 3 : CodeGenerator::visitOsrEntry(LOsrEntry* lir)
2942 : {
2943 3 : Register temp = ToRegister(lir->temp());
2944 :
2945 : // Remember the OSR entry offset into the code buffer.
2946 3 : masm.flushBuffer();
2947 3 : setOsrEntryOffset(masm.size());
2948 :
2949 : #ifdef JS_TRACE_LOGGING
2950 3 : emitTracelogStopEvent(TraceLogger_Baseline);
2951 3 : emitTracelogStartEvent(TraceLogger_IonMonkey);
2952 : #endif
2953 :
2954 : // If profiling, save the current frame pointer to a per-thread global field.
2955 3 : if (isProfilerInstrumentationEnabled())
2956 0 : masm.profilerEnterFrame(masm.getStackPointer(), temp);
2957 :
2958 : // Allocate the full frame for this function
2959 : // Note we have a new entry here. So we reset MacroAssembler::framePushed()
2960 : // to 0, before reserving the stack.
2961 3 : MOZ_ASSERT(masm.framePushed() == frameSize());
2962 3 : masm.setFramePushed(0);
2963 :
2964 : // Ensure that the Ion frames is properly aligned.
2965 3 : masm.assertStackAlignment(JitStackAlignment, 0);
2966 :
2967 3 : masm.reserveStack(frameSize());
2968 3 : }
2969 :
2970 : void
2971 2 : CodeGenerator::visitOsrEnvironmentChain(LOsrEnvironmentChain* lir)
2972 : {
2973 2 : const LAllocation* frame = lir->getOperand(0);
2974 2 : const LDefinition* object = lir->getDef(0);
2975 :
2976 2 : const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfEnvironmentChain();
2977 :
2978 2 : masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
2979 2 : }
2980 :
2981 : void
2982 0 : CodeGenerator::visitOsrArgumentsObject(LOsrArgumentsObject* lir)
2983 : {
2984 0 : const LAllocation* frame = lir->getOperand(0);
2985 0 : const LDefinition* object = lir->getDef(0);
2986 :
2987 0 : const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfArgsObj();
2988 :
2989 0 : masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
2990 0 : }
2991 :
2992 : void
2993 42 : CodeGenerator::visitOsrValue(LOsrValue* value)
2994 : {
2995 42 : const LAllocation* frame = value->getOperand(0);
2996 42 : const ValueOperand out = ToOutValue(value);
2997 :
2998 42 : const ptrdiff_t frameOffset = value->mir()->frameOffset();
2999 :
3000 42 : masm.loadValue(Address(ToRegister(frame), frameOffset), out);
3001 42 : }
3002 :
3003 : void
3004 3 : CodeGenerator::visitOsrReturnValue(LOsrReturnValue* lir)
3005 : {
3006 3 : const LAllocation* frame = lir->getOperand(0);
3007 3 : const ValueOperand out = ToOutValue(lir);
3008 :
3009 3 : Address flags = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfFlags());
3010 3 : Address retval = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfReturnValue());
3011 :
3012 3 : masm.moveValue(UndefinedValue(), out);
3013 :
3014 6 : Label done;
3015 3 : masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
3016 3 : masm.loadValue(retval, out);
3017 3 : masm.bind(&done);
3018 3 : }
3019 :
3020 : void
3021 62 : CodeGenerator::visitStackArgT(LStackArgT* lir)
3022 : {
3023 62 : const LAllocation* arg = lir->getArgument();
3024 62 : MIRType argType = lir->type();
3025 62 : uint32_t argslot = lir->argslot();
3026 62 : MOZ_ASSERT(argslot - 1u < graph.argumentSlotCount());
3027 :
3028 62 : int32_t stack_offset = StackOffsetOfPassedArg(argslot);
3029 62 : Address dest(masm.getStackPointer(), stack_offset);
3030 :
3031 62 : if (arg->isFloatReg())
3032 0 : masm.storeDouble(ToFloatRegister(arg), dest);
3033 62 : else if (arg->isRegister())
3034 42 : masm.storeValue(ValueTypeFromMIRType(argType), ToRegister(arg), dest);
3035 : else
3036 20 : masm.storeValue(arg->toConstant()->toJSValue(), dest);
3037 62 : }
3038 :
3039 : void
3040 9 : CodeGenerator::visitStackArgV(LStackArgV* lir)
3041 : {
3042 9 : ValueOperand val = ToValue(lir, 0);
3043 9 : uint32_t argslot = lir->argslot();
3044 9 : MOZ_ASSERT(argslot - 1u < graph.argumentSlotCount());
3045 :
3046 9 : int32_t stack_offset = StackOffsetOfPassedArg(argslot);
3047 :
3048 9 : masm.storeValue(val, Address(masm.getStackPointer(), stack_offset));
3049 9 : }
3050 :
3051 : void
3052 429 : CodeGenerator::visitMoveGroup(LMoveGroup* group)
3053 : {
3054 429 : if (!group->numMoves())
3055 0 : return;
3056 :
3057 429 : MoveResolver& resolver = masm.moveResolver();
3058 :
3059 983 : for (size_t i = 0; i < group->numMoves(); i++) {
3060 554 : const LMove& move = group->getMove(i);
3061 :
3062 554 : LAllocation from = move.from();
3063 554 : LAllocation to = move.to();
3064 554 : LDefinition::Type type = move.type();
3065 :
3066 : // No bogus moves.
3067 554 : MOZ_ASSERT(from != to);
3068 554 : MOZ_ASSERT(!from.isConstant());
3069 : MoveOp::Type moveType;
3070 554 : switch (type) {
3071 : case LDefinition::OBJECT:
3072 : case LDefinition::SLOTS:
3073 : #ifdef JS_NUNBOX32
3074 : case LDefinition::TYPE:
3075 : case LDefinition::PAYLOAD:
3076 : #else
3077 : case LDefinition::BOX:
3078 : #endif
3079 389 : case LDefinition::GENERAL: moveType = MoveOp::GENERAL; break;
3080 165 : case LDefinition::INT32: moveType = MoveOp::INT32; break;
3081 0 : case LDefinition::FLOAT32: moveType = MoveOp::FLOAT32; break;
3082 0 : case LDefinition::DOUBLE: moveType = MoveOp::DOUBLE; break;
3083 0 : case LDefinition::SIMD128INT: moveType = MoveOp::SIMD128INT; break;
3084 0 : case LDefinition::SIMD128FLOAT: moveType = MoveOp::SIMD128FLOAT; break;
3085 0 : default: MOZ_CRASH("Unexpected move type");
3086 : }
3087 :
3088 554 : masm.propagateOOM(resolver.addMove(toMoveOperand(from), toMoveOperand(to), moveType));
3089 : }
3090 :
3091 429 : masm.propagateOOM(resolver.resolve());
3092 429 : if (masm.oom())
3093 0 : return;
3094 :
3095 858 : MoveEmitter emitter(masm);
3096 :
3097 : #ifdef JS_CODEGEN_X86
3098 : if (group->maybeScratchRegister().isGeneralReg())
3099 : emitter.setScratchRegister(group->maybeScratchRegister().toGeneralReg()->reg());
3100 : else
3101 : resolver.sortMemoryToMemoryMoves();
3102 : #endif
3103 :
3104 429 : emitter.emit(resolver);
3105 429 : emitter.finish();
3106 : }
3107 :
3108 : void
3109 50 : CodeGenerator::visitInteger(LInteger* lir)
3110 : {
3111 50 : masm.move32(Imm32(lir->getValue()), ToRegister(lir->output()));
3112 50 : }
3113 :
3114 : void
3115 0 : CodeGenerator::visitInteger64(LInteger64* lir)
3116 : {
3117 0 : masm.move64(Imm64(lir->getValue()), ToOutRegister64(lir));
3118 0 : }
3119 :
3120 : void
3121 19 : CodeGenerator::visitPointer(LPointer* lir)
3122 : {
3123 19 : if (lir->kind() == LPointer::GC_THING)
3124 19 : masm.movePtr(ImmGCPtr(lir->gcptr()), ToRegister(lir->output()));
3125 : else
3126 0 : masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
3127 19 : }
3128 :
3129 : void
3130 2 : CodeGenerator::visitKeepAliveObject(LKeepAliveObject* lir)
3131 : {
3132 : // No-op.
3133 2 : }
3134 :
3135 : void
3136 7 : CodeGenerator::visitSlots(LSlots* lir)
3137 : {
3138 7 : Address slots(ToRegister(lir->object()), NativeObject::offsetOfSlots());
3139 7 : masm.loadPtr(slots, ToRegister(lir->output()));
3140 7 : }
3141 :
3142 : void
3143 7 : CodeGenerator::visitLoadSlotT(LLoadSlotT* lir)
3144 : {
3145 7 : Register base = ToRegister(lir->slots());
3146 7 : int32_t offset = lir->mir()->slot() * sizeof(js::Value);
3147 7 : AnyRegister result = ToAnyRegister(lir->output());
3148 :
3149 7 : masm.loadUnboxedValue(Address(base, offset), lir->mir()->type(), result);
3150 7 : }
3151 :
3152 : void
3153 0 : CodeGenerator::visitLoadSlotV(LLoadSlotV* lir)
3154 : {
3155 0 : ValueOperand dest = ToOutValue(lir);
3156 0 : Register base = ToRegister(lir->input());
3157 0 : int32_t offset = lir->mir()->slot() * sizeof(js::Value);
3158 :
3159 0 : masm.loadValue(Address(base, offset), dest);
3160 0 : }
3161 :
3162 : void
3163 0 : CodeGenerator::visitStoreSlotT(LStoreSlotT* lir)
3164 : {
3165 0 : Register base = ToRegister(lir->slots());
3166 0 : int32_t offset = lir->mir()->slot() * sizeof(js::Value);
3167 0 : Address dest(base, offset);
3168 :
3169 0 : if (lir->mir()->needsBarrier())
3170 0 : emitPreBarrier(dest);
3171 :
3172 0 : MIRType valueType = lir->mir()->value()->type();
3173 :
3174 0 : if (valueType == MIRType::ObjectOrNull) {
3175 0 : masm.storeObjectOrNull(ToRegister(lir->value()), dest);
3176 : } else {
3177 0 : ConstantOrRegister value;
3178 0 : if (lir->value()->isConstant())
3179 0 : value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
3180 : else
3181 0 : value = TypedOrValueRegister(valueType, ToAnyRegister(lir->value()));
3182 0 : masm.storeUnboxedValue(value, valueType, dest, lir->mir()->slotType());
3183 : }
3184 0 : }
3185 :
3186 : void
3187 0 : CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
3188 : {
3189 0 : Register base = ToRegister(lir->slots());
3190 0 : int32_t offset = lir->mir()->slot() * sizeof(Value);
3191 :
3192 0 : const ValueOperand value = ToValue(lir, LStoreSlotV::Value);
3193 :
3194 0 : if (lir->mir()->needsBarrier())
3195 0 : emitPreBarrier(Address(base, offset));
3196 :
3197 0 : masm.storeValue(value, Address(base, offset));
3198 0 : }
3199 :
3200 : static void
3201 0 : GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard,
3202 : Register obj, Register scratch, Label* miss, bool checkNullExpando)
3203 : {
3204 0 : if (guard.group) {
3205 0 : masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss);
3206 :
3207 0 : Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando());
3208 0 : if (guard.shape) {
3209 0 : masm.loadPtr(expandoAddress, scratch);
3210 0 : masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss);
3211 0 : masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss);
3212 0 : } else if (checkNullExpando) {
3213 0 : masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss);
3214 : }
3215 : } else {
3216 0 : masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss);
3217 : }
3218 0 : }
3219 :
3220 : void
3221 0 : CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
3222 : const TypedOrValueRegister& output)
3223 : {
3224 0 : MGetPropertyPolymorphic* mir = ins->mirRaw()->toGetPropertyPolymorphic();
3225 :
3226 0 : Label done;
3227 :
3228 0 : for (size_t i = 0; i < mir->numReceivers(); i++) {
3229 0 : ReceiverGuard receiver = mir->receiver(i);
3230 :
3231 0 : Label next;
3232 0 : masm.comment("GuardReceiver");
3233 0 : GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
3234 :
3235 0 : if (receiver.shape) {
3236 0 : masm.comment("loadTypedOrValue");
3237 : // If this is an unboxed expando access, GuardReceiver loaded the
3238 : // expando object into scratch.
3239 0 : Register target = receiver.group ? scratch : obj;
3240 :
3241 0 : Shape* shape = mir->shape(i);
3242 0 : if (shape->slot() < shape->numFixedSlots()) {
3243 : // Fixed slot.
3244 0 : masm.loadTypedOrValue(Address(target, NativeObject::getFixedSlotOffset(shape->slot())),
3245 0 : output);
3246 : } else {
3247 : // Dynamic slot.
3248 0 : uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
3249 0 : masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
3250 0 : masm.loadTypedOrValue(Address(scratch, offset), output);
3251 : }
3252 : } else {
3253 0 : masm.comment("loadUnboxedProperty");
3254 : const UnboxedLayout::Property* property =
3255 0 : receiver.group->unboxedLayout().lookup(mir->name());
3256 0 : Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
3257 :
3258 0 : masm.loadUnboxedProperty(propertyAddr, property->type, output);
3259 : }
3260 :
3261 0 : if (i == mir->numReceivers() - 1) {
3262 0 : bailoutFrom(&next, ins->snapshot());
3263 : } else {
3264 0 : masm.jump(&done);
3265 0 : masm.bind(&next);
3266 : }
3267 : }
3268 :
3269 0 : masm.bind(&done);
3270 0 : }
3271 :
3272 : void
3273 0 : CodeGenerator::visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV* ins)
3274 : {
3275 0 : Register obj = ToRegister(ins->obj());
3276 0 : ValueOperand output = GetValueOutput(ins);
3277 0 : emitGetPropertyPolymorphic(ins, obj, output.scratchReg(), output);
3278 0 : }
3279 :
3280 : void
3281 0 : CodeGenerator::visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins)
3282 : {
3283 0 : Register obj = ToRegister(ins->obj());
3284 0 : TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
3285 0 : Register temp = (output.type() == MIRType::Double)
3286 0 : ? ToRegister(ins->temp())
3287 0 : : output.typedReg().gpr();
3288 0 : emitGetPropertyPolymorphic(ins, obj, temp, output);
3289 0 : }
3290 :
3291 : template <typename T>
3292 : static void
3293 0 : EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type)
3294 : {
3295 0 : if (type == JSVAL_TYPE_OBJECT)
3296 0 : masm.guardedCallPreBarrier(address, MIRType::Object);
3297 0 : else if (type == JSVAL_TYPE_STRING)
3298 0 : masm.guardedCallPreBarrier(address, MIRType::String);
3299 : else
3300 0 : MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
3301 0 : }
3302 :
3303 : void
3304 0 : CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
3305 : const ConstantOrRegister& value)
3306 : {
3307 0 : MSetPropertyPolymorphic* mir = ins->mirRaw()->toSetPropertyPolymorphic();
3308 :
3309 0 : Label done;
3310 0 : for (size_t i = 0; i < mir->numReceivers(); i++) {
3311 0 : ReceiverGuard receiver = mir->receiver(i);
3312 :
3313 0 : Label next;
3314 0 : GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
3315 :
3316 0 : if (receiver.shape) {
3317 : // If this is an unboxed expando access, GuardReceiver loaded the
3318 : // expando object into scratch.
3319 0 : Register target = receiver.group ? scratch : obj;
3320 :
3321 0 : Shape* shape = mir->shape(i);
3322 0 : if (shape->slot() < shape->numFixedSlots()) {
3323 : // Fixed slot.
3324 0 : Address addr(target, NativeObject::getFixedSlotOffset(shape->slot()));
3325 0 : if (mir->needsBarrier())
3326 0 : emitPreBarrier(addr);
3327 0 : masm.storeConstantOrRegister(value, addr);
3328 : } else {
3329 : // Dynamic slot.
3330 0 : masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
3331 0 : Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
3332 0 : if (mir->needsBarrier())
3333 0 : emitPreBarrier(addr);
3334 0 : masm.storeConstantOrRegister(value, addr);
3335 : }
3336 : } else {
3337 : const UnboxedLayout::Property* property =
3338 0 : receiver.group->unboxedLayout().lookup(mir->name());
3339 0 : Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
3340 :
3341 0 : EmitUnboxedPreBarrier(masm, propertyAddr, property->type);
3342 0 : masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
3343 : }
3344 :
3345 0 : if (i == mir->numReceivers() - 1) {
3346 0 : bailoutFrom(&next, ins->snapshot());
3347 : } else {
3348 0 : masm.jump(&done);
3349 0 : masm.bind(&next);
3350 : }
3351 : }
3352 :
3353 0 : masm.bind(&done);
3354 0 : }
3355 :
3356 : void
3357 0 : CodeGenerator::visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins)
3358 : {
3359 0 : Register obj = ToRegister(ins->obj());
3360 0 : Register temp = ToRegister(ins->temp());
3361 0 : ValueOperand value = ToValue(ins, LSetPropertyPolymorphicV::Value);
3362 0 : emitSetPropertyPolymorphic(ins, obj, temp, TypedOrValueRegister(value));
3363 0 : }
3364 :
3365 : void
3366 0 : CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
3367 : {
3368 0 : Register obj = ToRegister(ins->obj());
3369 0 : Register temp = ToRegister(ins->temp());
3370 :
3371 0 : ConstantOrRegister value;
3372 0 : if (ins->mir()->value()->isConstant())
3373 0 : value = ConstantOrRegister(ins->mir()->value()->toConstant()->toJSValue());
3374 : else
3375 0 : value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value()));
3376 :
3377 0 : emitSetPropertyPolymorphic(ins, obj, temp, value);
3378 0 : }
3379 :
3380 : void
3381 7 : CodeGenerator::visitElements(LElements* lir)
3382 : {
3383 : Address elements(ToRegister(lir->object()),
3384 7 : lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
3385 7 : : NativeObject::offsetOfElements());
3386 7 : masm.loadPtr(elements, ToRegister(lir->output()));
3387 7 : }
3388 :
3389 : typedef bool (*ConvertElementsToDoublesFn)(JSContext*, uintptr_t);
3390 3 : static const VMFunction ConvertElementsToDoublesInfo =
3391 6 : FunctionInfo<ConvertElementsToDoublesFn>(ObjectElements::ConvertElementsToDoubles,
3392 : "ObjectElements::ConvertElementsToDoubles");
3393 :
3394 : void
3395 0 : CodeGenerator::visitConvertElementsToDoubles(LConvertElementsToDoubles* lir)
3396 : {
3397 0 : Register elements = ToRegister(lir->elements());
3398 :
3399 0 : OutOfLineCode* ool = oolCallVM(ConvertElementsToDoublesInfo, lir,
3400 0 : ArgList(elements), StoreNothing());
3401 :
3402 0 : Address convertedAddress(elements, ObjectElements::offsetOfFlags());
3403 0 : Imm32 bit(ObjectElements::CONVERT_DOUBLE_ELEMENTS);
3404 0 : masm.branchTest32(Assembler::Zero, convertedAddress, bit, ool->entry());
3405 0 : masm.bind(ool->rejoin());
3406 0 : }
3407 :
3408 : void
3409 0 : CodeGenerator::visitMaybeToDoubleElement(LMaybeToDoubleElement* lir)
3410 : {
3411 0 : Register elements = ToRegister(lir->elements());
3412 0 : Register value = ToRegister(lir->value());
3413 0 : ValueOperand out = ToOutValue(lir);
3414 :
3415 0 : FloatRegister temp = ToFloatRegister(lir->tempFloat());
3416 0 : Label convert, done;
3417 :
3418 : // If the CONVERT_DOUBLE_ELEMENTS flag is set, convert the int32
3419 : // value to double. Else, just box it.
3420 0 : masm.branchTest32(Assembler::NonZero,
3421 0 : Address(elements, ObjectElements::offsetOfFlags()),
3422 : Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
3423 0 : &convert);
3424 :
3425 0 : masm.tagValue(JSVAL_TYPE_INT32, value, out);
3426 0 : masm.jump(&done);
3427 :
3428 0 : masm.bind(&convert);
3429 0 : masm.convertInt32ToDouble(value, temp);
3430 0 : masm.boxDouble(temp, out);
3431 :
3432 0 : masm.bind(&done);
3433 0 : }
3434 :
3435 : typedef bool (*CopyElementsForWriteFn)(JSContext*, NativeObject*);
3436 3 : static const VMFunction CopyElementsForWriteInfo =
3437 6 : FunctionInfo<CopyElementsForWriteFn>(NativeObject::CopyElementsForWrite,
3438 : "NativeObject::CopyElementsForWrite");
3439 :
3440 : void
3441 0 : CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir)
3442 : {
3443 0 : Register object = ToRegister(lir->object());
3444 0 : Register temp = ToRegister(lir->temp());
3445 :
3446 0 : OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir,
3447 0 : ArgList(object), StoreNothing());
3448 :
3449 0 : if (lir->mir()->checkNative()) {
3450 0 : masm.loadObjClass(object, temp);
3451 0 : masm.branchTest32(Assembler::NonZero, Address(temp, Class::offsetOfFlags()),
3452 0 : Imm32(Class::NON_NATIVE), ool->rejoin());
3453 : }
3454 :
3455 0 : masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp);
3456 0 : masm.branchTest32(Assembler::NonZero,
3457 0 : Address(temp, ObjectElements::offsetOfFlags()),
3458 : Imm32(ObjectElements::COPY_ON_WRITE),
3459 0 : ool->entry());
3460 0 : masm.bind(ool->rejoin());
3461 0 : }
3462 :
3463 : void
3464 6 : CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment* lir)
3465 : {
3466 6 : Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
3467 6 : masm.loadPtr(environment, ToRegister(lir->output()));
3468 6 : }
3469 :
3470 : typedef LexicalEnvironmentObject* (*NewLexicalEnvironmentObjectFn)(JSContext*,
3471 : Handle<LexicalScope*>,
3472 : HandleObject, gc::InitialHeap);
3473 3 : static const VMFunction NewLexicalEnvironmentObjectInfo =
3474 6 : FunctionInfo<NewLexicalEnvironmentObjectFn>(LexicalEnvironmentObject::create,
3475 : "LexicalEnvironmentObject::create");
3476 :
3477 : void
3478 0 : CodeGenerator::visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir)
3479 : {
3480 0 : pushArg(Imm32(gc::DefaultHeap));
3481 0 : pushArg(ToRegister(lir->enclosing()));
3482 0 : pushArg(ImmGCPtr(lir->mir()->scope()));
3483 0 : callVM(NewLexicalEnvironmentObjectInfo, lir);
3484 0 : }
3485 :
3486 : typedef JSObject* (*CopyLexicalEnvironmentObjectFn)(JSContext*, HandleObject, bool);
3487 3 : static const VMFunction CopyLexicalEnvironmentObjectInfo =
3488 6 : FunctionInfo<CopyLexicalEnvironmentObjectFn>(js::jit::CopyLexicalEnvironmentObject,
3489 : "js::jit::CopyLexicalEnvironmentObject");
3490 :
3491 : void
3492 0 : CodeGenerator::visitCopyLexicalEnvironmentObject(LCopyLexicalEnvironmentObject* lir)
3493 : {
3494 0 : pushArg(Imm32(lir->mir()->copySlots()));
3495 0 : pushArg(ToRegister(lir->env()));
3496 0 : callVM(CopyLexicalEnvironmentObjectInfo, lir);
3497 0 : }
3498 :
3499 : void
3500 0 : CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity* guard)
3501 : {
3502 0 : Register input = ToRegister(guard->input());
3503 0 : Register expected = ToRegister(guard->expected());
3504 :
3505 : Assembler::Condition cond =
3506 0 : guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
3507 0 : bailoutCmpPtr(cond, input, expected, guard->snapshot());
3508 0 : }
3509 :
3510 : void
3511 0 : CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
3512 : {
3513 0 : const MGuardReceiverPolymorphic* mir = lir->mir();
3514 0 : Register obj = ToRegister(lir->object());
3515 0 : Register temp = ToRegister(lir->temp());
3516 :
3517 0 : Label done;
3518 :
3519 0 : for (size_t i = 0; i < mir->numReceivers(); i++) {
3520 0 : const ReceiverGuard& receiver = mir->receiver(i);
3521 :
3522 0 : Label next;
3523 0 : GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true);
3524 :
3525 0 : if (i == mir->numReceivers() - 1) {
3526 0 : bailoutFrom(&next, lir->snapshot());
3527 : } else {
3528 0 : masm.jump(&done);
3529 0 : masm.bind(&next);
3530 : }
3531 : }
3532 :
3533 0 : masm.bind(&done);
3534 0 : }
3535 :
3536 : void
3537 0 : CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir)
3538 : {
3539 0 : Label miss;
3540 :
3541 0 : Register obj = ToRegister(lir->object());
3542 0 : masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual,
3543 0 : Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss);
3544 :
3545 0 : bailoutFrom(&miss, lir->snapshot());
3546 0 : }
3547 :
3548 : void
3549 0 : CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
3550 : {
3551 0 : Register obj = ToRegister(lir->object());
3552 0 : Register result = ToRegister(lir->getDef(0));
3553 :
3554 0 : masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
3555 0 : }
3556 :
3557 : void
3558 47 : CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
3559 : {
3560 47 : ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
3561 47 : Register scratch = ToTempRegisterOrInvalid(lir->temp());
3562 :
3563 94 : Label miss;
3564 47 : masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), lir->mir()->barrierKind(), scratch, &miss);
3565 47 : bailoutFrom(&miss, lir->snapshot());
3566 47 : }
3567 :
3568 : void
3569 21 : CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir)
3570 : {
3571 21 : Register obj = ToRegister(lir->object());
3572 21 : Register scratch = ToTempRegisterOrInvalid(lir->temp());
3573 42 : Label miss, ok;
3574 :
3575 21 : if (lir->mir()->type() == MIRType::ObjectOrNull) {
3576 0 : masm.comment("Object or Null");
3577 0 : Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok : &miss;
3578 0 : masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget);
3579 : } else {
3580 21 : MOZ_ASSERT(lir->mir()->type() == MIRType::Object);
3581 21 : MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
3582 : }
3583 :
3584 21 : if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) {
3585 21 : masm.comment("Type tag only");
3586 21 : masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss);
3587 : }
3588 :
3589 21 : bailoutFrom(&miss, lir->snapshot());
3590 21 : masm.bind(&ok);
3591 21 : }
3592 :
3593 : void
3594 0 : CodeGenerator::visitMonitorTypes(LMonitorTypes* lir)
3595 : {
3596 0 : ValueOperand operand = ToValue(lir, LMonitorTypes::Input);
3597 0 : Register scratch = ToTempUnboxRegister(lir->temp());
3598 :
3599 0 : Label matched, miss;
3600 0 : masm.guardTypeSet(operand, lir->mir()->typeSet(), lir->mir()->barrierKind(), scratch, &miss);
3601 0 : bailoutFrom(&miss, lir->snapshot());
3602 0 : }
3603 :
3604 : // Out-of-line path to update the store buffer.
3605 : class OutOfLineCallPostWriteBarrier : public OutOfLineCodeBase<CodeGenerator>
3606 : {
3607 : LInstruction* lir_;
3608 : const LAllocation* object_;
3609 :
3610 : public:
3611 2 : OutOfLineCallPostWriteBarrier(LInstruction* lir, const LAllocation* object)
3612 2 : : lir_(lir), object_(object)
3613 2 : { }
3614 :
3615 2 : void accept(CodeGenerator* codegen) {
3616 2 : codegen->visitOutOfLineCallPostWriteBarrier(this);
3617 2 : }
3618 :
3619 4 : LInstruction* lir() const {
3620 4 : return lir_;
3621 : }
3622 2 : const LAllocation* object() const {
3623 2 : return object_;
3624 : }
3625 : };
3626 :
3627 : static void
3628 0 : EmitStoreBufferCheckForConstant(MacroAssembler& masm, JSObject* object,
3629 : AllocatableGeneralRegisterSet& regs, Label* exit, Label* callVM)
3630 : {
3631 0 : Register temp = regs.takeAny();
3632 :
3633 0 : const gc::TenuredCell* cell = &object->asTenured();
3634 0 : gc::Arena* arena = cell->arena();
3635 :
3636 0 : Register cells = temp;
3637 0 : masm.loadPtr(AbsoluteAddress(&arena->bufferedCells()), cells);
3638 :
3639 0 : size_t index = gc::ArenaCellSet::getCellIndex(cell);
3640 : size_t word;
3641 : uint32_t mask;
3642 0 : gc::ArenaCellSet::getWordIndexAndMask(index, &word, &mask);
3643 0 : size_t offset = gc::ArenaCellSet::offsetOfBits() + word * sizeof(uint32_t);
3644 :
3645 0 : masm.branchTest32(Assembler::NonZero, Address(cells, offset), Imm32(mask), exit);
3646 :
3647 : // Check whether this is the sentinel set and if so call the VM to allocate
3648 : // one for this arena.
3649 0 : masm.branchPtr(Assembler::Equal, Address(cells, gc::ArenaCellSet::offsetOfArena()),
3650 0 : ImmPtr(nullptr), callVM);
3651 :
3652 : // Add the cell to the set.
3653 0 : masm.or32(Imm32(mask), Address(cells, offset));
3654 0 : masm.jump(exit);
3655 :
3656 0 : regs.add(temp);
3657 0 : }
3658 :
3659 : static void
3660 2 : EmitPostWriteBarrier(MacroAssembler& masm, Register objreg, JSObject* maybeConstant, bool isGlobal,
3661 : AllocatableGeneralRegisterSet& regs)
3662 : {
3663 2 : MOZ_ASSERT_IF(isGlobal, maybeConstant);
3664 :
3665 4 : Label callVM;
3666 4 : Label exit;
3667 :
3668 : // We already have a fast path to check whether a global is in the store
3669 : // buffer.
3670 2 : if (!isGlobal && maybeConstant)
3671 0 : EmitStoreBufferCheckForConstant(masm, maybeConstant, regs, &exit, &callVM);
3672 :
3673 : // Call into the VM to barrier the write.
3674 2 : masm.bind(&callVM);
3675 :
3676 2 : Register runtimereg = regs.takeAny();
3677 2 : masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
3678 :
3679 2 : void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
3680 2 : masm.setupUnalignedABICall(regs.takeAny());
3681 2 : masm.passABIArg(runtimereg);
3682 2 : masm.passABIArg(objreg);
3683 2 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
3684 :
3685 2 : masm.bind(&exit);
3686 2 : }
3687 :
3688 : void
3689 2 : CodeGenerator::emitPostWriteBarrier(const LAllocation* obj)
3690 : {
3691 2 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
3692 :
3693 2 : Register objreg;
3694 2 : JSObject* object = nullptr;
3695 2 : bool isGlobal = false;
3696 2 : if (obj->isConstant()) {
3697 0 : object = &obj->toConstant()->toObject();
3698 0 : isGlobal = isGlobalObject(object);
3699 0 : objreg = regs.takeAny();
3700 0 : masm.movePtr(ImmGCPtr(object), objreg);
3701 : } else {
3702 2 : objreg = ToRegister(obj);
3703 2 : regs.takeUnchecked(objreg);
3704 : }
3705 :
3706 2 : EmitPostWriteBarrier(masm, objreg, object, isGlobal, regs);
3707 2 : }
3708 :
3709 : void
3710 0 : CodeGenerator::emitPostWriteBarrier(Register objreg)
3711 : {
3712 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
3713 0 : regs.takeUnchecked(objreg);
3714 0 : EmitPostWriteBarrier(masm, objreg, nullptr, false, regs);
3715 0 : }
3716 :
3717 : void
3718 2 : CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool)
3719 : {
3720 2 : saveLiveVolatile(ool->lir());
3721 2 : const LAllocation* obj = ool->object();
3722 2 : emitPostWriteBarrier(obj);
3723 2 : restoreLiveVolatile(ool->lir());
3724 :
3725 2 : masm.jump(ool->rejoin());
3726 2 : }
3727 :
3728 : void
3729 2 : CodeGenerator::maybeEmitGlobalBarrierCheck(const LAllocation* maybeGlobal, OutOfLineCode* ool)
3730 : {
3731 : // Check whether an object is a global that we have already barriered before
3732 : // calling into the VM.
3733 :
3734 2 : if (!maybeGlobal->isConstant())
3735 4 : return;
3736 :
3737 0 : JSObject* obj = &maybeGlobal->toConstant()->toObject();
3738 0 : if (!isGlobalObject(obj))
3739 0 : return;
3740 :
3741 0 : JSCompartment* comp = obj->compartment();
3742 0 : auto addr = AbsoluteAddress(&comp->globalWriteBarriered);
3743 0 : masm.branch32(Assembler::NotEqual, addr, Imm32(0), ool->rejoin());
3744 : }
3745 :
3746 : template <class LPostBarrierType>
3747 : void
3748 1 : CodeGenerator::visitPostWriteBarrierCommonO(LPostBarrierType* lir, OutOfLineCode* ool)
3749 : {
3750 1 : addOutOfLineCode(ool, lir->mir());
3751 :
3752 1 : Register temp = ToTempRegisterOrInvalid(lir->temp());
3753 :
3754 1 : if (lir->object()->isConstant()) {
3755 : // Constant nursery objects cannot appear here, see LIRGenerator::visitPostWriteElementBarrier.
3756 0 : MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject()));
3757 : } else {
3758 1 : masm.branchPtrInNurseryChunk(Assembler::Equal, ToRegister(lir->object()), temp,
3759 : ool->rejoin());
3760 : }
3761 :
3762 1 : maybeEmitGlobalBarrierCheck(lir->object(), ool);
3763 :
3764 1 : Register valueObj = ToRegister(lir->value());
3765 1 : if (lir->mir()->value()->type() == MIRType::ObjectOrNull)
3766 0 : masm.branchTestPtr(Assembler::Zero, valueObj, valueObj, ool->rejoin());
3767 : else
3768 1 : MOZ_ASSERT(lir->mir()->value()->type() == MIRType::Object);
3769 1 : masm.branchPtrInNurseryChunk(Assembler::Equal, valueObj, temp, ool->entry());
3770 :
3771 1 : masm.bind(ool->rejoin());
3772 1 : }
3773 :
3774 : template <class LPostBarrierType>
3775 : void
3776 1 : CodeGenerator::visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool)
3777 : {
3778 1 : addOutOfLineCode(ool, lir->mir());
3779 :
3780 1 : Register temp = ToTempRegisterOrInvalid(lir->temp());
3781 :
3782 1 : if (lir->object()->isConstant()) {
3783 : // Constant nursery objects cannot appear here, see LIRGenerator::visitPostWriteElementBarrier.
3784 0 : MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject()));
3785 : } else {
3786 1 : masm.branchPtrInNurseryChunk(Assembler::Equal, ToRegister(lir->object()), temp,
3787 : ool->rejoin());
3788 : }
3789 :
3790 1 : maybeEmitGlobalBarrierCheck(lir->object(), ool);
3791 :
3792 1 : ValueOperand value = ToValue(lir, LPostBarrierType::Input);
3793 1 : masm.branchValueIsNurseryObject(Assembler::Equal, value, temp, ool->entry());
3794 :
3795 1 : masm.bind(ool->rejoin());
3796 1 : }
3797 :
3798 : void
3799 1 : CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO* lir)
3800 : {
3801 1 : auto ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
3802 1 : visitPostWriteBarrierCommonO(lir, ool);
3803 1 : }
3804 :
3805 : void
3806 1 : CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV* lir)
3807 : {
3808 1 : auto ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
3809 1 : visitPostWriteBarrierCommonV(lir, ool);
3810 1 : }
3811 :
3812 : // Out-of-line path to update the store buffer.
3813 : class OutOfLineCallPostWriteElementBarrier : public OutOfLineCodeBase<CodeGenerator>
3814 : {
3815 : LInstruction* lir_;
3816 : const LAllocation* object_;
3817 : const LAllocation* index_;
3818 :
3819 : public:
3820 0 : OutOfLineCallPostWriteElementBarrier(LInstruction* lir, const LAllocation* object,
3821 : const LAllocation* index)
3822 0 : : lir_(lir),
3823 : object_(object),
3824 0 : index_(index)
3825 0 : { }
3826 :
3827 0 : void accept(CodeGenerator* codegen) {
3828 0 : codegen->visitOutOfLineCallPostWriteElementBarrier(this);
3829 0 : }
3830 :
3831 0 : LInstruction* lir() const {
3832 0 : return lir_;
3833 : }
3834 :
3835 0 : const LAllocation* object() const {
3836 0 : return object_;
3837 : }
3838 :
3839 0 : const LAllocation* index() const {
3840 0 : return index_;
3841 : }
3842 : };
3843 :
3844 : void
3845 0 : CodeGenerator::visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool)
3846 : {
3847 0 : saveLiveVolatile(ool->lir());
3848 :
3849 0 : const LAllocation* obj = ool->object();
3850 0 : const LAllocation* index = ool->index();
3851 :
3852 0 : Register objreg = obj->isConstant() ? InvalidReg : ToRegister(obj);
3853 0 : Register indexreg = ToRegister(index);
3854 :
3855 0 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
3856 0 : regs.takeUnchecked(indexreg);
3857 :
3858 0 : if (obj->isConstant()) {
3859 0 : objreg = regs.takeAny();
3860 0 : masm.movePtr(ImmGCPtr(&obj->toConstant()->toObject()), objreg);
3861 : } else {
3862 0 : regs.takeUnchecked(objreg);
3863 : }
3864 :
3865 0 : Register runtimereg = regs.takeAny();
3866 0 : masm.setupUnalignedABICall(runtimereg);
3867 0 : masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
3868 0 : masm.passABIArg(runtimereg);
3869 0 : masm.passABIArg(objreg);
3870 0 : masm.passABIArg(indexreg);
3871 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (PostWriteElementBarrier<IndexInBounds::Maybe>)));
3872 :
3873 0 : restoreLiveVolatile(ool->lir());
3874 :
3875 0 : masm.jump(ool->rejoin());
3876 0 : }
3877 :
3878 : void
3879 0 : CodeGenerator::visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir)
3880 : {
3881 0 : auto ool = new(alloc()) OutOfLineCallPostWriteElementBarrier(lir, lir->object(), lir->index());
3882 0 : visitPostWriteBarrierCommonO(lir, ool);
3883 0 : }
3884 :
3885 : void
3886 0 : CodeGenerator::visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir)
3887 : {
3888 0 : auto ool = new(alloc()) OutOfLineCallPostWriteElementBarrier(lir, lir->object(), lir->index());
3889 0 : visitPostWriteBarrierCommonV(lir, ool);
3890 0 : }
3891 :
3892 : void
3893 9 : CodeGenerator::visitCallNative(LCallNative* call)
3894 : {
3895 9 : WrappedFunction* target = call->getSingleTarget();
3896 9 : MOZ_ASSERT(target);
3897 9 : MOZ_ASSERT(target->isNative());
3898 :
3899 9 : int callargslot = call->argslot();
3900 9 : int unusedStack = StackOffsetOfPassedArg(callargslot);
3901 :
3902 : // Registers used for callWithABI() argument-passing.
3903 9 : const Register argContextReg = ToRegister(call->getArgContextReg());
3904 9 : const Register argUintNReg = ToRegister(call->getArgUintNReg());
3905 9 : const Register argVpReg = ToRegister(call->getArgVpReg());
3906 :
3907 : // Misc. temporary registers.
3908 9 : const Register tempReg = ToRegister(call->getTempReg());
3909 :
3910 18 : DebugOnly<uint32_t> initialStack = masm.framePushed();
3911 :
3912 9 : masm.checkStackAlignment();
3913 :
3914 : // Native functions have the signature:
3915 : // bool (*)(JSContext*, unsigned, Value* vp)
3916 : // Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
3917 : // are the function arguments.
3918 :
3919 : // Allocate space for the outparam, moving the StackPointer to what will be &vp[1].
3920 9 : masm.adjustStack(unusedStack);
3921 :
3922 : // Push a Value containing the callee object: natives are allowed to access their callee before
3923 : // setitng the return value. The StackPointer is moved to &vp[0].
3924 9 : masm.Push(ObjectValue(*target->rawJSFunction()));
3925 :
3926 : // Preload arguments into registers.
3927 9 : masm.loadJSContext(argContextReg);
3928 9 : masm.move32(Imm32(call->numActualArgs()), argUintNReg);
3929 9 : masm.moveStackPtrTo(argVpReg);
3930 :
3931 9 : masm.Push(argUintNReg);
3932 :
3933 : // Construct native exit frame.
3934 9 : uint32_t safepointOffset = masm.buildFakeExitFrame(tempReg);
3935 9 : masm.enterFakeExitFrameForNative(argContextReg, tempReg, call->mir()->isConstructing());
3936 :
3937 9 : markSafepointAt(safepointOffset, call);
3938 :
3939 9 : emitTracelogStartEvent(TraceLogger_Call);
3940 :
3941 : // Construct and execute call.
3942 9 : masm.setupUnalignedABICall(tempReg);
3943 9 : masm.passABIArg(argContextReg);
3944 9 : masm.passABIArg(argUintNReg);
3945 9 : masm.passABIArg(argVpReg);
3946 9 : JSNative native = target->native();
3947 9 : if (call->ignoresReturnValue()) {
3948 1 : const JSJitInfo* jitInfo = target->jitInfo();
3949 1 : if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
3950 0 : native = jitInfo->ignoresReturnValueMethod;
3951 : }
3952 9 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native));
3953 :
3954 9 : emitTracelogStopEvent(TraceLogger_Call);
3955 :
3956 : // Test for failure.
3957 9 : masm.branchIfFalseBool(ReturnReg, masm.failureLabel());
3958 :
3959 : // Load the outparam vp[0] into output register(s).
3960 9 : masm.loadValue(Address(masm.getStackPointer(), NativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
3961 :
3962 : // The next instruction is removing the footer of the exit frame, so there
3963 : // is no need for leaveFakeExitFrame.
3964 :
3965 : // Move the StackPointer back to its original location, unwinding the native exit frame.
3966 9 : masm.adjustStack(NativeExitFrameLayout::Size() - unusedStack);
3967 9 : MOZ_ASSERT(masm.framePushed() == initialStack);
3968 9 : }
3969 :
3970 : static void
3971 0 : LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv)
3972 : {
3973 : // Load the value in DOM_OBJECT_SLOT for a native or proxy DOM object. This
3974 : // will be in the first slot but may be fixed or non-fixed.
3975 0 : MOZ_ASSERT(obj != priv);
3976 :
3977 : // Check shape->numFixedSlots != 0.
3978 0 : masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), priv);
3979 :
3980 0 : Label hasFixedSlots, done;
3981 0 : masm.branchTest32(Assembler::NonZero,
3982 0 : Address(priv, Shape::offsetOfSlotInfo()),
3983 0 : Imm32(Shape::fixedSlotsMask()),
3984 0 : &hasFixedSlots);
3985 :
3986 0 : masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), priv);
3987 0 : masm.loadPrivate(Address(priv, 0), priv);
3988 :
3989 0 : masm.jump(&done);
3990 0 : masm.bind(&hasFixedSlots);
3991 :
3992 0 : masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), priv);
3993 :
3994 0 : masm.bind(&done);
3995 0 : }
3996 :
3997 : void
3998 0 : CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
3999 : {
4000 0 : WrappedFunction* target = call->getSingleTarget();
4001 0 : MOZ_ASSERT(target);
4002 0 : MOZ_ASSERT(target->isNative());
4003 0 : MOZ_ASSERT(target->jitInfo());
4004 0 : MOZ_ASSERT(call->mir()->isCallDOMNative());
4005 :
4006 0 : int callargslot = call->argslot();
4007 0 : int unusedStack = StackOffsetOfPassedArg(callargslot);
4008 :
4009 : // Registers used for callWithABI() argument-passing.
4010 0 : const Register argJSContext = ToRegister(call->getArgJSContext());
4011 0 : const Register argObj = ToRegister(call->getArgObj());
4012 0 : const Register argPrivate = ToRegister(call->getArgPrivate());
4013 0 : const Register argArgs = ToRegister(call->getArgArgs());
4014 :
4015 0 : DebugOnly<uint32_t> initialStack = masm.framePushed();
4016 :
4017 0 : masm.checkStackAlignment();
4018 :
4019 : // DOM methods have the signature:
4020 : // bool (*)(JSContext*, HandleObject, void* private, const JSJitMethodCallArgs& args)
4021 : // Where args is initialized from an argc and a vp, vp[0] is space for an
4022 : // outparam and the callee, vp[1] is |this|, and vp[2] onward are the
4023 : // function arguments. Note that args stores the argv, not the vp, and
4024 : // argv == vp + 2.
4025 :
4026 : // Nestle the stack up against the pushed arguments, leaving StackPointer at
4027 : // &vp[1]
4028 0 : masm.adjustStack(unusedStack);
4029 : // argObj is filled with the extracted object, then returned.
4030 0 : Register obj = masm.extractObject(Address(masm.getStackPointer(), 0), argObj);
4031 0 : MOZ_ASSERT(obj == argObj);
4032 :
4033 : // Push a Value containing the callee object: natives are allowed to access their callee before
4034 : // setitng the return value. After this the StackPointer points to &vp[0].
4035 0 : masm.Push(ObjectValue(*target->rawJSFunction()));
4036 :
4037 : // Now compute the argv value. Since StackPointer is pointing to &vp[0] and
4038 : // argv is &vp[2] we just need to add 2*sizeof(Value) to the current
4039 : // StackPointer.
4040 : JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgv == 0);
4041 : JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgc ==
4042 : IonDOMMethodExitFrameLayoutTraits::offsetOfArgcFromArgv);
4043 0 : masm.computeEffectiveAddress(Address(masm.getStackPointer(), 2 * sizeof(Value)), argArgs);
4044 :
4045 0 : LoadDOMPrivate(masm, obj, argPrivate);
4046 :
4047 : // Push argc from the call instruction into what will become the IonExitFrame
4048 0 : masm.Push(Imm32(call->numActualArgs()));
4049 :
4050 : // Push our argv onto the stack
4051 0 : masm.Push(argArgs);
4052 : // And store our JSJitMethodCallArgs* in argArgs.
4053 0 : masm.moveStackPtrTo(argArgs);
4054 :
4055 : // Push |this| object for passing HandleObject. We push after argc to
4056 : // maintain the same sp-relative location of the object pointer with other
4057 : // DOMExitFrames.
4058 0 : masm.Push(argObj);
4059 0 : masm.moveStackPtrTo(argObj);
4060 :
4061 : // Construct native exit frame.
4062 0 : uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
4063 0 : masm.loadJSContext(argJSContext);
4064 0 : masm.enterFakeExitFrame(argJSContext, argJSContext, IonDOMMethodExitFrameLayoutToken);
4065 :
4066 0 : markSafepointAt(safepointOffset, call);
4067 :
4068 : // Construct and execute call.
4069 0 : masm.setupUnalignedABICall(argJSContext);
4070 0 : masm.loadJSContext(argJSContext);
4071 0 : masm.passABIArg(argJSContext);
4072 0 : masm.passABIArg(argObj);
4073 0 : masm.passABIArg(argPrivate);
4074 0 : masm.passABIArg(argArgs);
4075 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->jitInfo()->method));
4076 :
4077 0 : if (target->jitInfo()->isInfallible) {
4078 0 : masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
4079 0 : JSReturnOperand);
4080 : } else {
4081 : // Test for failure.
4082 0 : masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
4083 :
4084 : // Load the outparam vp[0] into output register(s).
4085 0 : masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
4086 0 : JSReturnOperand);
4087 : }
4088 :
4089 : // The next instruction is removing the footer of the exit frame, so there
4090 : // is no need for leaveFakeExitFrame.
4091 :
4092 : // Move the StackPointer back to its original location, unwinding the native exit frame.
4093 0 : masm.adjustStack(IonDOMMethodExitFrameLayout::Size() - unusedStack);
4094 0 : MOZ_ASSERT(masm.framePushed() == initialStack);
4095 0 : }
4096 :
4097 : typedef bool (*GetIntrinsicValueFn)(JSContext* cx, HandlePropertyName, MutableHandleValue);
4098 3 : static const VMFunction GetIntrinsicValueInfo =
4099 6 : FunctionInfo<GetIntrinsicValueFn>(GetIntrinsicValue, "GetIntrinsicValue");
4100 :
4101 : void
4102 1 : CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
4103 : {
4104 1 : pushArg(ImmGCPtr(lir->mir()->name()));
4105 1 : callVM(GetIntrinsicValueInfo, lir);
4106 1 : }
4107 :
4108 : typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*,
4109 : MutableHandleValue);
4110 3 : static const VMFunction InvokeFunctionInfo =
4111 6 : FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction");
4112 :
4113 : void
4114 18 : CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
4115 : bool constructing, bool ignoresReturnValue,
4116 : uint32_t argc, uint32_t unusedStack)
4117 : {
4118 : // Nestle %esp up to the argument vector.
4119 : // Each path must account for framePushed_ separately, for callVM to be valid.
4120 18 : masm.freeStack(unusedStack);
4121 :
4122 18 : pushArg(masm.getStackPointer()); // argv.
4123 18 : pushArg(Imm32(argc)); // argc.
4124 18 : pushArg(Imm32(ignoresReturnValue));
4125 18 : pushArg(Imm32(constructing)); // constructing.
4126 18 : pushArg(calleereg); // JSFunction*.
4127 :
4128 18 : callVM(InvokeFunctionInfo, call);
4129 :
4130 : // Un-nestle %esp from the argument vector. No prefix was pushed.
4131 18 : masm.reserveStack(unusedStack);
4132 18 : }
4133 :
4134 : void
4135 9 : CodeGenerator::visitCallGeneric(LCallGeneric* call)
4136 : {
4137 9 : Register calleereg = ToRegister(call->getFunction());
4138 9 : Register objreg = ToRegister(call->getTempObject());
4139 9 : Register nargsreg = ToRegister(call->getNargsReg());
4140 9 : uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
4141 18 : Label invoke, thunk, makeCall, end;
4142 :
4143 : // Known-target case is handled by LCallKnown.
4144 9 : MOZ_ASSERT(!call->hasSingleTarget());
4145 :
4146 : // Generate an ArgumentsRectifier.
4147 9 : JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
4148 :
4149 9 : masm.checkStackAlignment();
4150 :
4151 : // Guard that calleereg is actually a function object.
4152 9 : masm.loadObjClass(calleereg, nargsreg);
4153 9 : masm.branchPtr(Assembler::NotEqual, nargsreg, ImmPtr(&JSFunction::class_), &invoke);
4154 :
4155 : // Guard that calleereg is an interpreted function with a JSScript.
4156 : // If we are constructing, also ensure the callee is a constructor.
4157 9 : if (call->mir()->isConstructing()) {
4158 4 : masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
4159 : } else {
4160 5 : masm.branchIfFunctionHasNoScript(calleereg, &invoke);
4161 5 : masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, calleereg, objreg, &invoke);
4162 : }
4163 :
4164 : // Knowing that calleereg is a non-native function, load the JSScript.
4165 9 : masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
4166 :
4167 : // Load script jitcode.
4168 9 : masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
4169 :
4170 : // Nestle the StackPointer up to the argument vector.
4171 9 : masm.freeStack(unusedStack);
4172 :
4173 : // Construct the IonFramePrefix.
4174 9 : uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
4175 18 : JitFrameLayout::Size());
4176 9 : masm.Push(Imm32(call->numActualArgs()));
4177 9 : masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
4178 9 : masm.Push(Imm32(descriptor));
4179 :
4180 : // Check whether the provided arguments satisfy target argc.
4181 : // We cannot have lowered to LCallGeneric with a known target. Assert that we didn't
4182 : // add any undefineds in IonBuilder. NB: MCall::numStackArgs includes |this|.
4183 18 : DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
4184 9 : MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - numNonArgsOnStack);
4185 9 : masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nargsreg);
4186 9 : masm.branch32(Assembler::Above, nargsreg, Imm32(call->numActualArgs()), &thunk);
4187 9 : masm.jump(&makeCall);
4188 :
4189 : // Argument fixed needed. Load the ArgumentsRectifier.
4190 9 : masm.bind(&thunk);
4191 : {
4192 9 : MOZ_ASSERT(ArgumentsRectifierReg != objreg);
4193 9 : masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
4194 9 : masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
4195 9 : masm.move32(Imm32(call->numActualArgs()), ArgumentsRectifierReg);
4196 : }
4197 :
4198 : // Finally call the function in objreg.
4199 9 : masm.bind(&makeCall);
4200 9 : uint32_t callOffset = masm.callJit(objreg);
4201 9 : markSafepointAt(callOffset, call);
4202 :
4203 : // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
4204 : // The return address has already been removed from the Ion frame.
4205 9 : int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
4206 9 : masm.adjustStack(prefixGarbage - unusedStack);
4207 9 : masm.jump(&end);
4208 :
4209 : // Handle uncompiled or native functions.
4210 9 : masm.bind(&invoke);
4211 9 : emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
4212 9 : call->numActualArgs(), unusedStack);
4213 :
4214 9 : masm.bind(&end);
4215 :
4216 : // If the return value of the constructing function is Primitive,
4217 : // replace the return value with the Object from CreateThis.
4218 9 : if (call->mir()->isConstructing()) {
4219 8 : Label notPrimitive;
4220 4 : masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
4221 4 : masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand);
4222 4 : masm.bind(¬Primitive);
4223 : }
4224 9 : }
4225 :
4226 : typedef bool (*InvokeFunctionShuffleFn)(JSContext*, HandleObject, uint32_t, uint32_t, Value*,
4227 : MutableHandleValue);
4228 3 : static const VMFunction InvokeFunctionShuffleInfo =
4229 6 : FunctionInfo<InvokeFunctionShuffleFn>(InvokeFunctionShuffleNewTarget,
4230 : "InvokeFunctionShuffleNewTarget");
4231 : void
4232 0 : CodeGenerator::emitCallInvokeFunctionShuffleNewTarget(LCallKnown* call, Register calleeReg,
4233 : uint32_t numFormals, uint32_t unusedStack)
4234 : {
4235 0 : masm.freeStack(unusedStack);
4236 :
4237 0 : pushArg(masm.getStackPointer());
4238 0 : pushArg(Imm32(numFormals));
4239 0 : pushArg(Imm32(call->numActualArgs()));
4240 0 : pushArg(calleeReg);
4241 :
4242 0 : callVM(InvokeFunctionShuffleInfo, call);
4243 :
4244 0 : masm.reserveStack(unusedStack);
4245 0 : }
4246 :
4247 : void
4248 9 : CodeGenerator::visitCallKnown(LCallKnown* call)
4249 : {
4250 9 : Register calleereg = ToRegister(call->getFunction());
4251 9 : Register objreg = ToRegister(call->getTempObject());
4252 9 : uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
4253 9 : WrappedFunction* target = call->getSingleTarget();
4254 18 : Label end, uncompiled;
4255 :
4256 : // Native single targets are handled by LCallNative.
4257 9 : MOZ_ASSERT(!target->isNative());
4258 : // Missing arguments must have been explicitly appended by the IonBuilder.
4259 18 : DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
4260 9 : MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack);
4261 :
4262 9 : MOZ_ASSERT_IF(call->isConstructing(), target->isConstructor());
4263 :
4264 9 : masm.checkStackAlignment();
4265 :
4266 9 : if (target->isClassConstructor() && !call->isConstructing()) {
4267 0 : emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
4268 0 : call->numActualArgs(), unusedStack);
4269 0 : return;
4270 : }
4271 :
4272 9 : MOZ_ASSERT_IF(target->isClassConstructor(), call->isConstructing());
4273 :
4274 : // The calleereg is known to be a non-native function, but might point to
4275 : // a LazyScript instead of a JSScript.
4276 9 : masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
4277 :
4278 : // Knowing that calleereg is a non-native function, load the JSScript.
4279 9 : masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
4280 :
4281 : // Load script jitcode.
4282 9 : if (call->mir()->needsArgCheck())
4283 2 : masm.loadBaselineOrIonRaw(objreg, objreg, &uncompiled);
4284 : else
4285 7 : masm.loadBaselineOrIonNoArgCheck(objreg, objreg, &uncompiled);
4286 :
4287 : // Nestle the StackPointer up to the argument vector.
4288 9 : masm.freeStack(unusedStack);
4289 :
4290 : // Construct the IonFramePrefix.
4291 9 : uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
4292 18 : JitFrameLayout::Size());
4293 9 : masm.Push(Imm32(call->numActualArgs()));
4294 9 : masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
4295 9 : masm.Push(Imm32(descriptor));
4296 :
4297 : // Finally call the function in objreg.
4298 9 : uint32_t callOffset = masm.callJit(objreg);
4299 9 : markSafepointAt(callOffset, call);
4300 :
4301 : // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
4302 : // The return address has already been removed from the Ion frame.
4303 9 : int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
4304 9 : masm.adjustStack(prefixGarbage - unusedStack);
4305 9 : masm.jump(&end);
4306 :
4307 : // Handle uncompiled functions.
4308 9 : masm.bind(&uncompiled);
4309 9 : if (call->isConstructing() && target->nargs() > call->numActualArgs())
4310 0 : emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
4311 : else
4312 9 : emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
4313 9 : call->numActualArgs(), unusedStack);
4314 :
4315 9 : masm.bind(&end);
4316 :
4317 : // If the return value of the constructing function is Primitive,
4318 : // replace the return value with the Object from CreateThis.
4319 9 : if (call->mir()->isConstructing()) {
4320 0 : Label notPrimitive;
4321 0 : masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
4322 0 : masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand);
4323 0 : masm.bind(¬Primitive);
4324 : }
4325 : }
4326 :
4327 : template<typename T>
4328 : void
4329 0 : CodeGenerator::emitCallInvokeFunction(T* apply, Register extraStackSize)
4330 : {
4331 0 : Register objreg = ToRegister(apply->getTempObject());
4332 0 : MOZ_ASSERT(objreg != extraStackSize);
4333 :
4334 : // Push the space used by the arguments.
4335 0 : masm.moveStackPtrTo(objreg);
4336 0 : masm.Push(extraStackSize);
4337 :
4338 0 : pushArg(objreg); // argv.
4339 0 : pushArg(ToRegister(apply->getArgc())); // argc.
4340 0 : pushArg(Imm32(false)); // ignoresReturnValue.
4341 0 : pushArg(Imm32(false)); // isConstrucing.
4342 0 : pushArg(ToRegister(apply->getFunction())); // JSFunction*.
4343 :
4344 : // This specialization og callVM restore the extraStackSize after the call.
4345 0 : callVM(InvokeFunctionInfo, apply, &extraStackSize);
4346 :
4347 0 : masm.Pop(extraStackSize);
4348 0 : }
4349 :
4350 : // Do not bailout after the execution of this function since the stack no longer
4351 : // correspond to what is expected by the snapshots.
4352 : void
4353 0 : CodeGenerator::emitAllocateSpaceForApply(Register argcreg, Register extraStackSpace, Label* end)
4354 : {
4355 : // Initialize the loop counter AND Compute the stack usage (if == 0)
4356 0 : masm.movePtr(argcreg, extraStackSpace);
4357 :
4358 : // Align the JitFrameLayout on the JitStackAlignment.
4359 : if (JitStackValueAlignment > 1) {
4360 0 : MOZ_ASSERT(frameSize() % JitStackAlignment == 0,
4361 : "Stack padding assumes that the frameSize is correct");
4362 : MOZ_ASSERT(JitStackValueAlignment == 2);
4363 0 : Label noPaddingNeeded;
4364 : // if the number of arguments is odd, then we do not need any padding.
4365 0 : masm.branchTestPtr(Assembler::NonZero, argcreg, Imm32(1), &noPaddingNeeded);
4366 0 : masm.addPtr(Imm32(1), extraStackSpace);
4367 0 : masm.bind(&noPaddingNeeded);
4368 : }
4369 :
4370 : // Reserve space for copying the arguments.
4371 0 : NativeObject::elementsSizeMustNotOverflow();
4372 0 : masm.lshiftPtr(Imm32(ValueShift), extraStackSpace);
4373 0 : masm.subFromStackPtr(extraStackSpace);
4374 :
4375 : #ifdef DEBUG
4376 : // Put a magic value in the space reserved for padding. Note, this code
4377 : // cannot be merged with the previous test, as not all architectures can
4378 : // write below their stack pointers.
4379 : if (JitStackValueAlignment > 1) {
4380 : MOZ_ASSERT(JitStackValueAlignment == 2);
4381 0 : Label noPaddingNeeded;
4382 : // if the number of arguments is odd, then we do not need any padding.
4383 0 : masm.branchTestPtr(Assembler::NonZero, argcreg, Imm32(1), &noPaddingNeeded);
4384 0 : BaseValueIndex dstPtr(masm.getStackPointer(), argcreg);
4385 0 : masm.storeValue(MagicValue(JS_ARG_POISON), dstPtr);
4386 0 : masm.bind(&noPaddingNeeded);
4387 : }
4388 : #endif
4389 :
4390 : // Skip the copy of arguments if there are none.
4391 0 : masm.branchTestPtr(Assembler::Zero, argcreg, argcreg, end);
4392 0 : }
4393 :
4394 : // Destroys argvIndex and copyreg.
4395 : void
4396 0 : CodeGenerator::emitCopyValuesForApply(Register argvSrcBase, Register argvIndex, Register copyreg,
4397 : size_t argvSrcOffset, size_t argvDstOffset)
4398 : {
4399 0 : Label loop;
4400 0 : masm.bind(&loop);
4401 :
4402 : // As argvIndex is off by 1, and we use the decBranchPtr instruction
4403 : // to loop back, we have to substract the size of the word which are
4404 : // copied.
4405 0 : BaseValueIndex srcPtr(argvSrcBase, argvIndex, argvSrcOffset - sizeof(void*));
4406 0 : BaseValueIndex dstPtr(masm.getStackPointer(), argvIndex, argvDstOffset - sizeof(void*));
4407 0 : masm.loadPtr(srcPtr, copyreg);
4408 0 : masm.storePtr(copyreg, dstPtr);
4409 :
4410 : // Handle 32 bits architectures.
4411 : if (sizeof(Value) == 2 * sizeof(void*)) {
4412 : BaseValueIndex srcPtrLow(argvSrcBase, argvIndex, argvSrcOffset - 2 * sizeof(void*));
4413 : BaseValueIndex dstPtrLow(masm.getStackPointer(), argvIndex, argvDstOffset - 2 * sizeof(void*));
4414 : masm.loadPtr(srcPtrLow, copyreg);
4415 : masm.storePtr(copyreg, dstPtrLow);
4416 : }
4417 :
4418 0 : masm.decBranchPtr(Assembler::NonZero, argvIndex, Imm32(1), &loop);
4419 0 : }
4420 :
4421 : void
4422 0 : CodeGenerator::emitPopArguments(Register extraStackSpace)
4423 : {
4424 : // Pop |this| and Arguments.
4425 0 : masm.freeStack(extraStackSpace);
4426 0 : }
4427 :
4428 : void
4429 0 : CodeGenerator::emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace)
4430 : {
4431 : // Holds the function nargs. Initially the number of args to the caller.
4432 0 : Register argcreg = ToRegister(apply->getArgc());
4433 0 : Register copyreg = ToRegister(apply->getTempObject());
4434 :
4435 0 : Label end;
4436 0 : emitAllocateSpaceForApply(argcreg, extraStackSpace, &end);
4437 :
4438 : // We are making a copy of the arguments which are above the JitFrameLayout
4439 : // of the current Ion frame.
4440 : //
4441 : // [arg1] [arg0] <- src [this] [JitFrameLayout] [.. frameSize ..] [pad] [arg1] [arg0] <- dst
4442 :
4443 : // Compute the source and destination offsets into the stack.
4444 0 : size_t argvSrcOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
4445 0 : size_t argvDstOffset = 0;
4446 :
4447 : // Save the extra stack space, and re-use the register as a base.
4448 0 : masm.push(extraStackSpace);
4449 0 : Register argvSrcBase = extraStackSpace;
4450 0 : argvSrcOffset += sizeof(void*);
4451 0 : argvDstOffset += sizeof(void*);
4452 :
4453 : // Save the actual number of register, and re-use the register as an index register.
4454 0 : masm.push(argcreg);
4455 0 : Register argvIndex = argcreg;
4456 0 : argvSrcOffset += sizeof(void*);
4457 0 : argvDstOffset += sizeof(void*);
4458 :
4459 : // srcPtr = (StackPointer + extraStackSpace) + argvSrcOffset
4460 : // dstPtr = (StackPointer ) + argvDstOffset
4461 0 : masm.addStackPtrTo(argvSrcBase);
4462 :
4463 : // Copy arguments.
4464 0 : emitCopyValuesForApply(argvSrcBase, argvIndex, copyreg, argvSrcOffset, argvDstOffset);
4465 :
4466 : // Restore argcreg and the extra stack space counter.
4467 0 : masm.pop(argcreg);
4468 0 : masm.pop(extraStackSpace);
4469 :
4470 : // Join with all arguments copied and the extra stack usage computed.
4471 0 : masm.bind(&end);
4472 :
4473 : // Push |this|.
4474 0 : masm.addPtr(Imm32(sizeof(Value)), extraStackSpace);
4475 0 : masm.pushValue(ToValue(apply, LApplyArgsGeneric::ThisIndex));
4476 0 : }
4477 :
4478 : void
4479 0 : CodeGenerator::emitPushArguments(LApplyArrayGeneric* apply, Register extraStackSpace)
4480 : {
4481 0 : Label noCopy, epilogue;
4482 0 : Register tmpArgc = ToRegister(apply->getTempObject());
4483 0 : Register elementsAndArgc = ToRegister(apply->getElements());
4484 :
4485 : // Invariants guarded in the caller:
4486 : // - the array is not too long
4487 : // - the array length equals its initialized length
4488 :
4489 : // The array length is our argc for the purposes of allocating space.
4490 0 : Address length(ToRegister(apply->getElements()), ObjectElements::offsetOfLength());
4491 0 : masm.load32(length, tmpArgc);
4492 :
4493 : // Allocate space for the values.
4494 0 : emitAllocateSpaceForApply(tmpArgc, extraStackSpace, &noCopy);
4495 :
4496 : // Copy the values. This code is skipped entirely if there are
4497 : // no values.
4498 0 : size_t argvDstOffset = 0;
4499 :
4500 0 : Register argvSrcBase = elementsAndArgc; // Elements value
4501 :
4502 0 : masm.push(extraStackSpace);
4503 0 : Register copyreg = extraStackSpace;
4504 0 : argvDstOffset += sizeof(void*);
4505 :
4506 0 : masm.push(tmpArgc);
4507 0 : Register argvIndex = tmpArgc;
4508 0 : argvDstOffset += sizeof(void*);
4509 :
4510 : // Copy
4511 0 : emitCopyValuesForApply(argvSrcBase, argvIndex, copyreg, 0, argvDstOffset);
4512 :
4513 : // Restore.
4514 0 : masm.pop(elementsAndArgc);
4515 0 : masm.pop(extraStackSpace);
4516 0 : masm.jump(&epilogue);
4517 :
4518 : // Clear argc if we skipped the copy step.
4519 0 : masm.bind(&noCopy);
4520 0 : masm.movePtr(ImmPtr(0), elementsAndArgc);
4521 :
4522 : // Join with all arguments copied and the extra stack usage computed.
4523 : // Note, "elements" has become "argc".
4524 0 : masm.bind(&epilogue);
4525 :
4526 : // Push |this|.
4527 0 : masm.addPtr(Imm32(sizeof(Value)), extraStackSpace);
4528 0 : masm.pushValue(ToValue(apply, LApplyArgsGeneric::ThisIndex));
4529 0 : }
4530 :
4531 : template<typename T>
4532 : void
4533 0 : CodeGenerator::emitApplyGeneric(T* apply)
4534 : {
4535 : // Holds the function object.
4536 0 : Register calleereg = ToRegister(apply->getFunction());
4537 :
4538 : // Temporary register for modifying the function object.
4539 0 : Register objreg = ToRegister(apply->getTempObject());
4540 0 : Register extraStackSpace = ToRegister(apply->getTempStackCounter());
4541 :
4542 : // Holds the function nargs, computed in the invoker or (for
4543 : // ApplyArray) in the argument pusher.
4544 0 : Register argcreg = ToRegister(apply->getArgc());
4545 :
4546 : // Unless already known, guard that calleereg is actually a function object.
4547 0 : if (!apply->hasSingleTarget()) {
4548 0 : masm.loadObjClass(calleereg, objreg);
4549 :
4550 0 : ImmPtr ptr = ImmPtr(&JSFunction::class_);
4551 0 : bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot());
4552 : }
4553 :
4554 : // Copy the arguments of the current function.
4555 : //
4556 : // In the case of ApplyArray, also compute argc: the argc register
4557 : // and the elements register are the same; argc must not be
4558 : // referenced before the call to emitPushArguments() and elements
4559 : // must not be referenced after it returns.
4560 : //
4561 : // objreg is dead across this call.
4562 : //
4563 : // extraStackSpace is garbage on entry and defined on exit.
4564 0 : emitPushArguments(apply, extraStackSpace);
4565 :
4566 0 : masm.checkStackAlignment();
4567 :
4568 : // If the function is native, only emit the call to InvokeFunction.
4569 0 : if (apply->hasSingleTarget() && apply->getSingleTarget()->isNative()) {
4570 0 : emitCallInvokeFunction(apply, extraStackSpace);
4571 0 : emitPopArguments(extraStackSpace);
4572 0 : return;
4573 : }
4574 :
4575 0 : Label end, invoke;
4576 :
4577 : // Guard that calleereg is an interpreted function with a JSScript.
4578 0 : masm.branchIfFunctionHasNoScript(calleereg, &invoke);
4579 :
4580 : // Guard that calleereg is not a class constrcuctor
4581 0 : masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor,
4582 : calleereg, objreg, &invoke);
4583 :
4584 : // Knowing that calleereg is a non-native function, load the JSScript.
4585 0 : masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
4586 :
4587 : // Load script jitcode.
4588 0 : masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
4589 :
4590 : // Call with an Ion frame or a rectifier frame.
4591 : {
4592 : // Create the frame descriptor.
4593 0 : unsigned pushed = masm.framePushed();
4594 0 : Register stackSpace = extraStackSpace;
4595 0 : masm.addPtr(Imm32(pushed), stackSpace);
4596 0 : masm.makeFrameDescriptor(stackSpace, JitFrame_IonJS, JitFrameLayout::Size());
4597 :
4598 0 : masm.Push(argcreg);
4599 0 : masm.Push(calleereg);
4600 0 : masm.Push(stackSpace); // descriptor
4601 :
4602 0 : Label underflow, rejoin;
4603 :
4604 : // Check whether the provided arguments satisfy target argc.
4605 0 : if (!apply->hasSingleTarget()) {
4606 0 : Register nformals = extraStackSpace;
4607 0 : masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nformals);
4608 0 : masm.branch32(Assembler::Below, argcreg, nformals, &underflow);
4609 : } else {
4610 0 : masm.branch32(Assembler::Below, argcreg, Imm32(apply->getSingleTarget()->nargs()),
4611 : &underflow);
4612 : }
4613 :
4614 : // Skip the construction of the rectifier frame because we have no
4615 : // underflow.
4616 0 : masm.jump(&rejoin);
4617 :
4618 : // Argument fixup needed. Get ready to call the argumentsRectifier.
4619 : {
4620 0 : masm.bind(&underflow);
4621 :
4622 : // Hardcode the address of the argumentsRectifier code.
4623 0 : JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
4624 :
4625 0 : MOZ_ASSERT(ArgumentsRectifierReg != objreg);
4626 0 : masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
4627 0 : masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
4628 0 : masm.movePtr(argcreg, ArgumentsRectifierReg);
4629 : }
4630 :
4631 0 : masm.bind(&rejoin);
4632 :
4633 : // Finally call the function in objreg, as assigned by one of the paths above.
4634 0 : uint32_t callOffset = masm.callJit(objreg);
4635 0 : markSafepointAt(callOffset, apply);
4636 :
4637 : // Recover the number of arguments from the frame descriptor.
4638 0 : masm.loadPtr(Address(masm.getStackPointer(), 0), stackSpace);
4639 0 : masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), stackSpace);
4640 0 : masm.subPtr(Imm32(pushed), stackSpace);
4641 :
4642 : // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
4643 : // The return address has already been removed from the Ion frame.
4644 0 : int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
4645 0 : masm.adjustStack(prefixGarbage);
4646 0 : masm.jump(&end);
4647 : }
4648 :
4649 : // Handle uncompiled or native functions.
4650 : {
4651 0 : masm.bind(&invoke);
4652 0 : emitCallInvokeFunction(apply, extraStackSpace);
4653 : }
4654 :
4655 : // Pop arguments and continue.
4656 0 : masm.bind(&end);
4657 0 : emitPopArguments(extraStackSpace);
4658 : }
4659 :
4660 : void
4661 0 : CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric* apply)
4662 : {
4663 : // Limit the number of parameters we can handle to a number that does not risk
4664 : // us allocating too much stack, notably on Windows where there is a 4K guard page
4665 : // that has to be touched to extend the stack. See bug 1351278. The value "3000"
4666 : // is the size of the guard page minus an arbitrary, but large, safety margin.
4667 :
4668 0 : LSnapshot* snapshot = apply->snapshot();
4669 0 : Register argcreg = ToRegister(apply->getArgc());
4670 :
4671 0 : uint32_t limit = 3000 / sizeof(Value);
4672 0 : bailoutCmp32(Assembler::Above, argcreg, Imm32(limit), snapshot);
4673 :
4674 0 : emitApplyGeneric(apply);
4675 0 : }
4676 :
4677 : void
4678 0 : CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply)
4679 : {
4680 0 : LSnapshot* snapshot = apply->snapshot();
4681 0 : Register tmp = ToRegister(apply->getTempObject());
4682 :
4683 0 : Address length(ToRegister(apply->getElements()), ObjectElements::offsetOfLength());
4684 0 : masm.load32(length, tmp);
4685 :
4686 : // See comment in visitApplyArgsGeneric, above.
4687 :
4688 0 : uint32_t limit = 3000 / sizeof(Value);
4689 0 : bailoutCmp32(Assembler::Above, tmp, Imm32(limit), snapshot);
4690 :
4691 : // Ensure that the array does not contain an uninitialized tail.
4692 :
4693 : Address initializedLength(ToRegister(apply->getElements()),
4694 0 : ObjectElements::offsetOfInitializedLength());
4695 0 : masm.sub32(initializedLength, tmp);
4696 0 : bailoutCmp32(Assembler::NotEqual, tmp, Imm32(0), snapshot);
4697 :
4698 0 : emitApplyGeneric(apply);
4699 0 : }
4700 :
4701 : void
4702 18 : CodeGenerator::visitBail(LBail* lir)
4703 : {
4704 18 : bailout(lir->snapshot());
4705 18 : }
4706 :
4707 : void
4708 18 : CodeGenerator::visitUnreachable(LUnreachable* lir)
4709 : {
4710 18 : masm.assumeUnreachable("end-of-block assumed unreachable");
4711 18 : }
4712 :
4713 : void
4714 0 : CodeGenerator::visitEncodeSnapshot(LEncodeSnapshot* lir)
4715 : {
4716 0 : encode(lir->snapshot());
4717 0 : }
4718 :
4719 : void
4720 0 : CodeGenerator::visitGetDynamicName(LGetDynamicName* lir)
4721 : {
4722 0 : Register envChain = ToRegister(lir->getEnvironmentChain());
4723 0 : Register name = ToRegister(lir->getName());
4724 0 : Register temp1 = ToRegister(lir->temp1());
4725 0 : Register temp2 = ToRegister(lir->temp2());
4726 0 : Register temp3 = ToRegister(lir->temp3());
4727 :
4728 0 : masm.loadJSContext(temp3);
4729 :
4730 : /* Make space for the outparam. */
4731 0 : masm.adjustStack(-int32_t(sizeof(Value)));
4732 0 : masm.moveStackPtrTo(temp2);
4733 :
4734 0 : masm.setupUnalignedABICall(temp1);
4735 0 : masm.passABIArg(temp3);
4736 0 : masm.passABIArg(envChain);
4737 0 : masm.passABIArg(name);
4738 0 : masm.passABIArg(temp2);
4739 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GetDynamicName));
4740 :
4741 0 : const ValueOperand out = ToOutValue(lir);
4742 :
4743 0 : masm.loadValue(Address(masm.getStackPointer(), 0), out);
4744 0 : masm.adjustStack(sizeof(Value));
4745 :
4746 0 : Label undefined;
4747 0 : masm.branchTestUndefined(Assembler::Equal, out, &undefined);
4748 0 : bailoutFrom(&undefined, lir->snapshot());
4749 0 : }
4750 :
4751 : typedef bool (*DirectEvalSFn)(JSContext*, HandleObject, HandleScript, HandleValue,
4752 : HandleString, jsbytecode*, MutableHandleValue);
4753 3 : static const VMFunction DirectEvalStringInfo =
4754 6 : FunctionInfo<DirectEvalSFn>(DirectEvalStringFromIon, "DirectEvalStringFromIon");
4755 :
4756 : void
4757 0 : CodeGenerator::visitCallDirectEval(LCallDirectEval* lir)
4758 : {
4759 0 : Register envChain = ToRegister(lir->getEnvironmentChain());
4760 0 : Register string = ToRegister(lir->getString());
4761 :
4762 0 : pushArg(ImmPtr(lir->mir()->pc()));
4763 0 : pushArg(string);
4764 0 : pushArg(ToValue(lir, LCallDirectEval::NewTarget));
4765 0 : pushArg(ImmGCPtr(current->mir()->info().script()));
4766 0 : pushArg(envChain);
4767 :
4768 0 : callVM(DirectEvalStringInfo, lir);
4769 0 : }
4770 :
4771 : void
4772 16 : CodeGenerator::generateArgumentsChecks(bool bailout)
4773 : {
4774 : // Registers safe for use before generatePrologue().
4775 : static const uint32_t EntryTempMask = Registers::TempMask & ~(1 << OsrFrameReg.code());
4776 :
4777 : // This function can be used the normal way to check the argument types,
4778 : // before entering the function and bailout when arguments don't match.
4779 : // For debug purpose, this is can also be used to force/check that the
4780 : // arguments are correct. Upon fail it will hit a breakpoint.
4781 :
4782 16 : MIRGraph& mir = gen->graph();
4783 16 : MResumePoint* rp = mir.entryResumePoint();
4784 :
4785 : // No registers are allocated yet, so it's safe to grab anything.
4786 16 : Register temp = AllocatableGeneralRegisterSet(EntryTempMask).getAny();
4787 :
4788 16 : const CompileInfo& info = gen->info();
4789 :
4790 32 : Label miss;
4791 64 : for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
4792 : // All initial parameters are guaranteed to be MParameters.
4793 48 : MParameter* param = rp->getOperand(i)->toParameter();
4794 48 : const TypeSet* types = param->resultTypeSet();
4795 48 : if (!types || types->unknown())
4796 0 : continue;
4797 :
4798 : // Calculate the offset on the stack of the argument.
4799 : // (i - info.startArgSlot()) - Compute index of arg within arg vector.
4800 : // ... * sizeof(Value) - Scale by value size.
4801 : // ArgToStackOffset(...) - Compute displacement within arg vector.
4802 48 : int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
4803 48 : masm.guardTypeSet(Address(masm.getStackPointer(), offset), types, BarrierKind::TypeSet, temp, &miss);
4804 : }
4805 :
4806 16 : if (miss.used()) {
4807 16 : if (bailout) {
4808 8 : bailoutFrom(&miss, graph.entrySnapshot());
4809 : } else {
4810 16 : Label success;
4811 8 : masm.jump(&success);
4812 8 : masm.bind(&miss);
4813 :
4814 : // Check for cases where the type set guard might have missed due to
4815 : // changing object groups.
4816 32 : for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
4817 24 : MParameter* param = rp->getOperand(i)->toParameter();
4818 24 : const TemporaryTypeSet* types = param->resultTypeSet();
4819 24 : if (!types || types->unknown())
4820 0 : continue;
4821 :
4822 48 : Label skip;
4823 24 : Address addr(masm.getStackPointer(), ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value)));
4824 24 : masm.branchTestObject(Assembler::NotEqual, addr, &skip);
4825 24 : Register obj = masm.extractObject(addr, temp);
4826 24 : masm.guardTypeSetMightBeIncomplete(types, obj, temp, &success);
4827 24 : masm.bind(&skip);
4828 : }
4829 :
4830 8 : masm.assumeUnreachable("Argument check fail.");
4831 8 : masm.bind(&success);
4832 : }
4833 : }
4834 16 : }
4835 :
4836 : // Out-of-line path to report over-recursed error and fail.
4837 : class CheckOverRecursedFailure : public OutOfLineCodeBase<CodeGenerator>
4838 : {
4839 : LInstruction* lir_;
4840 :
4841 : public:
4842 7 : explicit CheckOverRecursedFailure(LInstruction* lir)
4843 7 : : lir_(lir)
4844 7 : { }
4845 :
4846 7 : void accept(CodeGenerator* codegen) {
4847 7 : codegen->visitCheckOverRecursedFailure(this);
4848 7 : }
4849 :
4850 21 : LInstruction* lir() const {
4851 21 : return lir_;
4852 : }
4853 : };
4854 :
4855 : void
4856 8 : CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed* lir)
4857 : {
4858 : // If we don't push anything on the stack, skip the check.
4859 8 : if (omitOverRecursedCheck())
4860 1 : return;
4861 :
4862 : // Ensure that this frame will not cross the stack limit.
4863 : // This is a weak check, justified by Ion using the C stack: we must always
4864 : // be some distance away from the actual limit, since if the limit is
4865 : // crossed, an error must be thrown, which requires more frames.
4866 : //
4867 : // It must always be possible to trespass past the stack limit.
4868 : // Ion may legally place frames very close to the limit. Calling additional
4869 : // C functions may then violate the limit without any checking.
4870 : //
4871 : // Since Ion frames exist on the C stack, the stack limit may be
4872 : // dynamically set by JS_SetThreadStackLimit() and JS_SetNativeStackQuota().
4873 :
4874 7 : CheckOverRecursedFailure* ool = new(alloc()) CheckOverRecursedFailure(lir);
4875 7 : addOutOfLineCode(ool, lir->mir());
4876 :
4877 7 : Register temp = ToRegister(lir->temp());
4878 :
4879 : // Conditional forward (unlikely) branch to failure.
4880 7 : const void* contextAddr = GetJitContext()->compartment->zone()->addressOfJSContext();
4881 7 : masm.loadPtr(AbsoluteAddress(contextAddr), temp);
4882 14 : masm.branchStackPtrRhs(Assembler::AboveOrEqual,
4883 7 : Address(temp, offsetof(JSContext, jitStackLimit)), ool->entry());
4884 7 : masm.bind(ool->rejoin());
4885 : }
4886 :
4887 : typedef bool (*DefVarFn)(JSContext*, HandlePropertyName, unsigned, HandleObject);
4888 3 : static const VMFunction DefVarInfo = FunctionInfo<DefVarFn>(DefVar, "DefVar");
4889 :
4890 : void
4891 0 : CodeGenerator::visitDefVar(LDefVar* lir)
4892 : {
4893 0 : Register envChain = ToRegister(lir->environmentChain());
4894 :
4895 0 : pushArg(envChain); // JSObject*
4896 0 : pushArg(Imm32(lir->mir()->attrs())); // unsigned
4897 0 : pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName*
4898 :
4899 0 : callVM(DefVarInfo, lir);
4900 0 : }
4901 :
4902 : typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned);
4903 3 : static const VMFunction DefLexicalInfo =
4904 6 : FunctionInfo<DefLexicalFn>(DefGlobalLexical, "DefGlobalLexical");
4905 :
4906 : void
4907 0 : CodeGenerator::visitDefLexical(LDefLexical* lir)
4908 : {
4909 0 : pushArg(Imm32(lir->mir()->attrs())); // unsigned
4910 0 : pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName*
4911 :
4912 0 : callVM(DefLexicalInfo, lir);
4913 0 : }
4914 :
4915 : typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject, HandleFunction);
4916 3 : static const VMFunction DefFunOperationInfo =
4917 6 : FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
4918 :
4919 : void
4920 0 : CodeGenerator::visitDefFun(LDefFun* lir)
4921 : {
4922 0 : Register envChain = ToRegister(lir->environmentChain());
4923 :
4924 0 : Register fun = ToRegister(lir->fun());
4925 0 : pushArg(fun);
4926 0 : pushArg(envChain);
4927 0 : pushArg(ImmGCPtr(current->mir()->info().script()));
4928 :
4929 0 : callVM(DefFunOperationInfo, lir);
4930 0 : }
4931 :
4932 : typedef bool (*CheckOverRecursedFn)(JSContext*);
4933 3 : static const VMFunction CheckOverRecursedInfo =
4934 6 : FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed, "CheckOverRecursed");
4935 :
4936 : void
4937 7 : CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool)
4938 : {
4939 : // The OOL path is hit if the recursion depth has been exceeded.
4940 : // Throw an InternalError for over-recursion.
4941 :
4942 : // LFunctionEnvironment can appear before LCheckOverRecursed, so we have
4943 : // to save all live registers to avoid crashes if CheckOverRecursed triggers
4944 : // a GC.
4945 7 : saveLive(ool->lir());
4946 :
4947 7 : callVM(CheckOverRecursedInfo, ool->lir());
4948 :
4949 7 : restoreLive(ool->lir());
4950 7 : masm.jump(ool->rejoin());
4951 7 : }
4952 :
4953 : IonScriptCounts*
4954 8 : CodeGenerator::maybeCreateScriptCounts()
4955 : {
4956 : // If scripts are being profiled, create a new IonScriptCounts for the
4957 : // profiling data, which will be attached to the associated JSScript or
4958 : // wasm module after code generation finishes.
4959 8 : if (!GetJitContext()->hasProfilingScripts())
4960 8 : return nullptr;
4961 :
4962 : // This test inhibits IonScriptCount creation for wasm code which is
4963 : // currently incompatible with wasm codegen for two reasons: (1) wasm code
4964 : // must be serializable and script count codegen bakes in absolute
4965 : // addresses, (2) wasm code does not have a JSScript with which to associate
4966 : // code coverage data.
4967 0 : JSScript* script = gen->info().script();
4968 0 : if (!script)
4969 0 : return nullptr;
4970 :
4971 0 : UniquePtr<IonScriptCounts> counts(js_new<IonScriptCounts>());
4972 0 : if (!counts || !counts->init(graph.numBlocks()))
4973 0 : return nullptr;
4974 :
4975 0 : for (size_t i = 0; i < graph.numBlocks(); i++) {
4976 0 : MBasicBlock* block = graph.getBlock(i)->mir();
4977 :
4978 0 : uint32_t offset = 0;
4979 0 : char* description = nullptr;
4980 0 : if (MResumePoint* resume = block->entryResumePoint()) {
4981 : // Find a PC offset in the outermost script to use. If this
4982 : // block is from an inlined script, find a location in the
4983 : // outer script to associate information about the inlining
4984 : // with.
4985 0 : while (resume->caller())
4986 0 : resume = resume->caller();
4987 0 : offset = script->pcToOffset(resume->pc());
4988 :
4989 0 : if (block->entryResumePoint()->caller()) {
4990 : // Get the filename and line number of the inner script.
4991 0 : JSScript* innerScript = block->info().script();
4992 0 : description = (char*) js_calloc(200);
4993 0 : if (description) {
4994 0 : snprintf(description, 200, "%s:%" PRIuSIZE,
4995 0 : innerScript->filename(), innerScript->lineno());
4996 : }
4997 : }
4998 : }
4999 :
5000 0 : if (!counts->block(i).init(block->id(), offset, description, block->numSuccessors()))
5001 0 : return nullptr;
5002 :
5003 0 : for (size_t j = 0; j < block->numSuccessors(); j++)
5004 0 : counts->block(i).setSuccessor(j, skipTrivialBlocks(block->getSuccessor(j))->id());
5005 : }
5006 :
5007 0 : scriptCounts_ = counts.release();
5008 0 : return scriptCounts_;
5009 : }
5010 :
5011 : // Structure for managing the state tracked for a block by script counters.
5012 : struct ScriptCountBlockState
5013 : {
5014 : IonBlockCounts& block;
5015 : MacroAssembler& masm;
5016 :
5017 : Sprinter printer;
5018 :
5019 : public:
5020 0 : ScriptCountBlockState(IonBlockCounts* block, MacroAssembler* masm)
5021 0 : : block(*block), masm(*masm), printer(GetJitContext()->cx, false)
5022 : {
5023 0 : }
5024 :
5025 0 : bool init()
5026 : {
5027 0 : if (!printer.init())
5028 0 : return false;
5029 :
5030 : // Bump the hit count for the block at the start. This code is not
5031 : // included in either the text for the block or the instruction byte
5032 : // counts.
5033 0 : masm.inc64(AbsoluteAddress(block.addressOfHitCount()));
5034 :
5035 : // Collect human readable assembly for the code generated in the block.
5036 0 : masm.setPrinter(&printer);
5037 :
5038 0 : return true;
5039 : }
5040 :
5041 0 : void visitInstruction(LInstruction* ins)
5042 : {
5043 : // Prefix stream of assembly instructions with their LIR instruction
5044 : // name and any associated high level info.
5045 0 : if (const char* extra = ins->extraName())
5046 0 : printer.printf("[%s:%s]\n", ins->opName(), extra);
5047 : else
5048 0 : printer.printf("[%s]\n", ins->opName());
5049 0 : }
5050 :
5051 0 : ~ScriptCountBlockState()
5052 0 : {
5053 0 : masm.setPrinter(nullptr);
5054 :
5055 0 : if (!printer.hadOutOfMemory())
5056 0 : block.setCode(printer.string());
5057 0 : }
5058 : };
5059 :
5060 : void
5061 368 : CodeGenerator::branchIfInvalidated(Register temp, Label* invalidated)
5062 : {
5063 368 : CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), temp);
5064 368 : masm.propagateOOM(ionScriptLabels_.append(label));
5065 :
5066 : // If IonScript::invalidationCount_ != 0, the script has been invalidated.
5067 1104 : masm.branch32(Assembler::NotEqual,
5068 736 : Address(temp, IonScript::offsetOfInvalidationCount()),
5069 : Imm32(0),
5070 368 : invalidated);
5071 368 : }
5072 :
5073 : void
5074 150 : CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset)
5075 : {
5076 150 : MOZ_ASSERT(type == MIRType::Object || type == MIRType::ObjectOrNull ||
5077 : type == MIRType::String || type == MIRType::Symbol);
5078 :
5079 150 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
5080 150 : regs.take(input);
5081 :
5082 150 : Register temp = regs.takeAny();
5083 150 : masm.push(temp);
5084 :
5085 : // Don't check if the script has been invalidated. In that case invalid
5086 : // types are expected (until we reach the OsiPoint and bailout).
5087 300 : Label done;
5088 150 : branchIfInvalidated(temp, &done);
5089 :
5090 204 : if ((type == MIRType::Object || type == MIRType::ObjectOrNull) &&
5091 202 : typeset && !typeset->unknownObject())
5092 : {
5093 : // We have a result TypeSet, assert this object is in it.
5094 96 : Label miss, ok;
5095 48 : if (type == MIRType::ObjectOrNull)
5096 0 : masm.branchPtr(Assembler::Equal, input, ImmWord(0), &ok);
5097 48 : if (typeset->getObjectCount() > 0)
5098 43 : masm.guardObjectType(input, typeset, temp, &miss);
5099 : else
5100 5 : masm.jump(&miss);
5101 48 : masm.jump(&ok);
5102 :
5103 48 : masm.bind(&miss);
5104 48 : masm.guardTypeSetMightBeIncomplete(typeset, input, temp, &ok);
5105 :
5106 48 : masm.assumeUnreachable("MIR instruction returned object with unexpected type");
5107 :
5108 48 : masm.bind(&ok);
5109 : }
5110 :
5111 : // Check that we have a valid GC pointer.
5112 150 : saveVolatile();
5113 150 : masm.setupUnalignedABICall(temp);
5114 150 : masm.loadJSContext(temp);
5115 150 : masm.passABIArg(temp);
5116 150 : masm.passABIArg(input);
5117 :
5118 : void* callee;
5119 150 : switch (type) {
5120 : case MIRType::Object:
5121 96 : callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectPtr);
5122 96 : break;
5123 : case MIRType::ObjectOrNull:
5124 0 : callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectOrNullPtr);
5125 0 : break;
5126 : case MIRType::String:
5127 54 : callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidStringPtr);
5128 54 : break;
5129 : case MIRType::Symbol:
5130 0 : callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidSymbolPtr);
5131 0 : break;
5132 : default:
5133 0 : MOZ_CRASH();
5134 : }
5135 :
5136 150 : masm.callWithABI(callee);
5137 150 : restoreVolatile();
5138 :
5139 150 : masm.bind(&done);
5140 150 : masm.pop(temp);
5141 150 : }
5142 :
5143 : void
5144 218 : CodeGenerator::emitAssertResultV(const ValueOperand input, const TemporaryTypeSet* typeset)
5145 : {
5146 218 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
5147 218 : regs.take(input);
5148 :
5149 218 : Register temp1 = regs.takeAny();
5150 218 : Register temp2 = regs.takeAny();
5151 218 : masm.push(temp1);
5152 218 : masm.push(temp2);
5153 :
5154 : // Don't check if the script has been invalidated. In that case invalid
5155 : // types are expected (until we reach the OsiPoint and bailout).
5156 436 : Label done;
5157 218 : branchIfInvalidated(temp1, &done);
5158 :
5159 218 : if (typeset && !typeset->unknown()) {
5160 : // We have a result TypeSet, assert this value is in it.
5161 166 : Label miss, ok;
5162 83 : masm.guardTypeSet(input, typeset, BarrierKind::TypeSet, temp1, &miss);
5163 83 : masm.jump(&ok);
5164 :
5165 83 : masm.bind(&miss);
5166 :
5167 : // Check for cases where the type set guard might have missed due to
5168 : // changing object groups.
5169 166 : Label realMiss;
5170 83 : masm.branchTestObject(Assembler::NotEqual, input, &realMiss);
5171 83 : Register payload = masm.extractObject(input, temp1);
5172 83 : masm.guardTypeSetMightBeIncomplete(typeset, payload, temp1, &ok);
5173 83 : masm.bind(&realMiss);
5174 :
5175 83 : masm.assumeUnreachable("MIR instruction returned value with unexpected type");
5176 :
5177 83 : masm.bind(&ok);
5178 : }
5179 :
5180 : // Check that we have a valid GC pointer.
5181 218 : saveVolatile();
5182 :
5183 218 : masm.pushValue(input);
5184 218 : masm.moveStackPtrTo(temp1);
5185 :
5186 218 : masm.setupUnalignedABICall(temp2);
5187 218 : masm.loadJSContext(temp2);
5188 218 : masm.passABIArg(temp2);
5189 218 : masm.passABIArg(temp1);
5190 218 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, AssertValidValue));
5191 218 : masm.popValue(input);
5192 218 : restoreVolatile();
5193 :
5194 218 : masm.bind(&done);
5195 218 : masm.pop(temp2);
5196 218 : masm.pop(temp1);
5197 218 : }
5198 :
5199 : #ifdef DEBUG
5200 : void
5201 179 : CodeGenerator::emitObjectOrStringResultChecks(LInstruction* lir, MDefinition* mir)
5202 : {
5203 179 : if (lir->numDefs() == 0)
5204 29 : return;
5205 :
5206 150 : MOZ_ASSERT(lir->numDefs() == 1);
5207 150 : Register output = ToRegister(lir->getDef(0));
5208 :
5209 150 : emitAssertObjectOrStringResult(output, mir->type(), mir->resultTypeSet());
5210 : }
5211 :
5212 : void
5213 301 : CodeGenerator::emitValueResultChecks(LInstruction* lir, MDefinition* mir)
5214 : {
5215 301 : if (lir->numDefs() == 0)
5216 130 : return;
5217 :
5218 254 : MOZ_ASSERT(lir->numDefs() == BOX_PIECES);
5219 254 : if (!lir->getDef(0)->output()->isRegister())
5220 36 : return;
5221 :
5222 218 : ValueOperand output = ToOutValue(lir);
5223 :
5224 218 : emitAssertResultV(output, mir->resultTypeSet());
5225 : }
5226 :
5227 : void
5228 1681 : CodeGenerator::emitDebugResultChecks(LInstruction* ins)
5229 : {
5230 : // In debug builds, check that LIR instructions return valid values.
5231 :
5232 1681 : MDefinition* mir = ins->mirRaw();
5233 1681 : if (!mir)
5234 866 : return;
5235 :
5236 815 : switch (mir->type()) {
5237 : case MIRType::Object:
5238 : case MIRType::ObjectOrNull:
5239 : case MIRType::String:
5240 : case MIRType::Symbol:
5241 179 : emitObjectOrStringResultChecks(ins, mir);
5242 179 : break;
5243 : case MIRType::Value:
5244 301 : emitValueResultChecks(ins, mir);
5245 301 : break;
5246 : default:
5247 335 : break;
5248 : }
5249 : }
5250 :
5251 : void
5252 1681 : CodeGenerator::emitDebugForceBailing(LInstruction* lir)
5253 : {
5254 1681 : if (!lir->snapshot())
5255 2855 : return;
5256 326 : if (lir->isStart())
5257 11 : return;
5258 315 : if (lir->isOsiPoint())
5259 134 : return;
5260 :
5261 181 : masm.comment("emitDebugForceBailing");
5262 181 : const void* bailAfterAddr = GetJitContext()->compartment->zone()->addressOfIonBailAfter();
5263 :
5264 181 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
5265 :
5266 362 : Label done, notBail, bail;
5267 181 : masm.branch32(Assembler::Equal, AbsoluteAddress(bailAfterAddr), Imm32(0), &done);
5268 : {
5269 181 : Register temp = regs.takeAny();
5270 :
5271 181 : masm.push(temp);
5272 181 : masm.load32(AbsoluteAddress(bailAfterAddr), temp);
5273 181 : masm.sub32(Imm32(1), temp);
5274 181 : masm.store32(temp, AbsoluteAddress(bailAfterAddr));
5275 :
5276 181 : masm.branch32(Assembler::NotEqual, temp, Imm32(0), ¬Bail);
5277 : {
5278 181 : masm.pop(temp);
5279 181 : masm.jump(&bail);
5280 181 : bailoutFrom(&bail, lir->snapshot());
5281 : }
5282 181 : masm.bind(¬Bail);
5283 181 : masm.pop(temp);
5284 : }
5285 181 : masm.bind(&done);
5286 : }
5287 : #endif
5288 :
5289 : static void
5290 0 : DumpTrackedSite(const BytecodeSite* site)
5291 : {
5292 0 : if (!JitSpewEnabled(JitSpew_OptimizationTracking))
5293 0 : return;
5294 :
5295 : #ifdef JS_JITSPEW
5296 0 : unsigned column = 0;
5297 0 : unsigned lineNumber = PCToLineNumber(site->script(), site->pc(), &column);
5298 0 : JitSpew(JitSpew_OptimizationTracking, "Types for %s at %s:%u:%u",
5299 0 : CodeName[JSOp(*site->pc())],
5300 : site->script()->filename(),
5301 : lineNumber,
5302 0 : column);
5303 : #endif
5304 : }
5305 :
5306 : static void
5307 0 : DumpTrackedOptimizations(TrackedOptimizations* optimizations)
5308 : {
5309 0 : if (!JitSpewEnabled(JitSpew_OptimizationTracking))
5310 0 : return;
5311 :
5312 0 : optimizations->spew(JitSpew_OptimizationTracking);
5313 : }
5314 :
5315 : bool
5316 8 : CodeGenerator::generateBody()
5317 : {
5318 8 : IonScriptCounts* counts = maybeCreateScriptCounts();
5319 :
5320 : #if defined(JS_ION_PERF)
5321 : PerfSpewer* perfSpewer = &perfSpewer_;
5322 : if (gen->compilingWasm())
5323 : perfSpewer = &gen->perfSpewer();
5324 : #endif
5325 :
5326 411 : for (size_t i = 0; i < graph.numBlocks(); i++) {
5327 403 : current = graph.getBlock(i);
5328 :
5329 : // Don't emit any code for trivial blocks, containing just a goto. Such
5330 : // blocks are created to split critical edges, and if we didn't end up
5331 : // putting any instructions in them, we can skip them.
5332 403 : if (current->isTrivial())
5333 107 : continue;
5334 :
5335 : #ifdef JS_JITSPEW
5336 296 : const char* filename = nullptr;
5337 296 : size_t lineNumber = 0;
5338 296 : unsigned columnNumber = 0;
5339 296 : if (current->mir()->info().script()) {
5340 296 : filename = current->mir()->info().script()->filename();
5341 296 : if (current->mir()->pc())
5342 296 : lineNumber = PCToLineNumber(current->mir()->info().script(), current->mir()->pc(),
5343 : &columnNumber);
5344 : } else {
5345 : #ifdef DEBUG
5346 0 : lineNumber = current->mir()->lineno();
5347 0 : columnNumber = current->mir()->columnIndex();
5348 : #endif
5349 : }
5350 592 : JitSpew(JitSpew_Codegen, "# block%" PRIuSIZE " %s:%" PRIuSIZE ":%u%s:",
5351 : i, filename ? filename : "?", lineNumber, columnNumber,
5352 888 : current->mir()->isLoopHeader() ? " (loop header)" : "");
5353 : #endif
5354 :
5355 296 : masm.bind(current->label());
5356 :
5357 592 : mozilla::Maybe<ScriptCountBlockState> blockCounts;
5358 296 : if (counts) {
5359 0 : blockCounts.emplace(&counts->block(i), &masm);
5360 0 : if (!blockCounts->init())
5361 0 : return false;
5362 : }
5363 296 : TrackedOptimizations* last = nullptr;
5364 :
5365 : #if defined(JS_ION_PERF)
5366 : perfSpewer->startBasicBlock(current->mir(), masm);
5367 : #endif
5368 :
5369 1977 : for (LInstructionIterator iter = current->begin(); iter != current->end(); iter++) {
5370 1681 : if (!alloc().ensureBallast())
5371 0 : return false;
5372 :
5373 : #ifdef JS_JITSPEW
5374 1681 : JitSpewStart(JitSpew_Codegen, "instruction %s", iter->opName());
5375 1681 : if (const char* extra = iter->extraName())
5376 225 : JitSpewCont(JitSpew_Codegen, ":%s", extra);
5377 1681 : JitSpewFin(JitSpew_Codegen);
5378 : #endif
5379 :
5380 1681 : if (counts)
5381 0 : blockCounts->visitInstruction(*iter);
5382 :
5383 : #ifdef CHECK_OSIPOINT_REGISTERS
5384 1681 : if (iter->safepoint())
5385 134 : resetOsiPointRegs(iter->safepoint());
5386 : #endif
5387 :
5388 1681 : if (iter->mirRaw()) {
5389 : // Only add instructions that have a tracked inline script tree.
5390 815 : if (iter->mirRaw()->trackedTree()) {
5391 815 : if (!addNativeToBytecodeEntry(iter->mirRaw()->trackedSite()))
5392 0 : return false;
5393 : }
5394 :
5395 : // Track the start native offset of optimizations.
5396 815 : if (iter->mirRaw()->trackedOptimizations()) {
5397 0 : if (last != iter->mirRaw()->trackedOptimizations()) {
5398 0 : DumpTrackedSite(iter->mirRaw()->trackedSite());
5399 0 : DumpTrackedOptimizations(iter->mirRaw()->trackedOptimizations());
5400 0 : last = iter->mirRaw()->trackedOptimizations();
5401 : }
5402 0 : if (!addTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations()))
5403 0 : return false;
5404 : }
5405 : }
5406 :
5407 : #ifdef DEBUG
5408 1681 : setElement(*iter); // needed to encode correct snapshot location.
5409 1681 : emitDebugForceBailing(*iter);
5410 : #endif
5411 :
5412 1681 : iter->accept(this);
5413 :
5414 : // Track the end native offset of optimizations.
5415 1681 : if (iter->mirRaw() && iter->mirRaw()->trackedOptimizations())
5416 0 : extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations());
5417 :
5418 : #ifdef DEBUG
5419 1681 : if (!counts) {
5420 1681 : if (JitOptions.fullDebugChecks)
5421 1681 : emitDebugResultChecks(*iter);
5422 : }
5423 : #endif
5424 : }
5425 296 : if (masm.oom())
5426 0 : return false;
5427 :
5428 : #if defined(JS_ION_PERF)
5429 : perfSpewer->endBasicBlock(masm);
5430 : #endif
5431 : }
5432 :
5433 8 : return true;
5434 : }
5435 :
5436 : // Out-of-line object allocation for LNewArray.
5437 : class OutOfLineNewArray : public OutOfLineCodeBase<CodeGenerator>
5438 : {
5439 : LNewArray* lir_;
5440 :
5441 : public:
5442 3 : explicit OutOfLineNewArray(LNewArray* lir)
5443 3 : : lir_(lir)
5444 3 : { }
5445 :
5446 3 : void accept(CodeGenerator* codegen) {
5447 3 : codegen->visitOutOfLineNewArray(this);
5448 3 : }
5449 :
5450 3 : LNewArray* lir() const {
5451 3 : return lir_;
5452 : }
5453 : };
5454 :
5455 : typedef JSObject* (*NewArrayOperationFn)(JSContext*, HandleScript, jsbytecode*, uint32_t,
5456 : NewObjectKind);
5457 3 : static const VMFunction NewArrayOperationInfo =
5458 6 : FunctionInfo<NewArrayOperationFn>(NewArrayOperation, "NewArrayOperation");
5459 :
5460 : static JSObject*
5461 0 : NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group,
5462 : bool convertDoubleElements)
5463 : {
5464 0 : JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
5465 0 : if (!res)
5466 0 : return nullptr;
5467 0 : if (convertDoubleElements)
5468 0 : res->as<ArrayObject>().setShouldConvertDoubleElements();
5469 0 : return res;
5470 : }
5471 :
5472 : typedef JSObject* (*NewArrayWithGroupFn)(JSContext*, uint32_t, HandleObjectGroup, bool);
5473 3 : static const VMFunction NewArrayWithGroupInfo =
5474 6 : FunctionInfo<NewArrayWithGroupFn>(NewArrayWithGroup, "NewArrayWithGroup");
5475 :
5476 : void
5477 3 : CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
5478 : {
5479 3 : Register objReg = ToRegister(lir->output());
5480 :
5481 3 : MOZ_ASSERT(!lir->isCall());
5482 3 : saveLive(lir);
5483 :
5484 3 : JSObject* templateObject = lir->mir()->templateObject();
5485 :
5486 3 : if (templateObject) {
5487 3 : pushArg(Imm32(lir->mir()->convertDoubleElements()));
5488 3 : pushArg(ImmGCPtr(templateObject->group()));
5489 3 : pushArg(Imm32(lir->mir()->length()));
5490 :
5491 3 : callVM(NewArrayWithGroupInfo, lir);
5492 : } else {
5493 0 : pushArg(Imm32(GenericObject));
5494 0 : pushArg(Imm32(lir->mir()->length()));
5495 0 : pushArg(ImmPtr(lir->mir()->pc()));
5496 0 : pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
5497 :
5498 0 : callVM(NewArrayOperationInfo, lir);
5499 : }
5500 :
5501 3 : if (ReturnReg != objReg)
5502 3 : masm.movePtr(ReturnReg, objReg);
5503 :
5504 3 : restoreLive(lir);
5505 3 : }
5506 :
5507 : typedef JSObject* (*NewDerivedTypedObjectFn)(JSContext*,
5508 : HandleObject type,
5509 : HandleObject owner,
5510 : int32_t offset);
5511 3 : static const VMFunction CreateDerivedTypedObjInfo =
5512 6 : FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj, "CreateDerivedTypedObj");
5513 :
5514 : void
5515 0 : CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject* lir)
5516 : {
5517 0 : pushArg(ToRegister(lir->offset()));
5518 0 : pushArg(ToRegister(lir->owner()));
5519 0 : pushArg(ToRegister(lir->type()));
5520 0 : callVM(CreateDerivedTypedObjInfo, lir);
5521 0 : }
5522 :
5523 : void
5524 0 : CodeGenerator::visitAtan2D(LAtan2D* lir)
5525 : {
5526 0 : Register temp = ToRegister(lir->temp());
5527 0 : FloatRegister y = ToFloatRegister(lir->y());
5528 0 : FloatRegister x = ToFloatRegister(lir->x());
5529 :
5530 0 : masm.setupUnalignedABICall(temp);
5531 0 : masm.passABIArg(y, MoveOp::DOUBLE);
5532 0 : masm.passABIArg(x, MoveOp::DOUBLE);
5533 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaAtan2), MoveOp::DOUBLE);
5534 :
5535 0 : MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
5536 0 : }
5537 :
5538 : void
5539 0 : CodeGenerator::visitHypot(LHypot* lir)
5540 : {
5541 0 : Register temp = ToRegister(lir->temp());
5542 0 : uint32_t numArgs = lir->numArgs();
5543 0 : masm.setupUnalignedABICall(temp);
5544 :
5545 0 : for (uint32_t i = 0 ; i < numArgs; ++i)
5546 0 : masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
5547 :
5548 0 : switch(numArgs) {
5549 : case 2:
5550 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaHypot), MoveOp::DOUBLE);
5551 0 : break;
5552 : case 3:
5553 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, hypot3), MoveOp::DOUBLE);
5554 0 : break;
5555 : case 4:
5556 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, hypot4), MoveOp::DOUBLE);
5557 0 : break;
5558 : default:
5559 0 : MOZ_CRASH("Unexpected number of arguments to hypot function.");
5560 : }
5561 0 : MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
5562 0 : }
5563 :
5564 : void
5565 3 : CodeGenerator::visitNewArray(LNewArray* lir)
5566 : {
5567 3 : Register objReg = ToRegister(lir->output());
5568 3 : Register tempReg = ToRegister(lir->temp());
5569 3 : JSObject* templateObject = lir->mir()->templateObject();
5570 6 : DebugOnly<uint32_t> length = lir->mir()->length();
5571 :
5572 3 : MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
5573 :
5574 3 : if (lir->mir()->isVMCall()) {
5575 0 : visitNewArrayCallVM(lir);
5576 0 : return;
5577 : }
5578 :
5579 3 : OutOfLineNewArray* ool = new(alloc()) OutOfLineNewArray(lir);
5580 3 : addOutOfLineCode(ool, lir->mir());
5581 :
5582 3 : masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(),
5583 : ool->entry(), /* initContents = */ true,
5584 6 : lir->mir()->convertDoubleElements());
5585 :
5586 3 : masm.bind(ool->rejoin());
5587 : }
5588 :
5589 : void
5590 3 : CodeGenerator::visitOutOfLineNewArray(OutOfLineNewArray* ool)
5591 : {
5592 3 : visitNewArrayCallVM(ool->lir());
5593 3 : masm.jump(ool->rejoin());
5594 3 : }
5595 :
5596 : void
5597 0 : CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
5598 : {
5599 0 : Register objReg = ToRegister(lir->output());
5600 0 : Register tempReg = ToRegister(lir->temp());
5601 0 : ArrayObject* templateObject = lir->mir()->templateObject();
5602 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5603 :
5604 : // If we have a template object, we can inline call object creation.
5605 0 : OutOfLineCode* ool = oolCallVM(NewArrayCopyOnWriteInfo, lir,
5606 0 : ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
5607 0 : StoreRegisterTo(objReg));
5608 :
5609 0 : masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
5610 :
5611 0 : masm.bind(ool->rejoin());
5612 0 : }
5613 :
5614 : typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
5615 3 : static const VMFunction ArrayConstructorOneArgInfo =
5616 6 : FunctionInfo<ArrayConstructorOneArgFn>(ArrayConstructorOneArg, "ArrayConstructorOneArg");
5617 :
5618 : void
5619 0 : CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
5620 : {
5621 0 : Register lengthReg = ToRegister(lir->length());
5622 0 : Register objReg = ToRegister(lir->output());
5623 0 : Register tempReg = ToRegister(lir->temp());
5624 :
5625 0 : JSObject* templateObject = lir->mir()->templateObject();
5626 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5627 :
5628 0 : OutOfLineCode* ool = oolCallVM(ArrayConstructorOneArgInfo, lir,
5629 0 : ArgList(ImmGCPtr(templateObject->group()), lengthReg),
5630 0 : StoreRegisterTo(objReg));
5631 :
5632 0 : bool canInline = true;
5633 0 : size_t inlineLength = 0;
5634 0 : if (templateObject->is<ArrayObject>()) {
5635 0 : if (templateObject->as<ArrayObject>().hasFixedElements()) {
5636 0 : size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
5637 0 : inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
5638 : } else {
5639 0 : canInline = false;
5640 : }
5641 : } else {
5642 0 : if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
5643 : size_t nbytes =
5644 0 : templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
5645 0 : inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
5646 : } else {
5647 0 : canInline = false;
5648 : }
5649 : }
5650 :
5651 0 : if (canInline) {
5652 : // Try to do the allocation inline if the template object is big enough
5653 : // for the length in lengthReg. If the length is bigger we could still
5654 : // use the template object and not allocate the elements, but it's more
5655 : // efficient to do a single big allocation than (repeatedly) reallocating
5656 : // the array later on when filling it.
5657 0 : masm.branch32(Assembler::Above, lengthReg, Imm32(inlineLength), ool->entry());
5658 :
5659 0 : masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
5660 :
5661 0 : size_t lengthOffset = NativeObject::offsetOfFixedElements() + ObjectElements::offsetOfLength();
5662 0 : masm.store32(lengthReg, Address(objReg, lengthOffset));
5663 : } else {
5664 0 : masm.jump(ool->entry());
5665 : }
5666 :
5667 0 : masm.bind(ool->rejoin());
5668 0 : }
5669 :
5670 : typedef ArrayIteratorObject* (*NewArrayIteratorObjectFn)(JSContext*, NewObjectKind);
5671 3 : static const VMFunction NewArrayIteratorObjectInfo =
5672 6 : FunctionInfo<NewArrayIteratorObjectFn>(NewArrayIteratorObject, "NewArrayIteratorObject");
5673 :
5674 : typedef StringIteratorObject* (*NewStringIteratorObjectFn)(JSContext*, NewObjectKind);
5675 3 : static const VMFunction NewStringIteratorObjectInfo =
5676 6 : FunctionInfo<NewStringIteratorObjectFn>(NewStringIteratorObject, "NewStringIteratorObject");
5677 :
5678 : void
5679 0 : CodeGenerator::visitNewIterator(LNewIterator* lir)
5680 : {
5681 0 : Register objReg = ToRegister(lir->output());
5682 0 : Register tempReg = ToRegister(lir->temp());
5683 0 : JSObject* templateObject = lir->mir()->templateObject();
5684 :
5685 : OutOfLineCode* ool;
5686 0 : switch (lir->mir()->type()) {
5687 : case MNewIterator::ArrayIterator:
5688 0 : ool = oolCallVM(NewArrayIteratorObjectInfo, lir,
5689 0 : ArgList(Imm32(GenericObject)),
5690 0 : StoreRegisterTo(objReg));
5691 0 : break;
5692 : case MNewIterator::StringIterator:
5693 0 : ool = oolCallVM(NewStringIteratorObjectInfo, lir,
5694 0 : ArgList(Imm32(GenericObject)),
5695 0 : StoreRegisterTo(objReg));
5696 0 : break;
5697 : default:
5698 0 : MOZ_CRASH("unexpected iterator type");
5699 : }
5700 :
5701 0 : masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, ool->entry());
5702 :
5703 0 : masm.bind(ool->rejoin());
5704 0 : }
5705 :
5706 : typedef TypedArrayObject* (*TypedArrayConstructorOneArgFn)(JSContext*, HandleObject, int32_t length);
5707 3 : static const VMFunction TypedArrayConstructorOneArgInfo =
5708 6 : FunctionInfo<TypedArrayConstructorOneArgFn>(TypedArrayCreateWithTemplate,
5709 : "TypedArrayCreateWithTemplate");
5710 :
5711 : void
5712 0 : CodeGenerator::visitNewTypedArray(LNewTypedArray* lir)
5713 : {
5714 0 : Register objReg = ToRegister(lir->output());
5715 0 : Register tempReg = ToRegister(lir->temp1());
5716 0 : Register lengthReg = ToRegister(lir->temp2());
5717 0 : LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
5718 :
5719 0 : JSObject* templateObject = lir->mir()->templateObject();
5720 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5721 :
5722 0 : TypedArrayObject* ttemplate = &templateObject->as<TypedArrayObject>();
5723 0 : uint32_t n = ttemplate->length();
5724 :
5725 0 : OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
5726 0 : ArgList(ImmGCPtr(templateObject), Imm32(n)),
5727 0 : StoreRegisterTo(objReg));
5728 :
5729 0 : masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
5730 0 : ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
5731 :
5732 0 : masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
5733 0 : ttemplate, TypedArrayLength::Fixed);
5734 :
5735 0 : masm.bind(ool->rejoin());
5736 0 : }
5737 :
5738 : void
5739 0 : CodeGenerator::visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir)
5740 : {
5741 0 : Register lengthReg = ToRegister(lir->length());
5742 0 : Register objReg = ToRegister(lir->output());
5743 0 : Register tempReg = ToRegister(lir->temp());
5744 0 : LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
5745 :
5746 0 : JSObject* templateObject = lir->mir()->templateObject();
5747 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5748 :
5749 0 : TypedArrayObject* ttemplate = &templateObject->as<TypedArrayObject>();
5750 :
5751 0 : OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
5752 0 : ArgList(ImmGCPtr(templateObject), lengthReg),
5753 0 : StoreRegisterTo(objReg));
5754 :
5755 0 : masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
5756 0 : ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
5757 :
5758 0 : masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
5759 0 : ttemplate, TypedArrayLength::Dynamic);
5760 :
5761 0 : masm.bind(ool->rejoin());
5762 0 : }
5763 :
5764 : // Out-of-line object allocation for JSOP_NEWOBJECT.
5765 : class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
5766 : {
5767 : LNewObject* lir_;
5768 :
5769 : public:
5770 1 : explicit OutOfLineNewObject(LNewObject* lir)
5771 1 : : lir_(lir)
5772 1 : { }
5773 :
5774 1 : void accept(CodeGenerator* codegen) {
5775 1 : codegen->visitOutOfLineNewObject(this);
5776 1 : }
5777 :
5778 1 : LNewObject* lir() const {
5779 1 : return lir_;
5780 : }
5781 : };
5782 :
5783 : typedef JSObject* (*NewInitObjectWithTemplateFn)(JSContext*, HandleObject);
5784 3 : static const VMFunction NewInitObjectWithTemplateInfo =
5785 6 : FunctionInfo<NewInitObjectWithTemplateFn>(NewObjectOperationWithTemplate,
5786 : "NewObjectOperationWithTemplate");
5787 :
5788 : typedef JSObject* (*NewInitObjectFn)(JSContext*, HandleScript, jsbytecode* pc, NewObjectKind);
5789 3 : static const VMFunction NewInitObjectInfo =
5790 6 : FunctionInfo<NewInitObjectFn>(NewObjectOperation, "NewObjectOperation");
5791 :
5792 : typedef PlainObject* (*ObjectCreateWithTemplateFn)(JSContext*, HandlePlainObject);
5793 3 : static const VMFunction ObjectCreateWithTemplateInfo =
5794 6 : FunctionInfo<ObjectCreateWithTemplateFn>(ObjectCreateWithTemplate, "ObjectCreateWithTemplate");
5795 :
5796 : void
5797 1 : CodeGenerator::visitNewObjectVMCall(LNewObject* lir)
5798 : {
5799 1 : Register objReg = ToRegister(lir->output());
5800 :
5801 1 : MOZ_ASSERT(!lir->isCall());
5802 1 : saveLive(lir);
5803 :
5804 1 : JSObject* templateObject = lir->mir()->templateObject();
5805 :
5806 : // If we're making a new object with a class prototype (that is, an object
5807 : // that derives its class from its prototype instead of being
5808 : // PlainObject::class_'d) from self-hosted code, we need a different init
5809 : // function.
5810 1 : switch (lir->mir()->mode()) {
5811 : case MNewObject::ObjectLiteral:
5812 1 : if (templateObject) {
5813 1 : pushArg(ImmGCPtr(templateObject));
5814 1 : callVM(NewInitObjectWithTemplateInfo, lir);
5815 : } else {
5816 0 : pushArg(Imm32(GenericObject));
5817 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
5818 0 : pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
5819 0 : callVM(NewInitObjectInfo, lir);
5820 : }
5821 1 : break;
5822 : case MNewObject::ObjectCreate:
5823 0 : pushArg(ImmGCPtr(templateObject));
5824 0 : callVM(ObjectCreateWithTemplateInfo, lir);
5825 0 : break;
5826 : }
5827 :
5828 1 : if (ReturnReg != objReg)
5829 1 : masm.movePtr(ReturnReg, objReg);
5830 :
5831 1 : restoreLive(lir);
5832 1 : }
5833 :
5834 : static bool
5835 3 : ShouldInitFixedSlots(LInstruction* lir, JSObject* obj)
5836 : {
5837 3 : if (!obj->isNative())
5838 0 : return true;
5839 3 : NativeObject* templateObj = &obj->as<NativeObject>();
5840 :
5841 : // Look for StoreFixedSlot instructions following an object allocation
5842 : // that write to this object before a GC is triggered or this object is
5843 : // passed to a VM call. If all fixed slots will be initialized, the
5844 : // allocation code doesn't need to set the slots to |undefined|.
5845 :
5846 3 : uint32_t nfixed = templateObj->numUsedFixedSlots();
5847 3 : if (nfixed == 0)
5848 0 : return false;
5849 :
5850 : // Only optimize if all fixed slots are initially |undefined|, so that we
5851 : // can assume incremental pre-barriers are not necessary. See also the
5852 : // comment below.
5853 5 : for (uint32_t slot = 0; slot < nfixed; slot++) {
5854 4 : if (!templateObj->getSlot(slot).isUndefined())
5855 2 : return true;
5856 : }
5857 :
5858 : // Keep track of the fixed slots that are initialized. initializedSlots is
5859 : // a bit mask with a bit for each slot.
5860 1 : MOZ_ASSERT(nfixed <= NativeObject::MAX_FIXED_SLOTS);
5861 : static_assert(NativeObject::MAX_FIXED_SLOTS <= 32, "Slot bits must fit in 32 bits");
5862 1 : uint32_t initializedSlots = 0;
5863 1 : uint32_t numInitialized = 0;
5864 :
5865 1 : MInstruction* allocMir = lir->mirRaw()->toInstruction();
5866 1 : MBasicBlock* block = allocMir->block();
5867 :
5868 : // Skip the allocation instruction.
5869 1 : MInstructionIterator iter = block->begin(allocMir);
5870 1 : MOZ_ASSERT(*iter == allocMir);
5871 1 : iter++;
5872 :
5873 : while (true) {
5874 3 : for (; iter != block->end(); iter++) {
5875 2 : if (iter->isNop() || iter->isConstant() || iter->isPostWriteBarrier()) {
5876 : // These instructions won't trigger a GC or read object slots.
5877 0 : continue;
5878 : }
5879 :
5880 2 : if (iter->isStoreFixedSlot()) {
5881 2 : MStoreFixedSlot* store = iter->toStoreFixedSlot();
5882 2 : if (store->object() != allocMir)
5883 0 : return true;
5884 :
5885 : // We may not initialize this object slot on allocation, so the
5886 : // pre-barrier could read uninitialized memory. Simply disable
5887 : // the barrier for this store: the object was just initialized
5888 : // so the barrier is not necessary.
5889 2 : store->setNeedsBarrier(false);
5890 :
5891 2 : uint32_t slot = store->slot();
5892 2 : MOZ_ASSERT(slot < nfixed);
5893 2 : if ((initializedSlots & (1 << slot)) == 0) {
5894 2 : numInitialized++;
5895 2 : initializedSlots |= (1 << slot);
5896 :
5897 2 : if (numInitialized == nfixed) {
5898 : // All fixed slots will be initialized.
5899 1 : MOZ_ASSERT(mozilla::CountPopulation32(initializedSlots) == nfixed);
5900 1 : return false;
5901 : }
5902 : }
5903 1 : continue;
5904 : }
5905 :
5906 0 : if (iter->isGoto()) {
5907 0 : block = iter->toGoto()->target();
5908 0 : if (block->numPredecessors() != 1)
5909 0 : return true;
5910 0 : break;
5911 : }
5912 :
5913 : // Unhandled instruction, assume it bails or reads object slots.
5914 0 : return true;
5915 : }
5916 0 : iter = block->begin();
5917 0 : }
5918 :
5919 : MOZ_CRASH("Shouldn't get here");
5920 : }
5921 :
5922 : void
5923 1 : CodeGenerator::visitNewObject(LNewObject* lir)
5924 : {
5925 1 : Register objReg = ToRegister(lir->output());
5926 1 : Register tempReg = ToRegister(lir->temp());
5927 1 : JSObject* templateObject = lir->mir()->templateObject();
5928 :
5929 1 : if (lir->mir()->isVMCall()) {
5930 0 : visitNewObjectVMCall(lir);
5931 0 : return;
5932 : }
5933 :
5934 1 : OutOfLineNewObject* ool = new(alloc()) OutOfLineNewObject(lir);
5935 1 : addOutOfLineCode(ool, lir->mir());
5936 :
5937 1 : bool initContents = ShouldInitFixedSlots(lir, templateObject);
5938 1 : masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
5939 1 : initContents);
5940 :
5941 1 : masm.bind(ool->rejoin());
5942 : }
5943 :
5944 : void
5945 1 : CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject* ool)
5946 : {
5947 1 : visitNewObjectVMCall(ool->lir());
5948 1 : masm.jump(ool->rejoin());
5949 1 : }
5950 :
5951 : typedef InlineTypedObject* (*NewTypedObjectFn)(JSContext*, Handle<InlineTypedObject*>, gc::InitialHeap);
5952 3 : static const VMFunction NewTypedObjectInfo =
5953 6 : FunctionInfo<NewTypedObjectFn>(InlineTypedObject::createCopy, "InlineTypedObject::createCopy");
5954 :
5955 : void
5956 0 : CodeGenerator::visitNewTypedObject(LNewTypedObject* lir)
5957 : {
5958 0 : Register object = ToRegister(lir->output());
5959 0 : Register temp = ToRegister(lir->temp());
5960 0 : InlineTypedObject* templateObject = lir->mir()->templateObject();
5961 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5962 :
5963 0 : OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
5964 0 : ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
5965 0 : StoreRegisterTo(object));
5966 :
5967 0 : masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
5968 :
5969 0 : masm.bind(ool->rejoin());
5970 0 : }
5971 :
5972 : void
5973 0 : CodeGenerator::visitSimdBox(LSimdBox* lir)
5974 : {
5975 0 : FloatRegister in = ToFloatRegister(lir->input());
5976 0 : Register object = ToRegister(lir->output());
5977 0 : Register temp = ToRegister(lir->temp());
5978 0 : InlineTypedObject* templateObject = lir->mir()->templateObject();
5979 0 : gc::InitialHeap initialHeap = lir->mir()->initialHeap();
5980 0 : MIRType type = lir->mir()->input()->type();
5981 :
5982 0 : registerSimdTemplate(lir->mir()->simdType());
5983 :
5984 0 : MOZ_ASSERT(lir->safepoint()->liveRegs().has(in), "Save the input register across oolCallVM");
5985 0 : OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
5986 0 : ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
5987 0 : StoreRegisterTo(object));
5988 :
5989 0 : masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
5990 0 : masm.bind(ool->rejoin());
5991 :
5992 0 : Address objectData(object, InlineTypedObject::offsetOfDataStart());
5993 0 : switch (type) {
5994 : case MIRType::Int8x16:
5995 : case MIRType::Int16x8:
5996 : case MIRType::Int32x4:
5997 : case MIRType::Bool8x16:
5998 : case MIRType::Bool16x8:
5999 : case MIRType::Bool32x4:
6000 0 : masm.storeUnalignedSimd128Int(in, objectData);
6001 0 : break;
6002 : case MIRType::Float32x4:
6003 0 : masm.storeUnalignedSimd128Float(in, objectData);
6004 0 : break;
6005 : default:
6006 0 : MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox.");
6007 : }
6008 0 : }
6009 :
6010 : void
6011 0 : CodeGenerator::registerSimdTemplate(SimdType simdType)
6012 : {
6013 0 : simdRefreshTemplatesDuringLink_ |= 1 << uint32_t(simdType);
6014 0 : }
6015 :
6016 : void
6017 7 : CodeGenerator::captureSimdTemplate(JSContext* cx)
6018 : {
6019 7 : JitCompartment* jitCompartment = cx->compartment()->jitCompartment();
6020 7 : while (simdRefreshTemplatesDuringLink_) {
6021 0 : uint32_t typeIndex = mozilla::CountTrailingZeroes32(simdRefreshTemplatesDuringLink_);
6022 0 : simdRefreshTemplatesDuringLink_ ^= 1 << typeIndex;
6023 0 : SimdType type = SimdType(typeIndex);
6024 :
6025 : // Note: the weak-reference on the template object should not have been
6026 : // garbage collected. It is either registered by IonBuilder, or verified
6027 : // before using it in the EagerSimdUnbox phase.
6028 0 : jitCompartment->registerSimdTemplateObjectFor(type);
6029 : }
6030 7 : }
6031 :
6032 : void
6033 0 : CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
6034 : {
6035 0 : Register object = ToRegister(lir->input());
6036 0 : FloatRegister simd = ToFloatRegister(lir->output());
6037 0 : Register temp = ToRegister(lir->temp());
6038 0 : Label bail;
6039 :
6040 : // obj->group()
6041 0 : masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp);
6042 :
6043 : // Guard that the object has the same representation as the one produced for
6044 : // SIMD value-type.
6045 0 : Address clasp(temp, ObjectGroup::offsetOfClasp());
6046 : static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
6047 0 : masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
6048 0 : &bail);
6049 :
6050 : // obj->type()->typeDescr()
6051 : // The previous class pointer comparison implies that the addendumKind is
6052 : // Addendum_TypeDescr.
6053 0 : masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp);
6054 :
6055 : // Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
6056 : // Value which is equivalent to the object class check.
6057 : static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
6058 0 : Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
6059 0 : masm.assertTestInt32(Assembler::Equal, typeDescrKind,
6060 0 : "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
6061 0 : masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
6062 :
6063 0 : SimdType type = lir->mir()->simdType();
6064 :
6065 : // Check if the SimdTypeDescr /Type/ match the specialization of this
6066 : // MSimdUnbox instruction.
6067 : static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
6068 0 : Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
6069 0 : masm.assertTestInt32(Assembler::Equal, typeDescrType,
6070 0 : "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
6071 0 : masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(int32_t(type)), &bail);
6072 :
6073 : // Load the value from the data of the InlineTypedObject.
6074 0 : Address objectData(object, InlineTypedObject::offsetOfDataStart());
6075 0 : switch (lir->mir()->type()) {
6076 : case MIRType::Int8x16:
6077 : case MIRType::Int16x8:
6078 : case MIRType::Int32x4:
6079 : case MIRType::Bool8x16:
6080 : case MIRType::Bool16x8:
6081 : case MIRType::Bool32x4:
6082 0 : masm.loadUnalignedSimd128Int(objectData, simd);
6083 0 : break;
6084 : case MIRType::Float32x4:
6085 0 : masm.loadUnalignedSimd128Float(objectData, simd);
6086 0 : break;
6087 : default:
6088 0 : MOZ_CRASH("The impossible happened!");
6089 : }
6090 :
6091 0 : bailoutFrom(&bail, lir->snapshot());
6092 0 : }
6093 :
6094 : typedef js::NamedLambdaObject* (*NewNamedLambdaObjectFn)(JSContext*, HandleFunction, gc::InitialHeap);
6095 3 : static const VMFunction NewNamedLambdaObjectInfo =
6096 6 : FunctionInfo<NewNamedLambdaObjectFn>(NamedLambdaObject::createTemplateObject,
6097 : "NamedLambdaObject::createTemplateObject");
6098 :
6099 : void
6100 0 : CodeGenerator::visitNewNamedLambdaObject(LNewNamedLambdaObject* lir)
6101 : {
6102 0 : Register objReg = ToRegister(lir->output());
6103 0 : Register tempReg = ToRegister(lir->temp());
6104 0 : EnvironmentObject* templateObj = lir->mir()->templateObj();
6105 0 : const CompileInfo& info = lir->mir()->block()->info();
6106 :
6107 : // If we have a template object, we can inline call object creation.
6108 0 : OutOfLineCode* ool = oolCallVM(NewNamedLambdaObjectInfo, lir,
6109 0 : ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(gc::DefaultHeap)),
6110 0 : StoreRegisterTo(objReg));
6111 :
6112 0 : bool initContents = ShouldInitFixedSlots(lir, templateObj);
6113 0 : masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
6114 0 : initContents);
6115 :
6116 0 : masm.bind(ool->rejoin());
6117 0 : }
6118 :
6119 : typedef JSObject* (*NewCallObjectFn)(JSContext*, HandleShape, HandleObjectGroup);
6120 3 : static const VMFunction NewCallObjectInfo =
6121 6 : FunctionInfo<NewCallObjectFn>(NewCallObject, "NewCallObject");
6122 :
6123 : void
6124 2 : CodeGenerator::visitNewCallObject(LNewCallObject* lir)
6125 : {
6126 2 : Register objReg = ToRegister(lir->output());
6127 2 : Register tempReg = ToRegister(lir->temp());
6128 :
6129 2 : CallObject* templateObj = lir->mir()->templateObject();
6130 :
6131 2 : OutOfLineCode* ool = oolCallVM(NewCallObjectInfo, lir,
6132 4 : ArgList(ImmGCPtr(templateObj->lastProperty()),
6133 4 : ImmGCPtr(templateObj->group())),
6134 6 : StoreRegisterTo(objReg));
6135 :
6136 : // Inline call object creation, using the OOL path only for tricky cases.
6137 2 : bool initContents = ShouldInitFixedSlots(lir, templateObj);
6138 2 : masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
6139 2 : initContents);
6140 :
6141 2 : masm.bind(ool->rejoin());
6142 2 : }
6143 :
6144 : typedef JSObject* (*NewSingletonCallObjectFn)(JSContext*, HandleShape);
6145 3 : static const VMFunction NewSingletonCallObjectInfo =
6146 6 : FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject, "NewSingletonCallObject");
6147 :
6148 : void
6149 0 : CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject* lir)
6150 : {
6151 0 : Register objReg = ToRegister(lir->output());
6152 :
6153 0 : JSObject* templateObj = lir->mir()->templateObject();
6154 :
6155 : OutOfLineCode* ool;
6156 0 : ool = oolCallVM(NewSingletonCallObjectInfo, lir,
6157 0 : ArgList(ImmGCPtr(templateObj->as<CallObject>().lastProperty())),
6158 0 : StoreRegisterTo(objReg));
6159 :
6160 : // Objects can only be given singleton types in VM calls. We make the call
6161 : // out of line to not bloat inline code, even if (naively) this seems like
6162 : // extra work.
6163 0 : masm.jump(ool->entry());
6164 0 : masm.bind(ool->rejoin());
6165 0 : }
6166 :
6167 : typedef JSObject* (*NewStringObjectFn)(JSContext*, HandleString);
6168 3 : static const VMFunction NewStringObjectInfo =
6169 6 : FunctionInfo<NewStringObjectFn>(NewStringObject, "NewStringObject");
6170 :
6171 : void
6172 0 : CodeGenerator::visitNewStringObject(LNewStringObject* lir)
6173 : {
6174 0 : Register input = ToRegister(lir->input());
6175 0 : Register output = ToRegister(lir->output());
6176 0 : Register temp = ToRegister(lir->temp());
6177 :
6178 0 : StringObject* templateObj = lir->mir()->templateObj();
6179 :
6180 0 : OutOfLineCode* ool = oolCallVM(NewStringObjectInfo, lir, ArgList(input),
6181 0 : StoreRegisterTo(output));
6182 :
6183 0 : masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
6184 :
6185 0 : masm.loadStringLength(input, temp);
6186 :
6187 0 : masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
6188 0 : masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
6189 :
6190 0 : masm.bind(ool->rejoin());
6191 0 : }
6192 :
6193 : typedef bool(*InitElemFn)(JSContext* cx, jsbytecode* pc, HandleObject obj,
6194 : HandleValue id, HandleValue value);
6195 3 : static const VMFunction InitElemInfo =
6196 6 : FunctionInfo<InitElemFn>(InitElemOperation, "InitElemOperation");
6197 :
6198 : void
6199 0 : CodeGenerator::visitInitElem(LInitElem* lir)
6200 : {
6201 0 : Register objReg = ToRegister(lir->getObject());
6202 :
6203 0 : pushArg(ToValue(lir, LInitElem::ValueIndex));
6204 0 : pushArg(ToValue(lir, LInitElem::IdIndex));
6205 0 : pushArg(objReg);
6206 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
6207 :
6208 0 : callVM(InitElemInfo, lir);
6209 0 : }
6210 :
6211 : typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandleValue,
6212 : HandleObject);
6213 3 : static const VMFunction InitElemGetterSetterInfo =
6214 6 : FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
6215 :
6216 : void
6217 0 : CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter* lir)
6218 : {
6219 0 : Register obj = ToRegister(lir->object());
6220 0 : Register value = ToRegister(lir->value());
6221 :
6222 0 : pushArg(value);
6223 0 : pushArg(ToValue(lir, LInitElemGetterSetter::IdIndex));
6224 0 : pushArg(obj);
6225 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
6226 :
6227 0 : callVM(InitElemGetterSetterInfo, lir);
6228 0 : }
6229 :
6230 : typedef bool(*MutatePrototypeFn)(JSContext* cx, HandlePlainObject obj, HandleValue value);
6231 3 : static const VMFunction MutatePrototypeInfo =
6232 6 : FunctionInfo<MutatePrototypeFn>(MutatePrototype, "MutatePrototype");
6233 :
6234 : void
6235 0 : CodeGenerator::visitMutateProto(LMutateProto* lir)
6236 : {
6237 0 : Register objReg = ToRegister(lir->getObject());
6238 :
6239 0 : pushArg(ToValue(lir, LMutateProto::ValueIndex));
6240 0 : pushArg(objReg);
6241 :
6242 0 : callVM(MutatePrototypeInfo, lir);
6243 0 : }
6244 :
6245 : typedef bool(*InitPropFn)(JSContext*, HandleObject, HandlePropertyName, HandleValue, jsbytecode* pc);
6246 3 : static const VMFunction InitPropInfo = FunctionInfo<InitPropFn>(InitProp, "InitProp");
6247 :
6248 : void
6249 0 : CodeGenerator::visitInitProp(LInitProp* lir)
6250 : {
6251 0 : Register objReg = ToRegister(lir->getObject());
6252 :
6253 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
6254 0 : pushArg(ToValue(lir, LInitProp::ValueIndex));
6255 0 : pushArg(ImmGCPtr(lir->mir()->propertyName()));
6256 0 : pushArg(objReg);
6257 :
6258 0 : callVM(InitPropInfo, lir);
6259 0 : }
6260 :
6261 : typedef bool(*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandlePropertyName,
6262 : HandleObject);
6263 3 : static const VMFunction InitPropGetterSetterInfo =
6264 6 : FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
6265 :
6266 : void
6267 0 : CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
6268 : {
6269 0 : Register obj = ToRegister(lir->object());
6270 0 : Register value = ToRegister(lir->value());
6271 :
6272 0 : pushArg(value);
6273 0 : pushArg(ImmGCPtr(lir->mir()->name()));
6274 0 : pushArg(obj);
6275 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
6276 :
6277 0 : callVM(InitPropGetterSetterInfo, lir);
6278 0 : }
6279 :
6280 : typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
6281 3 : static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis, "CreateThis");
6282 :
6283 : void
6284 4 : CodeGenerator::visitCreateThis(LCreateThis* lir)
6285 : {
6286 4 : const LAllocation* callee = lir->getCallee();
6287 4 : const LAllocation* newTarget = lir->getNewTarget();
6288 :
6289 4 : if (newTarget->isConstant())
6290 0 : pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
6291 : else
6292 4 : pushArg(ToRegister(newTarget));
6293 :
6294 4 : if (callee->isConstant())
6295 0 : pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
6296 : else
6297 4 : pushArg(ToRegister(callee));
6298 :
6299 4 : callVM(CreateThisInfoCodeGen, lir);
6300 4 : }
6301 :
6302 : static JSObject*
6303 0 : CreateThisForFunctionWithProtoWrapper(JSContext* cx, HandleObject callee, HandleObject newTarget,
6304 : HandleObject proto)
6305 : {
6306 0 : return CreateThisForFunctionWithProto(cx, callee, newTarget, proto);
6307 : }
6308 :
6309 : typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee,
6310 : HandleObject newTarget, HandleObject proto);
6311 3 : static const VMFunction CreateThisWithProtoInfo =
6312 6 : FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper,
6313 : "CreateThisForFunctionWithProtoWrapper");
6314 :
6315 : void
6316 0 : CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
6317 : {
6318 0 : const LAllocation* callee = lir->getCallee();
6319 0 : const LAllocation* newTarget = lir->getNewTarget();
6320 0 : const LAllocation* proto = lir->getPrototype();
6321 :
6322 0 : if (proto->isConstant())
6323 0 : pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
6324 : else
6325 0 : pushArg(ToRegister(proto));
6326 :
6327 0 : if (newTarget->isConstant())
6328 0 : pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
6329 : else
6330 0 : pushArg(ToRegister(newTarget));
6331 :
6332 0 : if (callee->isConstant())
6333 0 : pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
6334 : else
6335 0 : pushArg(ToRegister(callee));
6336 :
6337 0 : callVM(CreateThisWithProtoInfo, lir);
6338 0 : }
6339 :
6340 : void
6341 0 : CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate* lir)
6342 : {
6343 0 : JSObject* templateObject = lir->mir()->templateObject();
6344 0 : Register objReg = ToRegister(lir->output());
6345 0 : Register tempReg = ToRegister(lir->temp());
6346 :
6347 0 : OutOfLineCode* ool = oolCallVM(NewInitObjectWithTemplateInfo, lir,
6348 0 : ArgList(ImmGCPtr(templateObject)),
6349 0 : StoreRegisterTo(objReg));
6350 :
6351 : // Allocate. If the FreeList is empty, call to VM, which may GC.
6352 0 : bool initContents = !templateObject->is<PlainObject>() ||
6353 0 : ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
6354 0 : masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
6355 0 : initContents);
6356 :
6357 0 : masm.bind(ool->rejoin());
6358 0 : }
6359 :
6360 : typedef JSObject* (*NewIonArgumentsObjectFn)(JSContext* cx, JitFrameLayout* frame, HandleObject);
6361 3 : static const VMFunction NewIonArgumentsObjectInfo =
6362 6 : FunctionInfo<NewIonArgumentsObjectFn>((NewIonArgumentsObjectFn) ArgumentsObject::createForIon,
6363 : "ArgumentsObject::createForIon");
6364 :
6365 : void
6366 0 : CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject* lir)
6367 : {
6368 : // This should be getting constructed in the first block only, and not any OSR entry blocks.
6369 0 : MOZ_ASSERT(lir->mir()->block()->id() == 0);
6370 :
6371 0 : Register callObj = ToRegister(lir->getCallObject());
6372 0 : Register temp = ToRegister(lir->temp0());
6373 0 : Label done;
6374 :
6375 0 : if (ArgumentsObject* templateObj = lir->mir()->templateObject()) {
6376 0 : Register objTemp = ToRegister(lir->temp1());
6377 0 : Register cxTemp = ToRegister(lir->temp2());
6378 :
6379 0 : masm.Push(callObj);
6380 :
6381 : // Try to allocate an arguments object. This will leave the reserved
6382 : // slots uninitialized, so it's important we don't GC until we
6383 : // initialize these slots in ArgumentsObject::finishForIon.
6384 0 : Label failure;
6385 0 : masm.createGCObject(objTemp, temp, templateObj, gc::DefaultHeap, &failure,
6386 0 : /* initContents = */ false);
6387 :
6388 0 : masm.moveStackPtrTo(temp);
6389 0 : masm.addPtr(Imm32(masm.framePushed()), temp);
6390 :
6391 0 : masm.setupUnalignedABICall(cxTemp);
6392 0 : masm.loadJSContext(cxTemp);
6393 0 : masm.passABIArg(cxTemp);
6394 0 : masm.passABIArg(temp);
6395 0 : masm.passABIArg(callObj);
6396 0 : masm.passABIArg(objTemp);
6397 :
6398 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArgumentsObject::finishForIon));
6399 0 : masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, &failure);
6400 :
6401 : // Discard saved callObj on the stack.
6402 0 : masm.addToStackPtr(Imm32(sizeof(uintptr_t)));
6403 0 : masm.jump(&done);
6404 :
6405 0 : masm.bind(&failure);
6406 0 : masm.Pop(callObj);
6407 : }
6408 :
6409 0 : masm.moveStackPtrTo(temp);
6410 0 : masm.addPtr(Imm32(frameSize()), temp);
6411 :
6412 0 : pushArg(callObj);
6413 0 : pushArg(temp);
6414 0 : callVM(NewIonArgumentsObjectInfo, lir);
6415 :
6416 0 : masm.bind(&done);
6417 0 : }
6418 :
6419 : void
6420 0 : CodeGenerator::visitGetArgumentsObjectArg(LGetArgumentsObjectArg* lir)
6421 : {
6422 0 : Register temp = ToRegister(lir->getTemp(0));
6423 0 : Register argsObj = ToRegister(lir->getArgsObject());
6424 0 : ValueOperand out = ToOutValue(lir);
6425 :
6426 0 : masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
6427 0 : Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
6428 0 : masm.loadValue(argAddr, out);
6429 : #ifdef DEBUG
6430 0 : Label success;
6431 0 : masm.branchTestMagic(Assembler::NotEqual, out, &success);
6432 0 : masm.assumeUnreachable("Result from ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
6433 0 : masm.bind(&success);
6434 : #endif
6435 0 : }
6436 :
6437 : void
6438 0 : CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg* lir)
6439 : {
6440 0 : Register temp = ToRegister(lir->getTemp(0));
6441 0 : Register argsObj = ToRegister(lir->getArgsObject());
6442 0 : ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
6443 :
6444 0 : masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
6445 0 : Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
6446 0 : emitPreBarrier(argAddr);
6447 : #ifdef DEBUG
6448 0 : Label success;
6449 0 : masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
6450 0 : masm.assumeUnreachable("Result in ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
6451 0 : masm.bind(&success);
6452 : #endif
6453 0 : masm.storeValue(value, argAddr);
6454 0 : }
6455 :
6456 : void
6457 0 : CodeGenerator::visitReturnFromCtor(LReturnFromCtor* lir)
6458 : {
6459 0 : ValueOperand value = ToValue(lir, LReturnFromCtor::ValueIndex);
6460 0 : Register obj = ToRegister(lir->getObject());
6461 0 : Register output = ToRegister(lir->output());
6462 :
6463 0 : Label valueIsObject, end;
6464 :
6465 0 : masm.branchTestObject(Assembler::Equal, value, &valueIsObject);
6466 :
6467 : // Value is not an object. Return that other object.
6468 0 : masm.movePtr(obj, output);
6469 0 : masm.jump(&end);
6470 :
6471 : // Value is an object. Return unbox(Value).
6472 0 : masm.bind(&valueIsObject);
6473 0 : Register payload = masm.extractObject(value, output);
6474 0 : if (payload != output)
6475 0 : masm.movePtr(payload, output);
6476 :
6477 0 : masm.bind(&end);
6478 0 : }
6479 :
6480 : typedef bool (*BoxNonStrictThisFn)(JSContext*, HandleValue, MutableHandleValue);
6481 3 : static const VMFunction BoxNonStrictThisInfo =
6482 6 : FunctionInfo<BoxNonStrictThisFn>(BoxNonStrictThis, "BoxNonStrictThis");
6483 :
6484 : void
6485 0 : CodeGenerator::visitComputeThis(LComputeThis* lir)
6486 : {
6487 0 : ValueOperand value = ToValue(lir, LComputeThis::ValueIndex);
6488 0 : ValueOperand output = ToOutValue(lir);
6489 :
6490 0 : OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value), StoreValueTo(output));
6491 :
6492 0 : masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
6493 0 : masm.moveValue(value, output);
6494 0 : masm.bind(ool->rejoin());
6495 0 : }
6496 :
6497 : void
6498 0 : CodeGenerator::visitArrowNewTarget(LArrowNewTarget* lir)
6499 : {
6500 0 : Register callee = ToRegister(lir->callee());
6501 0 : ValueOperand output = ToOutValue(lir);
6502 0 : masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowNewTargetSlot()), output);
6503 0 : }
6504 :
6505 : void
6506 2 : CodeGenerator::visitArrayLength(LArrayLength* lir)
6507 : {
6508 2 : Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
6509 2 : masm.load32(length, ToRegister(lir->output()));
6510 2 : }
6511 :
6512 : void
6513 0 : CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
6514 : {
6515 0 : Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
6516 0 : RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
6517 :
6518 0 : masm.inc32(&newLength);
6519 0 : masm.store32(newLength, length);
6520 : // Restore register value if it is used/captured after.
6521 0 : masm.dec32(&newLength);
6522 0 : }
6523 :
6524 : template <class OrderedHashTable>
6525 : static void
6526 : RangeFront(MacroAssembler&, Register, Register, Register);
6527 :
6528 : template <>
6529 : void
6530 0 : RangeFront<ValueMap>(MacroAssembler& masm, Register range, Register i, Register front)
6531 : {
6532 0 : masm.loadPtr(Address(range, ValueMap::Range::offsetOfHashTable()), front);
6533 0 : masm.loadPtr(Address(front, ValueMap::offsetOfImplData()), front);
6534 :
6535 0 : MOZ_ASSERT(ValueMap::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
6536 : static_assert(ValueMap::sizeofImplData() == 24, "sizeof(Data) is 24");
6537 0 : masm.mulBy3(i, i);
6538 0 : masm.lshiftPtr(Imm32(3), i);
6539 0 : masm.addPtr(i, front);
6540 0 : }
6541 :
6542 : template <>
6543 : void
6544 0 : RangeFront<ValueSet>(MacroAssembler& masm, Register range, Register i, Register front)
6545 : {
6546 0 : masm.loadPtr(Address(range, ValueSet::Range::offsetOfHashTable()), front);
6547 0 : masm.loadPtr(Address(front, ValueSet::offsetOfImplData()), front);
6548 :
6549 0 : MOZ_ASSERT(ValueSet::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
6550 : static_assert(ValueSet::sizeofImplData() == 16, "sizeof(Data) is 16");
6551 0 : masm.lshiftPtr(Imm32(4), i);
6552 0 : masm.addPtr(i, front);
6553 0 : }
6554 :
6555 : template <class OrderedHashTable>
6556 : static void
6557 0 : RangePopFront(MacroAssembler& masm, Register range, Register front, Register dataLength,
6558 : Register temp)
6559 : {
6560 0 : Register i = temp;
6561 :
6562 0 : masm.add32(Imm32(1), Address(range, OrderedHashTable::Range::offsetOfCount()));
6563 :
6564 0 : masm.load32(Address(range, OrderedHashTable::Range::offsetOfI()), i);
6565 0 : masm.add32(Imm32(1), i);
6566 :
6567 0 : Label done, seek;
6568 0 : masm.bind(&seek);
6569 0 : masm.branch32(Assembler::AboveOrEqual, i, dataLength, &done);
6570 :
6571 : // We can add sizeof(Data) to |front| to select the next element, because
6572 : // |front| and |range.ht.data[i]| point to the same location.
6573 0 : MOZ_ASSERT(OrderedHashTable::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
6574 0 : masm.addPtr(Imm32(OrderedHashTable::sizeofImplData()), front);
6575 :
6576 0 : masm.branchTestMagic(Assembler::NotEqual, Address(front, OrderedHashTable::offsetOfEntryKey()),
6577 : JS_HASH_KEY_EMPTY, &done);
6578 :
6579 0 : masm.add32(Imm32(1), i);
6580 0 : masm.jump(&seek);
6581 :
6582 0 : masm.bind(&done);
6583 0 : masm.store32(i, Address(range, OrderedHashTable::Range::offsetOfI()));
6584 0 : }
6585 :
6586 : template <class OrderedHashTable>
6587 : static inline void
6588 0 : RangeDestruct(MacroAssembler& masm, Register range, Register temp0, Register temp1)
6589 : {
6590 0 : Register next = temp0;
6591 0 : Register prevp = temp1;
6592 :
6593 0 : masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfNext()), next);
6594 0 : masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfPrevP()), prevp);
6595 0 : masm.storePtr(next, Address(prevp, 0));
6596 :
6597 0 : Label hasNoNext;
6598 0 : masm.branchTestPtr(Assembler::Zero, next, next, &hasNoNext);
6599 :
6600 0 : masm.storePtr(prevp, Address(next, OrderedHashTable::Range::offsetOfPrevP()));
6601 :
6602 0 : masm.bind(&hasNoNext);
6603 :
6604 0 : masm.callFreeStub(range);
6605 0 : }
6606 :
6607 : template <>
6608 : void
6609 0 : CodeGenerator::emitLoadIteratorValues<ValueMap>(Register result, Register temp, Register front)
6610 : {
6611 0 : size_t elementsOffset = NativeObject::offsetOfFixedElements();
6612 :
6613 0 : Address keyAddress(front, ValueMap::Entry::offsetOfKey());
6614 0 : Address valueAddress(front, ValueMap::Entry::offsetOfValue());
6615 0 : Address keyElemAddress(result, elementsOffset);
6616 0 : Address valueElemAddress(result, elementsOffset + sizeof(Value));
6617 0 : masm.guardedCallPreBarrier(keyElemAddress, MIRType::Value);
6618 0 : masm.guardedCallPreBarrier(valueElemAddress, MIRType::Value);
6619 0 : masm.storeValue(keyAddress, keyElemAddress, temp);
6620 0 : masm.storeValue(valueAddress, valueElemAddress, temp);
6621 :
6622 0 : Label keyIsNotObject, valueIsNotNurseryObject, emitBarrier;
6623 0 : masm.branchTestObject(Assembler::NotEqual, keyAddress, &keyIsNotObject);
6624 0 : masm.branchValueIsNurseryObject(Assembler::Equal, keyAddress, temp, &emitBarrier);
6625 0 : masm.bind(&keyIsNotObject);
6626 0 : masm.branchTestObject(Assembler::NotEqual, valueAddress, &valueIsNotNurseryObject);
6627 0 : masm.branchValueIsNurseryObject(Assembler::NotEqual, valueAddress, temp,
6628 0 : &valueIsNotNurseryObject);
6629 : {
6630 0 : masm.bind(&emitBarrier);
6631 0 : saveVolatile(temp);
6632 0 : emitPostWriteBarrier(result);
6633 0 : restoreVolatile(temp);
6634 : }
6635 0 : masm.bind(&valueIsNotNurseryObject);
6636 0 : }
6637 :
6638 : template <>
6639 : void
6640 0 : CodeGenerator::emitLoadIteratorValues<ValueSet>(Register result, Register temp, Register front)
6641 : {
6642 0 : size_t elementsOffset = NativeObject::offsetOfFixedElements();
6643 :
6644 0 : Address keyAddress(front, ValueSet::offsetOfEntryKey());
6645 0 : Address keyElemAddress(result, elementsOffset);
6646 0 : masm.guardedCallPreBarrier(keyElemAddress, MIRType::Value);
6647 0 : masm.storeValue(keyAddress, keyElemAddress, temp);
6648 :
6649 0 : Label keyIsNotObject;
6650 0 : masm.branchTestObject(Assembler::NotEqual, keyAddress, &keyIsNotObject);
6651 0 : masm.branchValueIsNurseryObject(Assembler::NotEqual, keyAddress, temp, &keyIsNotObject);
6652 : {
6653 0 : saveVolatile(temp);
6654 0 : emitPostWriteBarrier(result);
6655 0 : restoreVolatile(temp);
6656 : }
6657 0 : masm.bind(&keyIsNotObject);
6658 0 : }
6659 :
6660 : template <class IteratorObject, class OrderedHashTable>
6661 : void
6662 0 : CodeGenerator::emitGetNextEntryForIterator(LGetNextEntryForIterator* lir)
6663 : {
6664 0 : Register iter = ToRegister(lir->iter());
6665 0 : Register result = ToRegister(lir->result());
6666 0 : Register temp = ToRegister(lir->temp0());
6667 0 : Register dataLength = ToRegister(lir->temp1());
6668 0 : Register range = ToRegister(lir->temp2());
6669 0 : Register output = ToRegister(lir->output());
6670 :
6671 0 : masm.loadPrivate(Address(iter, NativeObject::getFixedSlotOffset(IteratorObject::RangeSlot)),
6672 : range);
6673 :
6674 0 : Label iterAlreadyDone, iterDone, done;
6675 0 : masm.branchTestPtr(Assembler::Zero, range, range, &iterAlreadyDone);
6676 :
6677 0 : masm.load32(Address(range, OrderedHashTable::Range::offsetOfI()), temp);
6678 0 : masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfHashTable()), dataLength);
6679 0 : masm.load32(Address(dataLength, OrderedHashTable::offsetOfImplDataLength()), dataLength);
6680 0 : masm.branch32(Assembler::AboveOrEqual, temp, dataLength, &iterDone);
6681 : {
6682 0 : masm.push(iter);
6683 :
6684 0 : Register front = iter;
6685 0 : RangeFront<OrderedHashTable>(masm, range, temp, front);
6686 :
6687 0 : emitLoadIteratorValues<OrderedHashTable>(result, temp, front);
6688 :
6689 0 : RangePopFront<OrderedHashTable>(masm, range, front, dataLength, temp);
6690 :
6691 0 : masm.pop(iter);
6692 0 : masm.move32(Imm32(0), output);
6693 : }
6694 0 : masm.jump(&done);
6695 : {
6696 0 : masm.bind(&iterDone);
6697 :
6698 0 : RangeDestruct<OrderedHashTable>(masm, range, temp, dataLength);
6699 :
6700 0 : masm.storeValue(PrivateValue(nullptr),
6701 0 : Address(iter, NativeObject::getFixedSlotOffset(IteratorObject::RangeSlot)));
6702 :
6703 0 : masm.bind(&iterAlreadyDone);
6704 :
6705 0 : masm.move32(Imm32(1), output);
6706 : }
6707 0 : masm.bind(&done);
6708 0 : }
6709 :
6710 : void
6711 0 : CodeGenerator::visitGetNextEntryForIterator(LGetNextEntryForIterator* lir)
6712 : {
6713 0 : if (lir->mir()->mode() == MGetNextEntryForIterator::Map) {
6714 0 : emitGetNextEntryForIterator<MapIteratorObject, ValueMap>(lir);
6715 : } else {
6716 0 : MOZ_ASSERT(lir->mir()->mode() == MGetNextEntryForIterator::Set);
6717 0 : emitGetNextEntryForIterator<SetIteratorObject, ValueSet>(lir);
6718 : }
6719 0 : }
6720 :
6721 : void
6722 0 : CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir)
6723 : {
6724 0 : Register obj = ToRegister(lir->object());
6725 0 : Register out = ToRegister(lir->output());
6726 0 : masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
6727 0 : }
6728 :
6729 : void
6730 0 : CodeGenerator::visitTypedArrayElements(LTypedArrayElements* lir)
6731 : {
6732 0 : Register obj = ToRegister(lir->object());
6733 0 : Register out = ToRegister(lir->output());
6734 0 : masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
6735 0 : }
6736 :
6737 : void
6738 0 : CodeGenerator::visitSetDisjointTypedElements(LSetDisjointTypedElements* lir)
6739 : {
6740 0 : Register target = ToRegister(lir->target());
6741 0 : Register targetOffset = ToRegister(lir->targetOffset());
6742 0 : Register source = ToRegister(lir->source());
6743 :
6744 0 : Register temp = ToRegister(lir->temp());
6745 :
6746 0 : masm.setupUnalignedABICall(temp);
6747 0 : masm.passABIArg(target);
6748 0 : masm.passABIArg(targetOffset);
6749 0 : masm.passABIArg(source);
6750 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::SetDisjointTypedElements));
6751 0 : }
6752 :
6753 : void
6754 0 : CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr* lir)
6755 : {
6756 0 : Register obj = ToRegister(lir->object());
6757 0 : Register out = ToRegister(lir->output());
6758 :
6759 0 : masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), out);
6760 0 : masm.loadPtr(Address(out, ObjectGroup::offsetOfAddendum()), out);
6761 0 : }
6762 :
6763 : void
6764 0 : CodeGenerator::visitTypedObjectElements(LTypedObjectElements* lir)
6765 : {
6766 0 : Register obj = ToRegister(lir->object());
6767 0 : Register out = ToRegister(lir->output());
6768 :
6769 0 : if (lir->mir()->definitelyOutline()) {
6770 0 : masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
6771 : } else {
6772 0 : Label inlineObject, done;
6773 0 : masm.loadObjClass(obj, out);
6774 0 : masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
6775 0 : masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
6776 :
6777 0 : masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
6778 0 : masm.jump(&done);
6779 :
6780 0 : masm.bind(&inlineObject);
6781 0 : masm.computeEffectiveAddress(Address(obj, InlineTypedObject::offsetOfDataStart()), out);
6782 0 : masm.bind(&done);
6783 : }
6784 0 : }
6785 :
6786 : void
6787 0 : CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset* lir)
6788 : {
6789 0 : Register object = ToRegister(lir->object());
6790 0 : Register offset = ToRegister(lir->offset());
6791 0 : Register temp0 = ToRegister(lir->temp0());
6792 0 : Register temp1 = ToRegister(lir->temp1());
6793 :
6794 : // Compute the base pointer for the typed object's owner.
6795 0 : masm.loadPtr(Address(object, OutlineTypedObject::offsetOfOwner()), temp0);
6796 :
6797 0 : Label inlineObject, done;
6798 0 : masm.loadObjClass(temp0, temp1);
6799 0 : masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
6800 0 : masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
6801 :
6802 0 : masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0);
6803 0 : masm.jump(&done);
6804 :
6805 0 : masm.bind(&inlineObject);
6806 0 : masm.addPtr(ImmWord(InlineTypedObject::offsetOfDataStart()), temp0);
6807 :
6808 0 : masm.bind(&done);
6809 :
6810 : // Compute the new data pointer and set it in the object.
6811 0 : masm.addPtr(offset, temp0);
6812 0 : masm.storePtr(temp0, Address(object, OutlineTypedObject::offsetOfData()));
6813 0 : }
6814 :
6815 : void
6816 8 : CodeGenerator::visitStringLength(LStringLength* lir)
6817 : {
6818 8 : Register input = ToRegister(lir->string());
6819 8 : Register output = ToRegister(lir->output());
6820 :
6821 8 : masm.loadStringLength(input, output);
6822 8 : }
6823 :
6824 : void
6825 5 : CodeGenerator::visitMinMaxI(LMinMaxI* ins)
6826 : {
6827 5 : Register first = ToRegister(ins->first());
6828 5 : Register output = ToRegister(ins->output());
6829 :
6830 5 : MOZ_ASSERT(first == output);
6831 :
6832 10 : Label done;
6833 5 : Assembler::Condition cond = ins->mir()->isMax()
6834 5 : ? Assembler::GreaterThan
6835 5 : : Assembler::LessThan;
6836 :
6837 5 : if (ins->second()->isConstant()) {
6838 5 : masm.branch32(cond, first, Imm32(ToInt32(ins->second())), &done);
6839 5 : masm.move32(Imm32(ToInt32(ins->second())), output);
6840 : } else {
6841 0 : masm.branch32(cond, first, ToRegister(ins->second()), &done);
6842 0 : masm.move32(ToRegister(ins->second()), output);
6843 : }
6844 :
6845 5 : masm.bind(&done);
6846 5 : }
6847 :
6848 : void
6849 0 : CodeGenerator::visitAbsI(LAbsI* ins)
6850 : {
6851 0 : Register input = ToRegister(ins->input());
6852 0 : Label positive;
6853 :
6854 0 : MOZ_ASSERT(input == ToRegister(ins->output()));
6855 0 : masm.branchTest32(Assembler::NotSigned, input, input, &positive);
6856 0 : masm.neg32(input);
6857 0 : LSnapshot* snapshot = ins->snapshot();
6858 : #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
6859 : if (snapshot)
6860 : bailoutCmp32(Assembler::Equal, input, Imm32(INT32_MIN), snapshot);
6861 : #else
6862 0 : if (snapshot)
6863 0 : bailoutIf(Assembler::Overflow, snapshot);
6864 : #endif
6865 0 : masm.bind(&positive);
6866 0 : }
6867 :
6868 : void
6869 0 : CodeGenerator::visitPowI(LPowI* ins)
6870 : {
6871 0 : FloatRegister value = ToFloatRegister(ins->value());
6872 0 : Register power = ToRegister(ins->power());
6873 0 : Register temp = ToRegister(ins->temp());
6874 :
6875 0 : MOZ_ASSERT(power != temp);
6876 :
6877 0 : masm.setupUnalignedABICall(temp);
6878 0 : masm.passABIArg(value, MoveOp::DOUBLE);
6879 0 : masm.passABIArg(power);
6880 :
6881 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::powi), MoveOp::DOUBLE);
6882 0 : MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
6883 0 : }
6884 :
6885 : void
6886 0 : CodeGenerator::visitPowD(LPowD* ins)
6887 : {
6888 0 : FloatRegister value = ToFloatRegister(ins->value());
6889 0 : FloatRegister power = ToFloatRegister(ins->power());
6890 0 : Register temp = ToRegister(ins->temp());
6891 :
6892 0 : masm.setupUnalignedABICall(temp);
6893 0 : masm.passABIArg(value, MoveOp::DOUBLE);
6894 0 : masm.passABIArg(power, MoveOp::DOUBLE);
6895 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaPow), MoveOp::DOUBLE);
6896 :
6897 0 : MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
6898 0 : }
6899 :
6900 : using PowFn = bool (*)(JSContext*, HandleValue, HandleValue, MutableHandleValue);
6901 3 : static const VMFunction PowInfo =
6902 6 : FunctionInfo<PowFn>(js::math_pow_handle, "math_pow_handle");
6903 :
6904 : void
6905 0 : CodeGenerator::visitPowV(LPowV* ins)
6906 : {
6907 0 : pushArg(ToValue(ins, LPowV::PowerInput));
6908 0 : pushArg(ToValue(ins, LPowV::ValueInput));
6909 0 : callVM(PowInfo, ins);
6910 0 : }
6911 :
6912 : void
6913 0 : CodeGenerator::visitMathFunctionD(LMathFunctionD* ins)
6914 : {
6915 0 : Register temp = ToRegister(ins->temp());
6916 0 : FloatRegister input = ToFloatRegister(ins->input());
6917 0 : MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
6918 :
6919 0 : masm.setupUnalignedABICall(temp);
6920 :
6921 0 : const MathCache* mathCache = ins->mir()->cache();
6922 0 : if (mathCache) {
6923 0 : masm.movePtr(ImmPtr(mathCache), temp);
6924 0 : masm.passABIArg(temp);
6925 : }
6926 0 : masm.passABIArg(input, MoveOp::DOUBLE);
6927 :
6928 : # define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
6929 :
6930 0 : void* funptr = nullptr;
6931 0 : switch (ins->mir()->function()) {
6932 : case MMathFunction::Log:
6933 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log));
6934 0 : break;
6935 : case MMathFunction::Sin:
6936 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sin));
6937 0 : break;
6938 : case MMathFunction::Cos:
6939 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cos));
6940 0 : break;
6941 : case MMathFunction::Exp:
6942 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_exp));
6943 0 : break;
6944 : case MMathFunction::Tan:
6945 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_tan));
6946 0 : break;
6947 : case MMathFunction::ATan:
6948 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_atan));
6949 0 : break;
6950 : case MMathFunction::ASin:
6951 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_asin));
6952 0 : break;
6953 : case MMathFunction::ACos:
6954 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_acos));
6955 0 : break;
6956 : case MMathFunction::Log10:
6957 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log10));
6958 0 : break;
6959 : case MMathFunction::Log2:
6960 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log2));
6961 0 : break;
6962 : case MMathFunction::Log1P:
6963 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log1p));
6964 0 : break;
6965 : case MMathFunction::ExpM1:
6966 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_expm1));
6967 0 : break;
6968 : case MMathFunction::CosH:
6969 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cosh));
6970 0 : break;
6971 : case MMathFunction::SinH:
6972 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sinh));
6973 0 : break;
6974 : case MMathFunction::TanH:
6975 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_tanh));
6976 0 : break;
6977 : case MMathFunction::ACosH:
6978 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_acosh));
6979 0 : break;
6980 : case MMathFunction::ASinH:
6981 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_asinh));
6982 0 : break;
6983 : case MMathFunction::ATanH:
6984 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_atanh));
6985 0 : break;
6986 : case MMathFunction::Sign:
6987 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sign));
6988 0 : break;
6989 : case MMathFunction::Trunc:
6990 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_trunc));
6991 0 : break;
6992 : case MMathFunction::Cbrt:
6993 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cbrt));
6994 0 : break;
6995 : case MMathFunction::Floor:
6996 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_floor_impl);
6997 0 : break;
6998 : case MMathFunction::Ceil:
6999 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_ceil_impl);
7000 0 : break;
7001 : case MMathFunction::Round:
7002 0 : funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_round_impl);
7003 0 : break;
7004 : default:
7005 0 : MOZ_CRASH("Unknown math function");
7006 : }
7007 :
7008 : # undef MAYBE_CACHED
7009 :
7010 0 : masm.callWithABI(funptr, MoveOp::DOUBLE);
7011 0 : }
7012 :
7013 : void
7014 0 : CodeGenerator::visitMathFunctionF(LMathFunctionF* ins)
7015 : {
7016 0 : Register temp = ToRegister(ins->temp());
7017 0 : FloatRegister input = ToFloatRegister(ins->input());
7018 0 : MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnFloat32Reg);
7019 :
7020 0 : masm.setupUnalignedABICall(temp);
7021 0 : masm.passABIArg(input, MoveOp::FLOAT32);
7022 :
7023 0 : void* funptr = nullptr;
7024 0 : switch (ins->mir()->function()) {
7025 0 : case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void*, floorf); break;
7026 0 : case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void*, math_roundf_impl); break;
7027 0 : case MMathFunction::Ceil: funptr = JS_FUNC_TO_DATA_PTR(void*, ceilf); break;
7028 : default:
7029 0 : MOZ_CRASH("Unknown or unsupported float32 math function");
7030 : }
7031 :
7032 0 : masm.callWithABI(funptr, MoveOp::FLOAT32);
7033 0 : }
7034 :
7035 : void
7036 0 : CodeGenerator::visitModD(LModD* ins)
7037 : {
7038 0 : FloatRegister lhs = ToFloatRegister(ins->lhs());
7039 0 : FloatRegister rhs = ToFloatRegister(ins->rhs());
7040 :
7041 0 : MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
7042 0 : MOZ_ASSERT(ins->temp()->isBogusTemp() == gen->compilingWasm());
7043 :
7044 0 : if (gen->compilingWasm()) {
7045 0 : masm.setupWasmABICall();
7046 0 : masm.passABIArg(lhs, MoveOp::DOUBLE);
7047 0 : masm.passABIArg(rhs, MoveOp::DOUBLE);
7048 0 : masm.callWithABI(ins->mir()->bytecodeOffset(), wasm::SymbolicAddress::ModD, MoveOp::DOUBLE);
7049 : } else {
7050 0 : masm.setupUnalignedABICall(ToRegister(ins->temp()));
7051 0 : masm.passABIArg(lhs, MoveOp::DOUBLE);
7052 0 : masm.passABIArg(rhs, MoveOp::DOUBLE);
7053 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NumberMod), MoveOp::DOUBLE);
7054 : }
7055 0 : }
7056 :
7057 : typedef bool (*BinaryFn)(JSContext*, MutableHandleValue, MutableHandleValue, MutableHandleValue);
7058 :
7059 3 : static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues, "AddValues");
7060 3 : static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues, "SubValues");
7061 3 : static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues, "MulValues");
7062 3 : static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues, "DivValues");
7063 3 : static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues, "ModValues");
7064 3 : static const VMFunction UrshInfo = FunctionInfo<BinaryFn>(js::UrshValues, "UrshValues");
7065 :
7066 : void
7067 0 : CodeGenerator::visitBinaryV(LBinaryV* lir)
7068 : {
7069 0 : pushArg(ToValue(lir, LBinaryV::RhsInput));
7070 0 : pushArg(ToValue(lir, LBinaryV::LhsInput));
7071 :
7072 0 : switch (lir->jsop()) {
7073 : case JSOP_ADD:
7074 0 : callVM(AddInfo, lir);
7075 0 : break;
7076 :
7077 : case JSOP_SUB:
7078 0 : callVM(SubInfo, lir);
7079 0 : break;
7080 :
7081 : case JSOP_MUL:
7082 0 : callVM(MulInfo, lir);
7083 0 : break;
7084 :
7085 : case JSOP_DIV:
7086 0 : callVM(DivInfo, lir);
7087 0 : break;
7088 :
7089 : case JSOP_MOD:
7090 0 : callVM(ModInfo, lir);
7091 0 : break;
7092 :
7093 : case JSOP_URSH:
7094 0 : callVM(UrshInfo, lir);
7095 0 : break;
7096 :
7097 : default:
7098 0 : MOZ_CRASH("Unexpected binary op");
7099 : }
7100 0 : }
7101 :
7102 : typedef bool (*StringCompareFn)(JSContext*, HandleString, HandleString, bool*);
7103 3 : static const VMFunction StringsEqualInfo =
7104 6 : FunctionInfo<StringCompareFn>(jit::StringsEqual<true>, "StringsEqual");
7105 3 : static const VMFunction StringsNotEqualInfo =
7106 6 : FunctionInfo<StringCompareFn>(jit::StringsEqual<false>, "StringsEqual");
7107 :
7108 : void
7109 0 : CodeGenerator::emitCompareS(LInstruction* lir, JSOp op, Register left, Register right,
7110 : Register output)
7111 : {
7112 0 : MOZ_ASSERT(lir->isCompareS() || lir->isCompareStrictS());
7113 :
7114 0 : OutOfLineCode* ool = nullptr;
7115 :
7116 0 : if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
7117 0 : ool = oolCallVM(StringsEqualInfo, lir, ArgList(left, right), StoreRegisterTo(output));
7118 : } else {
7119 0 : MOZ_ASSERT(op == JSOP_NE || op == JSOP_STRICTNE);
7120 0 : ool = oolCallVM(StringsNotEqualInfo, lir, ArgList(left, right), StoreRegisterTo(output));
7121 : }
7122 :
7123 0 : masm.compareStrings(op, left, right, output, ool->entry());
7124 :
7125 0 : masm.bind(ool->rejoin());
7126 0 : }
7127 :
7128 : void
7129 0 : CodeGenerator::visitCompareStrictS(LCompareStrictS* lir)
7130 : {
7131 0 : JSOp op = lir->mir()->jsop();
7132 0 : MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
7133 :
7134 0 : const ValueOperand leftV = ToValue(lir, LCompareStrictS::Lhs);
7135 0 : Register right = ToRegister(lir->right());
7136 0 : Register output = ToRegister(lir->output());
7137 0 : Register tempToUnbox = ToTempUnboxRegister(lir->tempToUnbox());
7138 :
7139 0 : Label string, done;
7140 :
7141 0 : masm.branchTestString(Assembler::Equal, leftV, &string);
7142 0 : masm.move32(Imm32(op == JSOP_STRICTNE), output);
7143 0 : masm.jump(&done);
7144 :
7145 0 : masm.bind(&string);
7146 0 : Register left = masm.extractString(leftV, tempToUnbox);
7147 0 : emitCompareS(lir, op, left, right, output);
7148 :
7149 0 : masm.bind(&done);
7150 0 : }
7151 :
7152 : void
7153 0 : CodeGenerator::visitCompareS(LCompareS* lir)
7154 : {
7155 0 : JSOp op = lir->mir()->jsop();
7156 0 : Register left = ToRegister(lir->left());
7157 0 : Register right = ToRegister(lir->right());
7158 0 : Register output = ToRegister(lir->output());
7159 :
7160 0 : emitCompareS(lir, op, left, right, output);
7161 0 : }
7162 :
7163 : typedef bool (*CompareFn)(JSContext*, MutableHandleValue, MutableHandleValue, bool*);
7164 3 : static const VMFunction EqInfo =
7165 6 : FunctionInfo<CompareFn>(jit::LooselyEqual<true>, "LooselyEqual");
7166 3 : static const VMFunction NeInfo =
7167 6 : FunctionInfo<CompareFn>(jit::LooselyEqual<false>, "LooselyEqual");
7168 3 : static const VMFunction StrictEqInfo =
7169 6 : FunctionInfo<CompareFn>(jit::StrictlyEqual<true>, "StrictlyEqual");
7170 3 : static const VMFunction StrictNeInfo =
7171 6 : FunctionInfo<CompareFn>(jit::StrictlyEqual<false>, "StrictlyEqual");
7172 3 : static const VMFunction LtInfo =
7173 6 : FunctionInfo<CompareFn>(jit::LessThan, "LessThan");
7174 3 : static const VMFunction LeInfo =
7175 6 : FunctionInfo<CompareFn>(jit::LessThanOrEqual, "LessThanOrEqual");
7176 3 : static const VMFunction GtInfo =
7177 6 : FunctionInfo<CompareFn>(jit::GreaterThan, "GreaterThan");
7178 3 : static const VMFunction GeInfo =
7179 6 : FunctionInfo<CompareFn>(jit::GreaterThanOrEqual, "GreaterThanOrEqual");
7180 :
7181 : void
7182 0 : CodeGenerator::visitCompareVM(LCompareVM* lir)
7183 : {
7184 0 : pushArg(ToValue(lir, LBinaryV::RhsInput));
7185 0 : pushArg(ToValue(lir, LBinaryV::LhsInput));
7186 :
7187 0 : switch (lir->mir()->jsop()) {
7188 : case JSOP_EQ:
7189 0 : callVM(EqInfo, lir);
7190 0 : break;
7191 :
7192 : case JSOP_NE:
7193 0 : callVM(NeInfo, lir);
7194 0 : break;
7195 :
7196 : case JSOP_STRICTEQ:
7197 0 : callVM(StrictEqInfo, lir);
7198 0 : break;
7199 :
7200 : case JSOP_STRICTNE:
7201 0 : callVM(StrictNeInfo, lir);
7202 0 : break;
7203 :
7204 : case JSOP_LT:
7205 0 : callVM(LtInfo, lir);
7206 0 : break;
7207 :
7208 : case JSOP_LE:
7209 0 : callVM(LeInfo, lir);
7210 0 : break;
7211 :
7212 : case JSOP_GT:
7213 0 : callVM(GtInfo, lir);
7214 0 : break;
7215 :
7216 : case JSOP_GE:
7217 0 : callVM(GeInfo, lir);
7218 0 : break;
7219 :
7220 : default:
7221 0 : MOZ_CRASH("Unexpected compare op");
7222 : }
7223 0 : }
7224 :
7225 : void
7226 0 : CodeGenerator::visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir)
7227 : {
7228 0 : JSOp op = lir->mir()->jsop();
7229 0 : MCompare::CompareType compareType = lir->mir()->compareType();
7230 0 : MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
7231 : compareType == MCompare::Compare_Null);
7232 :
7233 0 : const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedV::Value);
7234 0 : Register output = ToRegister(lir->output());
7235 :
7236 0 : if (op == JSOP_EQ || op == JSOP_NE) {
7237 0 : MOZ_ASSERT(lir->mir()->lhs()->type() != MIRType::Object ||
7238 : lir->mir()->operandMightEmulateUndefined(),
7239 : "Operands which can't emulate undefined should have been folded");
7240 :
7241 0 : OutOfLineTestObjectWithLabels* ool = nullptr;
7242 0 : Maybe<Label> label1, label2;
7243 : Label* nullOrLikeUndefined;
7244 : Label* notNullOrLikeUndefined;
7245 0 : if (lir->mir()->operandMightEmulateUndefined()) {
7246 0 : ool = new(alloc()) OutOfLineTestObjectWithLabels();
7247 0 : addOutOfLineCode(ool, lir->mir());
7248 0 : nullOrLikeUndefined = ool->label1();
7249 0 : notNullOrLikeUndefined = ool->label2();
7250 : } else {
7251 0 : label1.emplace();
7252 0 : label2.emplace();
7253 0 : nullOrLikeUndefined = label1.ptr();
7254 0 : notNullOrLikeUndefined = label2.ptr();
7255 : }
7256 :
7257 0 : Register tag = masm.splitTagForTest(value);
7258 0 : MDefinition* input = lir->mir()->lhs();
7259 0 : if (input->mightBeType(MIRType::Null))
7260 0 : masm.branchTestNull(Assembler::Equal, tag, nullOrLikeUndefined);
7261 0 : if (input->mightBeType(MIRType::Undefined))
7262 0 : masm.branchTestUndefined(Assembler::Equal, tag, nullOrLikeUndefined);
7263 :
7264 0 : if (ool) {
7265 : // Check whether it's a truthy object or a falsy object that emulates
7266 : // undefined.
7267 0 : masm.branchTestObject(Assembler::NotEqual, tag, notNullOrLikeUndefined);
7268 :
7269 0 : Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
7270 0 : branchTestObjectEmulatesUndefined(objreg, nullOrLikeUndefined, notNullOrLikeUndefined,
7271 0 : ToRegister(lir->temp()), ool);
7272 : // fall through
7273 : }
7274 :
7275 0 : Label done;
7276 :
7277 : // It's not null or undefined, and if it's an object it doesn't
7278 : // emulate undefined, so it's not like undefined.
7279 0 : masm.move32(Imm32(op == JSOP_NE), output);
7280 0 : masm.jump(&done);
7281 :
7282 0 : masm.bind(nullOrLikeUndefined);
7283 0 : masm.move32(Imm32(op == JSOP_EQ), output);
7284 :
7285 : // Both branches meet here.
7286 0 : masm.bind(&done);
7287 0 : return;
7288 : }
7289 :
7290 0 : MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
7291 :
7292 0 : Assembler::Condition cond = JSOpToCondition(compareType, op);
7293 0 : if (compareType == MCompare::Compare_Null)
7294 0 : masm.testNullSet(cond, value, output);
7295 : else
7296 0 : masm.testUndefinedSet(cond, value, output);
7297 : }
7298 :
7299 : void
7300 0 : CodeGenerator::visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV* lir)
7301 : {
7302 0 : JSOp op = lir->cmpMir()->jsop();
7303 0 : MCompare::CompareType compareType = lir->cmpMir()->compareType();
7304 0 : MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
7305 : compareType == MCompare::Compare_Null);
7306 :
7307 0 : const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranchV::Value);
7308 :
7309 0 : if (op == JSOP_EQ || op == JSOP_NE) {
7310 : MBasicBlock* ifTrue;
7311 : MBasicBlock* ifFalse;
7312 :
7313 0 : if (op == JSOP_EQ) {
7314 0 : ifTrue = lir->ifTrue();
7315 0 : ifFalse = lir->ifFalse();
7316 : } else {
7317 : // Swap branches.
7318 0 : ifTrue = lir->ifFalse();
7319 0 : ifFalse = lir->ifTrue();
7320 0 : op = JSOP_EQ;
7321 : }
7322 :
7323 0 : MOZ_ASSERT(lir->cmpMir()->lhs()->type() != MIRType::Object ||
7324 : lir->cmpMir()->operandMightEmulateUndefined(),
7325 : "Operands which can't emulate undefined should have been folded");
7326 :
7327 0 : OutOfLineTestObject* ool = nullptr;
7328 0 : if (lir->cmpMir()->operandMightEmulateUndefined()) {
7329 0 : ool = new(alloc()) OutOfLineTestObject();
7330 0 : addOutOfLineCode(ool, lir->cmpMir());
7331 : }
7332 :
7333 0 : Register tag = masm.splitTagForTest(value);
7334 :
7335 0 : Label* ifTrueLabel = getJumpLabelForBranch(ifTrue);
7336 0 : Label* ifFalseLabel = getJumpLabelForBranch(ifFalse);
7337 :
7338 0 : MDefinition* input = lir->cmpMir()->lhs();
7339 0 : if (input->mightBeType(MIRType::Null))
7340 0 : masm.branchTestNull(Assembler::Equal, tag, ifTrueLabel);
7341 0 : if (input->mightBeType(MIRType::Undefined))
7342 0 : masm.branchTestUndefined(Assembler::Equal, tag, ifTrueLabel);
7343 :
7344 0 : if (ool) {
7345 0 : masm.branchTestObject(Assembler::NotEqual, tag, ifFalseLabel);
7346 :
7347 : // Objects that emulate undefined are loosely equal to null/undefined.
7348 0 : Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
7349 0 : Register scratch = ToRegister(lir->temp());
7350 0 : testObjectEmulatesUndefined(objreg, ifTrueLabel, ifFalseLabel, scratch, ool);
7351 : } else {
7352 0 : masm.jump(ifFalseLabel);
7353 : }
7354 0 : return;
7355 : }
7356 :
7357 0 : MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
7358 :
7359 0 : Assembler::Condition cond = JSOpToCondition(compareType, op);
7360 0 : if (compareType == MCompare::Compare_Null)
7361 0 : testNullEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
7362 : else
7363 0 : testUndefinedEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
7364 : }
7365 :
7366 : void
7367 0 : CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir)
7368 : {
7369 0 : MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined ||
7370 : lir->mir()->compareType() == MCompare::Compare_Null);
7371 :
7372 0 : MIRType lhsType = lir->mir()->lhs()->type();
7373 0 : MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull);
7374 :
7375 0 : JSOp op = lir->mir()->jsop();
7376 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
7377 : "Strict equality should have been folded");
7378 :
7379 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
7380 : "If the object couldn't emulate undefined, this should have been folded.");
7381 :
7382 0 : Register objreg = ToRegister(lir->input());
7383 0 : Register output = ToRegister(lir->output());
7384 :
7385 0 : if ((op == JSOP_EQ || op == JSOP_NE) && lir->mir()->operandMightEmulateUndefined()) {
7386 0 : OutOfLineTestObjectWithLabels* ool = new(alloc()) OutOfLineTestObjectWithLabels();
7387 0 : addOutOfLineCode(ool, lir->mir());
7388 :
7389 0 : Label* emulatesUndefined = ool->label1();
7390 0 : Label* doesntEmulateUndefined = ool->label2();
7391 :
7392 0 : if (lhsType == MIRType::ObjectOrNull)
7393 0 : masm.branchTestPtr(Assembler::Zero, objreg, objreg, emulatesUndefined);
7394 :
7395 : branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined,
7396 0 : output, ool);
7397 :
7398 0 : Label done;
7399 :
7400 0 : masm.move32(Imm32(op == JSOP_NE), output);
7401 0 : masm.jump(&done);
7402 :
7403 0 : masm.bind(emulatesUndefined);
7404 0 : masm.move32(Imm32(op == JSOP_EQ), output);
7405 0 : masm.bind(&done);
7406 : } else {
7407 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull);
7408 :
7409 0 : Label isNull, done;
7410 :
7411 0 : masm.branchTestPtr(Assembler::Zero, objreg, objreg, &isNull);
7412 :
7413 0 : masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output);
7414 0 : masm.jump(&done);
7415 :
7416 0 : masm.bind(&isNull);
7417 0 : masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output);
7418 :
7419 0 : masm.bind(&done);
7420 : }
7421 0 : }
7422 :
7423 : void
7424 0 : CodeGenerator::visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT* lir)
7425 : {
7426 0 : DebugOnly<MCompare::CompareType> compareType = lir->cmpMir()->compareType();
7427 0 : MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
7428 : compareType == MCompare::Compare_Null);
7429 :
7430 0 : MIRType lhsType = lir->cmpMir()->lhs()->type();
7431 0 : MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull);
7432 :
7433 0 : JSOp op = lir->cmpMir()->jsop();
7434 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
7435 : "Strict equality should have been folded");
7436 :
7437 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->cmpMir()->operandMightEmulateUndefined(),
7438 : "If the object couldn't emulate undefined, this should have been folded.");
7439 :
7440 : MBasicBlock* ifTrue;
7441 : MBasicBlock* ifFalse;
7442 :
7443 0 : if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
7444 0 : ifTrue = lir->ifTrue();
7445 0 : ifFalse = lir->ifFalse();
7446 : } else {
7447 : // Swap branches.
7448 0 : ifTrue = lir->ifFalse();
7449 0 : ifFalse = lir->ifTrue();
7450 : }
7451 :
7452 0 : Register input = ToRegister(lir->getOperand(0));
7453 :
7454 0 : if ((op == JSOP_EQ || op == JSOP_NE) && lir->cmpMir()->operandMightEmulateUndefined()) {
7455 0 : OutOfLineTestObject* ool = new(alloc()) OutOfLineTestObject();
7456 0 : addOutOfLineCode(ool, lir->cmpMir());
7457 :
7458 0 : Label* ifTrueLabel = getJumpLabelForBranch(ifTrue);
7459 0 : Label* ifFalseLabel = getJumpLabelForBranch(ifFalse);
7460 :
7461 0 : if (lhsType == MIRType::ObjectOrNull)
7462 0 : masm.branchTestPtr(Assembler::Zero, input, input, ifTrueLabel);
7463 :
7464 : // Objects that emulate undefined are loosely equal to null/undefined.
7465 0 : Register scratch = ToRegister(lir->temp());
7466 0 : testObjectEmulatesUndefined(input, ifTrueLabel, ifFalseLabel, scratch, ool);
7467 : } else {
7468 0 : MOZ_ASSERT(lhsType == MIRType::ObjectOrNull);
7469 0 : testZeroEmitBranch(Assembler::Equal, input, ifTrue, ifFalse);
7470 : }
7471 0 : }
7472 :
7473 : typedef JSString* (*ConcatStringsFn)(JSContext*, HandleString, HandleString);
7474 3 : static const VMFunction ConcatStringsInfo =
7475 6 : FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>, "ConcatStrings");
7476 :
7477 : void
7478 12 : CodeGenerator::emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output)
7479 : {
7480 24 : OutOfLineCode* ool = oolCallVM(ConcatStringsInfo, lir, ArgList(lhs, rhs),
7481 36 : StoreRegisterTo(output));
7482 :
7483 12 : JitCode* stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier();
7484 12 : masm.call(stringConcatStub);
7485 12 : masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
7486 :
7487 12 : masm.bind(ool->rejoin());
7488 12 : }
7489 :
7490 : void
7491 12 : CodeGenerator::visitConcat(LConcat* lir)
7492 : {
7493 12 : Register lhs = ToRegister(lir->lhs());
7494 12 : Register rhs = ToRegister(lir->rhs());
7495 :
7496 12 : Register output = ToRegister(lir->output());
7497 :
7498 12 : MOZ_ASSERT(lhs == CallTempReg0);
7499 12 : MOZ_ASSERT(rhs == CallTempReg1);
7500 12 : MOZ_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
7501 12 : MOZ_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
7502 12 : MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
7503 12 : MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
7504 12 : MOZ_ASSERT(ToRegister(lir->temp5()) == CallTempReg4);
7505 12 : MOZ_ASSERT(output == CallTempReg5);
7506 :
7507 12 : emitConcat(lir, lhs, rhs, output);
7508 12 : }
7509 :
7510 : static void
7511 24 : CopyStringChars(MacroAssembler& masm, Register to, Register from, Register len,
7512 : Register byteOpScratch, size_t fromWidth, size_t toWidth)
7513 : {
7514 : // Copy |len| char16_t code units from |from| to |to|. Assumes len > 0
7515 : // (checked below in debug builds), and when done |to| must point to the
7516 : // next available char.
7517 :
7518 : #ifdef DEBUG
7519 48 : Label ok;
7520 24 : masm.branch32(Assembler::GreaterThan, len, Imm32(0), &ok);
7521 24 : masm.assumeUnreachable("Length should be greater than 0.");
7522 24 : masm.bind(&ok);
7523 : #endif
7524 :
7525 24 : MOZ_ASSERT(fromWidth == 1 || fromWidth == 2);
7526 24 : MOZ_ASSERT(toWidth == 1 || toWidth == 2);
7527 24 : MOZ_ASSERT_IF(toWidth == 1, fromWidth == 1);
7528 :
7529 48 : Label start;
7530 24 : masm.bind(&start);
7531 24 : if (fromWidth == 2)
7532 8 : masm.load16ZeroExtend(Address(from, 0), byteOpScratch);
7533 : else
7534 16 : masm.load8ZeroExtend(Address(from, 0), byteOpScratch);
7535 24 : if (toWidth == 2)
7536 16 : masm.store16(byteOpScratch, Address(to, 0));
7537 : else
7538 8 : masm.store8(byteOpScratch, Address(to, 0));
7539 24 : masm.addPtr(Imm32(fromWidth), from);
7540 24 : masm.addPtr(Imm32(toWidth), to);
7541 24 : masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start);
7542 24 : }
7543 :
7544 : static void
7545 8 : CopyStringCharsMaybeInflate(MacroAssembler& masm, Register input, Register destChars,
7546 : Register temp1, Register temp2)
7547 : {
7548 : // destChars is TwoByte and input is a Latin1 or TwoByte string, so we may
7549 : // have to inflate.
7550 :
7551 16 : Label isLatin1, done;
7552 8 : masm.loadStringLength(input, temp1);
7553 8 : masm.branchLatin1String(input, &isLatin1);
7554 : {
7555 8 : masm.loadStringChars(input, input);
7556 8 : CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char16_t), sizeof(char16_t));
7557 8 : masm.jump(&done);
7558 : }
7559 8 : masm.bind(&isLatin1);
7560 : {
7561 8 : masm.loadStringChars(input, input);
7562 8 : CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char), sizeof(char16_t));
7563 : }
7564 8 : masm.bind(&done);
7565 8 : }
7566 :
7567 : static void
7568 8 : ConcatInlineString(MacroAssembler& masm, Register lhs, Register rhs, Register output,
7569 : Register temp1, Register temp2, Register temp3,
7570 : Label* failure, Label* failurePopTemps, bool isTwoByte)
7571 : {
7572 : // State: result length in temp2.
7573 :
7574 : // Ensure both strings are linear.
7575 8 : masm.branchIfRope(lhs, failure);
7576 8 : masm.branchIfRope(rhs, failure);
7577 :
7578 : // Allocate a JSThinInlineString or JSFatInlineString.
7579 : size_t maxThinInlineLength;
7580 8 : if (isTwoByte)
7581 4 : maxThinInlineLength = JSThinInlineString::MAX_LENGTH_TWO_BYTE;
7582 : else
7583 4 : maxThinInlineLength = JSThinInlineString::MAX_LENGTH_LATIN1;
7584 :
7585 16 : Label isFat, allocDone;
7586 8 : masm.branch32(Assembler::Above, temp2, Imm32(maxThinInlineLength), &isFat);
7587 : {
7588 8 : uint32_t flags = JSString::INIT_THIN_INLINE_FLAGS;
7589 8 : if (!isTwoByte)
7590 4 : flags |= JSString::LATIN1_CHARS_BIT;
7591 8 : masm.newGCString(output, temp1, failure);
7592 8 : masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
7593 8 : masm.jump(&allocDone);
7594 : }
7595 8 : masm.bind(&isFat);
7596 : {
7597 8 : uint32_t flags = JSString::INIT_FAT_INLINE_FLAGS;
7598 8 : if (!isTwoByte)
7599 4 : flags |= JSString::LATIN1_CHARS_BIT;
7600 8 : masm.newGCFatInlineString(output, temp1, failure);
7601 8 : masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
7602 : }
7603 8 : masm.bind(&allocDone);
7604 :
7605 : // Store length.
7606 8 : masm.store32(temp2, Address(output, JSString::offsetOfLength()));
7607 :
7608 : // Load chars pointer in temp2.
7609 8 : masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
7610 :
7611 : {
7612 : // Copy lhs chars. Note that this advances temp2 to point to the next
7613 : // char. This also clobbers the lhs register.
7614 8 : if (isTwoByte) {
7615 4 : CopyStringCharsMaybeInflate(masm, lhs, temp2, temp1, temp3);
7616 : } else {
7617 4 : masm.loadStringLength(lhs, temp3);
7618 4 : masm.loadStringChars(lhs, lhs);
7619 4 : CopyStringChars(masm, temp2, lhs, temp3, temp1, sizeof(char), sizeof(char));
7620 : }
7621 :
7622 : // Copy rhs chars. Clobbers the rhs register.
7623 8 : if (isTwoByte) {
7624 4 : CopyStringCharsMaybeInflate(masm, rhs, temp2, temp1, temp3);
7625 : } else {
7626 4 : masm.loadStringLength(rhs, temp3);
7627 4 : masm.loadStringChars(rhs, rhs);
7628 4 : CopyStringChars(masm, temp2, rhs, temp3, temp1, sizeof(char), sizeof(char));
7629 : }
7630 :
7631 : // Null-terminate.
7632 8 : if (isTwoByte)
7633 4 : masm.store16(Imm32(0), Address(temp2, 0));
7634 : else
7635 4 : masm.store8(Imm32(0), Address(temp2, 0));
7636 : }
7637 :
7638 8 : masm.ret();
7639 8 : }
7640 :
7641 : typedef JSString* (*SubstringKernelFn)(JSContext* cx, HandleString str, int32_t begin, int32_t len);
7642 3 : static const VMFunction SubstringKernelInfo =
7643 6 : FunctionInfo<SubstringKernelFn>(SubstringKernel, "SubstringKernel");
7644 :
7645 : void
7646 0 : CodeGenerator::visitSubstr(LSubstr* lir)
7647 : {
7648 0 : Register string = ToRegister(lir->string());
7649 0 : Register begin = ToRegister(lir->begin());
7650 0 : Register length = ToRegister(lir->length());
7651 0 : Register output = ToRegister(lir->output());
7652 0 : Register temp = ToRegister(lir->temp());
7653 0 : Register temp3 = ToRegister(lir->temp3());
7654 :
7655 : // On x86 there are not enough registers. In that case reuse the string
7656 : // register as temporary.
7657 0 : Register temp2 = lir->temp2()->isBogusTemp() ? string : ToRegister(lir->temp2());
7658 :
7659 0 : Address stringFlags(string, JSString::offsetOfFlags());
7660 :
7661 0 : Label isLatin1, notInline, nonZero, isInlinedLatin1;
7662 :
7663 : // For every edge case use the C++ variant.
7664 : // Note: we also use this upon allocation failure in newGCString and
7665 : // newGCFatInlineString. To squeeze out even more performance those failures
7666 : // can be handled by allocate in ool code and returning to jit code to fill
7667 : // in all data.
7668 0 : OutOfLineCode* ool = oolCallVM(SubstringKernelInfo, lir,
7669 0 : ArgList(string, begin, length),
7670 0 : StoreRegisterTo(output));
7671 0 : Label* slowPath = ool->entry();
7672 0 : Label* done = ool->rejoin();
7673 :
7674 : // Zero length, return emptystring.
7675 0 : masm.branchTest32(Assembler::NonZero, length, length, &nonZero);
7676 0 : const JSAtomState& names = GetJitContext()->runtime->names();
7677 0 : masm.movePtr(ImmGCPtr(names.empty), output);
7678 0 : masm.jump(done);
7679 :
7680 : // Use slow path for ropes.
7681 0 : masm.bind(&nonZero);
7682 0 : masm.branchIfRopeOrExternal(string, temp, slowPath);
7683 :
7684 : // Handle inlined strings by creating a FatInlineString.
7685 0 : masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::INLINE_CHARS_BIT), ¬Inline);
7686 0 : masm.newGCFatInlineString(output, temp, slowPath);
7687 0 : masm.store32(length, Address(output, JSString::offsetOfLength()));
7688 0 : Address stringStorage(string, JSInlineString::offsetOfInlineStorage());
7689 0 : Address outputStorage(output, JSInlineString::offsetOfInlineStorage());
7690 :
7691 0 : masm.branchLatin1String(string, &isInlinedLatin1);
7692 : {
7693 0 : masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS),
7694 0 : Address(output, JSString::offsetOfFlags()));
7695 0 : masm.computeEffectiveAddress(stringStorage, temp);
7696 0 : if (temp2 == string)
7697 0 : masm.push(string);
7698 0 : BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
7699 0 : masm.computeEffectiveAddress(chars, temp2);
7700 0 : masm.computeEffectiveAddress(outputStorage, temp);
7701 0 : CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char16_t), sizeof(char16_t));
7702 0 : masm.load32(Address(output, JSString::offsetOfLength()), length);
7703 0 : masm.store16(Imm32(0), Address(temp, 0));
7704 0 : if (temp2 == string)
7705 0 : masm.pop(string);
7706 0 : masm.jump(done);
7707 : }
7708 0 : masm.bind(&isInlinedLatin1);
7709 : {
7710 0 : masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS | JSString::LATIN1_CHARS_BIT),
7711 0 : Address(output, JSString::offsetOfFlags()));
7712 0 : if (temp2 == string)
7713 0 : masm.push(string);
7714 0 : masm.computeEffectiveAddress(stringStorage, temp2);
7715 : static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
7716 0 : masm.addPtr(begin, temp2);
7717 0 : masm.computeEffectiveAddress(outputStorage, temp);
7718 0 : CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char), sizeof(char));
7719 0 : masm.load32(Address(output, JSString::offsetOfLength()), length);
7720 0 : masm.store8(Imm32(0), Address(temp, 0));
7721 0 : if (temp2 == string)
7722 0 : masm.pop(string);
7723 0 : masm.jump(done);
7724 : }
7725 :
7726 : // Handle other cases with a DependentString.
7727 0 : masm.bind(¬Inline);
7728 0 : masm.newGCString(output, temp, slowPath);
7729 0 : masm.store32(length, Address(output, JSString::offsetOfLength()));
7730 0 : masm.storePtr(string, Address(output, JSDependentString::offsetOfBase()));
7731 :
7732 0 : masm.branchLatin1String(string, &isLatin1);
7733 : {
7734 0 : masm.store32(Imm32(JSString::DEPENDENT_FLAGS), Address(output, JSString::offsetOfFlags()));
7735 0 : masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
7736 0 : BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
7737 0 : masm.computeEffectiveAddress(chars, temp);
7738 0 : masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
7739 0 : masm.jump(done);
7740 : }
7741 0 : masm.bind(&isLatin1);
7742 : {
7743 0 : masm.store32(Imm32(JSString::DEPENDENT_FLAGS | JSString::LATIN1_CHARS_BIT),
7744 0 : Address(output, JSString::offsetOfFlags()));
7745 0 : masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
7746 : static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
7747 0 : masm.addPtr(begin, temp);
7748 0 : masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
7749 0 : masm.jump(done);
7750 : }
7751 :
7752 0 : masm.bind(done);
7753 0 : }
7754 :
7755 : JitCode*
7756 4 : JitCompartment::generateStringConcatStub(JSContext* cx)
7757 : {
7758 8 : MacroAssembler masm(cx);
7759 :
7760 4 : Register lhs = CallTempReg0;
7761 4 : Register rhs = CallTempReg1;
7762 4 : Register temp1 = CallTempReg2;
7763 4 : Register temp2 = CallTempReg3;
7764 4 : Register temp3 = CallTempReg4;
7765 4 : Register output = CallTempReg5;
7766 :
7767 8 : Label failure, failurePopTemps;
7768 : #ifdef JS_USE_LINK_REGISTER
7769 : masm.pushReturnAddress();
7770 : #endif
7771 : // If lhs is empty, return rhs.
7772 8 : Label leftEmpty;
7773 4 : masm.loadStringLength(lhs, temp1);
7774 4 : masm.branchTest32(Assembler::Zero, temp1, temp1, &leftEmpty);
7775 :
7776 : // If rhs is empty, return lhs.
7777 8 : Label rightEmpty;
7778 4 : masm.loadStringLength(rhs, temp2);
7779 4 : masm.branchTest32(Assembler::Zero, temp2, temp2, &rightEmpty);
7780 :
7781 4 : masm.add32(temp1, temp2);
7782 :
7783 : // Check if we can use a JSFatInlineString. The result is a Latin1 string if
7784 : // lhs and rhs are both Latin1, so we AND the flags.
7785 8 : Label isFatInlineTwoByte, isFatInlineLatin1;
7786 4 : masm.load32(Address(lhs, JSString::offsetOfFlags()), temp1);
7787 4 : masm.and32(Address(rhs, JSString::offsetOfFlags()), temp1);
7788 :
7789 8 : Label isLatin1, notInline;
7790 4 : masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
7791 : {
7792 8 : masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_TWO_BYTE),
7793 4 : &isFatInlineTwoByte);
7794 4 : masm.jump(¬Inline);
7795 : }
7796 4 : masm.bind(&isLatin1);
7797 : {
7798 8 : masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_LATIN1),
7799 4 : &isFatInlineLatin1);
7800 : }
7801 4 : masm.bind(¬Inline);
7802 :
7803 : // Keep AND'ed flags in temp1.
7804 :
7805 : // Ensure result length <= JSString::MAX_LENGTH.
7806 4 : masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
7807 :
7808 : // Allocate a new rope.
7809 4 : masm.newGCString(output, temp3, &failure);
7810 :
7811 : // Store rope length and flags. temp1 still holds the result of AND'ing the
7812 : // lhs and rhs flags, so we just have to clear the other flags to get our
7813 : // rope flags (Latin1 if both lhs and rhs are Latin1).
7814 : static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
7815 4 : masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
7816 4 : masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
7817 4 : masm.store32(temp2, Address(output, JSString::offsetOfLength()));
7818 :
7819 : // Store left and right nodes.
7820 4 : masm.storePtr(lhs, Address(output, JSRope::offsetOfLeft()));
7821 4 : masm.storePtr(rhs, Address(output, JSRope::offsetOfRight()));
7822 4 : masm.ret();
7823 :
7824 4 : masm.bind(&leftEmpty);
7825 4 : masm.mov(rhs, output);
7826 4 : masm.ret();
7827 :
7828 4 : masm.bind(&rightEmpty);
7829 4 : masm.mov(lhs, output);
7830 4 : masm.ret();
7831 :
7832 4 : masm.bind(&isFatInlineTwoByte);
7833 : ConcatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
7834 4 : &failure, &failurePopTemps, true);
7835 :
7836 4 : masm.bind(&isFatInlineLatin1);
7837 : ConcatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
7838 4 : &failure, &failurePopTemps, false);
7839 :
7840 4 : masm.bind(&failurePopTemps);
7841 4 : masm.pop(temp2);
7842 4 : masm.pop(temp1);
7843 :
7844 4 : masm.bind(&failure);
7845 4 : masm.movePtr(ImmPtr(nullptr), output);
7846 4 : masm.ret();
7847 :
7848 8 : Linker linker(masm);
7849 8 : AutoFlushICache afc("StringConcatStub");
7850 4 : JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
7851 :
7852 : #ifdef JS_ION_PERF
7853 : writePerfSpewerJitCodeProfile(code, "StringConcatStub");
7854 : #endif
7855 : #ifdef MOZ_VTUNE
7856 4 : vtune::MarkStub(code, "StringConcatStub");
7857 : #endif
7858 :
7859 8 : return code;
7860 : }
7861 :
7862 : JitCode*
7863 4 : JitRuntime::generateMallocStub(JSContext* cx)
7864 : {
7865 4 : const Register regReturn = CallTempReg0;
7866 4 : const Register regNBytes = CallTempReg0;
7867 :
7868 8 : MacroAssembler masm(cx);
7869 :
7870 4 : AllocatableRegisterSet regs(RegisterSet::Volatile());
7871 : #ifdef JS_USE_LINK_REGISTER
7872 : masm.pushReturnAddress();
7873 : #endif
7874 4 : regs.takeUnchecked(regNBytes);
7875 4 : LiveRegisterSet save(regs.asLiveSet());
7876 4 : masm.PushRegsInMask(save);
7877 :
7878 4 : const Register regTemp = regs.takeAnyGeneral();
7879 4 : const Register regRuntime = regTemp;
7880 4 : MOZ_ASSERT(regTemp != regNBytes);
7881 :
7882 4 : masm.setupUnalignedABICall(regTemp);
7883 4 : masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
7884 4 : masm.passABIArg(regRuntime);
7885 4 : masm.passABIArg(regNBytes);
7886 4 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
7887 4 : masm.storeCallWordResult(regReturn);
7888 :
7889 4 : masm.PopRegsInMask(save);
7890 4 : masm.ret();
7891 :
7892 8 : Linker linker(masm);
7893 8 : AutoFlushICache afc("MallocStub");
7894 4 : JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
7895 :
7896 : #ifdef JS_ION_PERF
7897 : writePerfSpewerJitCodeProfile(code, "MallocStub");
7898 : #endif
7899 : #ifdef MOZ_VTUNE
7900 4 : vtune::MarkStub(code, "MallocStub");
7901 : #endif
7902 :
7903 8 : return code;
7904 : }
7905 :
7906 : JitCode*
7907 4 : JitRuntime::generateFreeStub(JSContext* cx)
7908 : {
7909 4 : const Register regSlots = CallTempReg0;
7910 :
7911 8 : MacroAssembler masm(cx);
7912 : #ifdef JS_USE_LINK_REGISTER
7913 : masm.pushReturnAddress();
7914 : #endif
7915 4 : AllocatableRegisterSet regs(RegisterSet::Volatile());
7916 4 : regs.takeUnchecked(regSlots);
7917 4 : LiveRegisterSet save(regs.asLiveSet());
7918 4 : masm.PushRegsInMask(save);
7919 :
7920 4 : const Register regTemp = regs.takeAnyGeneral();
7921 4 : MOZ_ASSERT(regTemp != regSlots);
7922 :
7923 4 : masm.setupUnalignedABICall(regTemp);
7924 4 : masm.passABIArg(regSlots);
7925 4 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js_free));
7926 :
7927 4 : masm.PopRegsInMask(save);
7928 :
7929 4 : masm.ret();
7930 :
7931 8 : Linker linker(masm);
7932 8 : AutoFlushICache afc("FreeStub");
7933 4 : JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
7934 :
7935 : #ifdef JS_ION_PERF
7936 : writePerfSpewerJitCodeProfile(code, "FreeStub");
7937 : #endif
7938 : #ifdef MOZ_VTUNE
7939 4 : vtune::MarkStub(code, "FreeStub");
7940 : #endif
7941 :
7942 8 : return code;
7943 : }
7944 :
7945 :
7946 : JitCode*
7947 4 : JitRuntime::generateLazyLinkStub(JSContext* cx)
7948 : {
7949 8 : MacroAssembler masm(cx);
7950 : #ifdef JS_USE_LINK_REGISTER
7951 : masm.pushReturnAddress();
7952 : #endif
7953 :
7954 4 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
7955 4 : Register temp0 = regs.takeAny();
7956 :
7957 4 : masm.loadJSContext(temp0);
7958 4 : masm.enterFakeExitFrame(temp0, temp0, LazyLinkExitFrameLayoutToken);
7959 4 : masm.PushStubCode();
7960 :
7961 4 : masm.setupUnalignedABICall(temp0);
7962 4 : masm.passABIArg(temp0);
7963 4 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation));
7964 :
7965 4 : masm.leaveExitFrame(/* stub code */ sizeof(JitCode*));
7966 :
7967 : #ifdef JS_USE_LINK_REGISTER
7968 : // Restore the return address such that the emitPrologue function of the
7969 : // CodeGenerator can push it back on the stack with pushReturnAddress.
7970 : masm.popReturnAddress();
7971 : #endif
7972 4 : masm.jump(ReturnReg);
7973 :
7974 8 : Linker linker(masm);
7975 8 : AutoFlushICache afc("LazyLinkStub");
7976 4 : JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
7977 :
7978 : #ifdef JS_ION_PERF
7979 : writePerfSpewerJitCodeProfile(code, "LazyLinkStub");
7980 : #endif
7981 : #ifdef MOZ_VTUNE
7982 4 : vtune::MarkStub(code, "LazyLinkStub");
7983 : #endif
7984 8 : return code;
7985 : }
7986 :
7987 : bool
7988 2072 : JitRuntime::generateTLEventVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f,
7989 : bool enter)
7990 : {
7991 : #ifdef JS_TRACE_LOGGING
7992 2072 : bool vmEventEnabled = TraceLogTextIdEnabled(TraceLogger_VM);
7993 2072 : bool vmSpecificEventEnabled = TraceLogTextIdEnabled(TraceLogger_VMSpecific);
7994 :
7995 2072 : if (vmEventEnabled || vmSpecificEventEnabled) {
7996 0 : AllocatableRegisterSet regs(RegisterSet::Volatile());
7997 0 : Register loggerReg = regs.takeAnyGeneral();
7998 0 : masm.Push(loggerReg);
7999 0 : masm.loadTraceLogger(loggerReg);
8000 :
8001 0 : if (vmEventEnabled) {
8002 0 : if (enter)
8003 0 : masm.tracelogStartId(loggerReg, TraceLogger_VM, /* force = */ true);
8004 : else
8005 0 : masm.tracelogStopId(loggerReg, TraceLogger_VM, /* force = */ true);
8006 : }
8007 0 : if (vmSpecificEventEnabled) {
8008 0 : TraceLoggerEvent event(f.name());
8009 0 : if (!event.hasTextId())
8010 0 : return false;
8011 :
8012 0 : if (enter)
8013 0 : masm.tracelogStartId(loggerReg, event.textId(), /* force = */ true);
8014 : else
8015 0 : masm.tracelogStopId(loggerReg, event.textId(), /* force = */ true);
8016 : }
8017 :
8018 0 : masm.Pop(loggerReg);
8019 : }
8020 : #endif
8021 :
8022 2072 : return true;
8023 : }
8024 :
8025 : typedef bool (*CharCodeAtFn)(JSContext*, HandleString, int32_t, uint32_t*);
8026 3 : static const VMFunction CharCodeAtInfo =
8027 6 : FunctionInfo<CharCodeAtFn>(jit::CharCodeAt, "CharCodeAt");
8028 :
8029 : void
8030 2 : CodeGenerator::visitCharCodeAt(LCharCodeAt* lir)
8031 : {
8032 2 : Register str = ToRegister(lir->str());
8033 2 : Register index = ToRegister(lir->index());
8034 2 : Register output = ToRegister(lir->output());
8035 :
8036 2 : OutOfLineCode* ool = oolCallVM(CharCodeAtInfo, lir, ArgList(str, index), StoreRegisterTo(output));
8037 2 : masm.loadStringChar(str, index, output, ool->entry());
8038 2 : masm.bind(ool->rejoin());
8039 2 : }
8040 :
8041 : typedef JSFlatString* (*StringFromCharCodeFn)(JSContext*, int32_t);
8042 3 : static const VMFunction StringFromCharCodeInfo =
8043 6 : FunctionInfo<StringFromCharCodeFn>(jit::StringFromCharCode, "StringFromCharCode");
8044 :
8045 : void
8046 2 : CodeGenerator::visitFromCharCode(LFromCharCode* lir)
8047 : {
8048 2 : Register code = ToRegister(lir->code());
8049 2 : Register output = ToRegister(lir->output());
8050 :
8051 2 : OutOfLineCode* ool = oolCallVM(StringFromCharCodeInfo, lir, ArgList(code), StoreRegisterTo(output));
8052 :
8053 : // OOL path if code >= UNIT_STATIC_LIMIT.
8054 4 : masm.branch32(Assembler::AboveOrEqual, code, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
8055 2 : ool->entry());
8056 :
8057 2 : masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
8058 2 : masm.loadPtr(BaseIndex(output, code, ScalePointer), output);
8059 :
8060 2 : masm.bind(ool->rejoin());
8061 2 : }
8062 :
8063 : typedef JSString* (*StringFromCodePointFn)(JSContext*, int32_t);
8064 3 : static const VMFunction StringFromCodePointInfo =
8065 6 : FunctionInfo<StringFromCodePointFn>(jit::StringFromCodePoint, "StringFromCodePoint");
8066 :
8067 : void
8068 0 : CodeGenerator::visitFromCodePoint(LFromCodePoint* lir)
8069 : {
8070 0 : Register codePoint = ToRegister(lir->codePoint());
8071 0 : Register output = ToRegister(lir->output());
8072 0 : Register temp1 = ToRegister(lir->temp1());
8073 0 : Register temp2 = ToRegister(lir->temp2());
8074 0 : LSnapshot* snapshot = lir->snapshot();
8075 :
8076 : // The OOL path is only taken when we can't allocate the inline string.
8077 0 : OutOfLineCode* ool = oolCallVM(StringFromCodePointInfo, lir, ArgList(codePoint),
8078 0 : StoreRegisterTo(output));
8079 :
8080 0 : Label isTwoByte;
8081 0 : Label* done = ool->rejoin();
8082 :
8083 : static_assert(StaticStrings::UNIT_STATIC_LIMIT -1 == JSString::MAX_LATIN1_CHAR,
8084 : "Latin-1 strings can be loaded from static strings");
8085 0 : masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
8086 0 : &isTwoByte);
8087 : {
8088 0 : masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
8089 0 : masm.loadPtr(BaseIndex(output, codePoint, ScalePointer), output);
8090 0 : masm.jump(done);
8091 : }
8092 0 : masm.bind(&isTwoByte);
8093 : {
8094 : // Use a bailout if the input is not a valid code point, because
8095 : // MFromCodePoint is movable and it'd be observable when a moved
8096 : // fromCodePoint throws an exception before its actual call site.
8097 0 : bailoutCmp32(Assembler::Above, codePoint, Imm32(unicode::NonBMPMax), snapshot);
8098 :
8099 : // Allocate a JSThinInlineString.
8100 : {
8101 : static_assert(JSThinInlineString::MAX_LENGTH_TWO_BYTE >= 2,
8102 : "JSThinInlineString can hold a supplementary code point");
8103 :
8104 0 : uint32_t flags = JSString::INIT_THIN_INLINE_FLAGS;
8105 0 : masm.newGCString(output, temp1, ool->entry());
8106 0 : masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
8107 : }
8108 :
8109 0 : Label isSupplementary;
8110 0 : masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(unicode::NonBMPMin),
8111 0 : &isSupplementary);
8112 : {
8113 : // Store length.
8114 0 : masm.store32(Imm32(1), Address(output, JSString::offsetOfLength()));
8115 :
8116 : // Load chars pointer in temp1.
8117 0 : masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
8118 0 : temp1);
8119 :
8120 0 : masm.store16(codePoint, Address(temp1, 0));
8121 :
8122 : // Null-terminate.
8123 0 : masm.store16(Imm32(0), Address(temp1, sizeof(char16_t)));
8124 :
8125 0 : masm.jump(done);
8126 : }
8127 0 : masm.bind(&isSupplementary);
8128 : {
8129 : // Store length.
8130 0 : masm.store32(Imm32(2), Address(output, JSString::offsetOfLength()));
8131 :
8132 : // Load chars pointer in temp1.
8133 0 : masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
8134 0 : temp1);
8135 :
8136 : // Inlined unicode::LeadSurrogate(uint32_t).
8137 0 : masm.move32(codePoint, temp2);
8138 0 : masm.rshift32(Imm32(10), temp2);
8139 0 : masm.add32(Imm32(unicode::LeadSurrogateMin - (unicode::NonBMPMin >> 10)), temp2);
8140 :
8141 0 : masm.store16(temp2, Address(temp1, 0));
8142 :
8143 : // Inlined unicode::TrailSurrogate(uint32_t).
8144 0 : masm.move32(codePoint, temp2);
8145 0 : masm.and32(Imm32(0x3FF), temp2);
8146 0 : masm.or32(Imm32(unicode::TrailSurrogateMin), temp2);
8147 :
8148 0 : masm.store16(temp2, Address(temp1, sizeof(char16_t)));
8149 :
8150 : // Null-terminate.
8151 0 : masm.store16(Imm32(0), Address(temp1, 2 * sizeof(char16_t)));
8152 : }
8153 : }
8154 :
8155 0 : masm.bind(done);
8156 0 : }
8157 :
8158 : void
8159 0 : CodeGenerator::visitSinCos(LSinCos *lir)
8160 : {
8161 0 : Register temp = ToRegister(lir->temp());
8162 0 : Register params = ToRegister(lir->temp2());
8163 0 : FloatRegister input = ToFloatRegister(lir->input());
8164 0 : FloatRegister outputSin = ToFloatRegister(lir->outputSin());
8165 0 : FloatRegister outputCos = ToFloatRegister(lir->outputCos());
8166 :
8167 0 : masm.reserveStack(sizeof(double) * 2);
8168 0 : masm.movePtr(masm.getStackPointer(), params);
8169 :
8170 0 : const MathCache* mathCache = lir->mir()->cache();
8171 :
8172 0 : masm.setupUnalignedABICall(temp);
8173 0 : if (mathCache) {
8174 0 : masm.movePtr(ImmPtr(mathCache), temp);
8175 0 : masm.passABIArg(temp);
8176 : }
8177 :
8178 : #define MAYBE_CACHED_(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
8179 :
8180 0 : masm.passABIArg(input, MoveOp::DOUBLE);
8181 0 : masm.passABIArg(MoveOperand(params, sizeof(double), MoveOperand::EFFECTIVE_ADDRESS),
8182 0 : MoveOp::GENERAL);
8183 0 : masm.passABIArg(MoveOperand(params, 0, MoveOperand::EFFECTIVE_ADDRESS),
8184 0 : MoveOp::GENERAL);
8185 :
8186 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED_(js::math_sincos)));
8187 : #undef MAYBE_CACHED_
8188 :
8189 0 : masm.loadDouble(Address(masm.getStackPointer(), 0), outputCos);
8190 0 : masm.loadDouble(Address(masm.getStackPointer(), sizeof(double)), outputSin);
8191 0 : masm.freeStack(sizeof(double) * 2);
8192 0 : }
8193 :
8194 : typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
8195 3 : static const VMFunction StringSplitInfo =
8196 6 : FunctionInfo<StringSplitFn>(js::str_split_string, "str_split_string");
8197 :
8198 : void
8199 0 : CodeGenerator::visitStringSplit(LStringSplit* lir)
8200 : {
8201 0 : pushArg(Imm32(INT32_MAX));
8202 0 : pushArg(ToRegister(lir->separator()));
8203 0 : pushArg(ToRegister(lir->string()));
8204 0 : pushArg(ImmGCPtr(lir->mir()->group()));
8205 :
8206 0 : callVM(StringSplitInfo, lir);
8207 0 : }
8208 :
8209 : void
8210 1 : CodeGenerator::visitInitializedLength(LInitializedLength* lir)
8211 : {
8212 1 : Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
8213 1 : masm.load32(initLength, ToRegister(lir->output()));
8214 1 : }
8215 :
8216 : void
8217 4 : CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
8218 : {
8219 4 : Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
8220 4 : RegisterOrInt32Constant index = ToRegisterOrInt32Constant(lir->index());
8221 :
8222 4 : masm.inc32(&index);
8223 4 : masm.store32(index, initLength);
8224 : // Restore register value if it is used/captured after.
8225 4 : masm.dec32(&index);
8226 4 : }
8227 :
8228 : void
8229 0 : CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
8230 : {
8231 0 : Register obj = ToRegister(lir->object());
8232 0 : Register result = ToRegister(lir->output());
8233 0 : masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
8234 0 : }
8235 :
8236 : void
8237 0 : CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir)
8238 : {
8239 0 : Register obj = ToRegister(lir->object());
8240 0 : Register result = ToRegister(lir->output());
8241 0 : masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result);
8242 0 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result);
8243 0 : }
8244 :
8245 : void
8246 0 : CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
8247 : {
8248 0 : Register obj = ToRegister(lir->object());
8249 0 : masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
8250 0 : }
8251 :
8252 : void
8253 0 : CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
8254 : {
8255 0 : Register obj = ToRegister(lir->object());
8256 0 : RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length());
8257 0 : Register temp = ToRegister(lir->temp());
8258 :
8259 0 : Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
8260 0 : masm.load32(initLengthAddr, temp);
8261 0 : masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
8262 :
8263 0 : if (key.isRegister())
8264 0 : masm.or32(key.reg(), temp);
8265 : else
8266 0 : masm.or32(Imm32(key.constant()), temp);
8267 :
8268 0 : masm.store32(temp, initLengthAddr);
8269 0 : }
8270 :
8271 : void
8272 0 : CodeGenerator::visitNotO(LNotO* lir)
8273 : {
8274 0 : MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
8275 : "This should be constant-folded if the object can't emulate undefined.");
8276 :
8277 0 : OutOfLineTestObjectWithLabels* ool = new(alloc()) OutOfLineTestObjectWithLabels();
8278 0 : addOutOfLineCode(ool, lir->mir());
8279 :
8280 0 : Label* ifEmulatesUndefined = ool->label1();
8281 0 : Label* ifDoesntEmulateUndefined = ool->label2();
8282 :
8283 0 : Register objreg = ToRegister(lir->input());
8284 0 : Register output = ToRegister(lir->output());
8285 : branchTestObjectEmulatesUndefined(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
8286 0 : output, ool);
8287 : // fall through
8288 :
8289 0 : Label join;
8290 :
8291 0 : masm.move32(Imm32(0), output);
8292 0 : masm.jump(&join);
8293 :
8294 0 : masm.bind(ifEmulatesUndefined);
8295 0 : masm.move32(Imm32(1), output);
8296 :
8297 0 : masm.bind(&join);
8298 0 : }
8299 :
8300 : void
8301 2 : CodeGenerator::visitNotV(LNotV* lir)
8302 : {
8303 4 : Maybe<Label> ifTruthyLabel, ifFalsyLabel;
8304 : Label* ifTruthy;
8305 : Label* ifFalsy;
8306 :
8307 2 : OutOfLineTestObjectWithLabels* ool = nullptr;
8308 2 : MDefinition* operand = lir->mir()->input();
8309 : // Unfortunately, it's possible that someone (e.g. phi elimination) switched
8310 : // out our operand after we did cacheOperandMightEmulateUndefined. So we
8311 : // might think it can emulate undefined _and_ know that it can't be an
8312 : // object.
8313 2 : if (lir->mir()->operandMightEmulateUndefined() && operand->mightBeType(MIRType::Object)) {
8314 0 : ool = new(alloc()) OutOfLineTestObjectWithLabels();
8315 0 : addOutOfLineCode(ool, lir->mir());
8316 0 : ifTruthy = ool->label1();
8317 0 : ifFalsy = ool->label2();
8318 : } else {
8319 2 : ifTruthyLabel.emplace();
8320 2 : ifFalsyLabel.emplace();
8321 2 : ifTruthy = ifTruthyLabel.ptr();
8322 2 : ifFalsy = ifFalsyLabel.ptr();
8323 : }
8324 :
8325 4 : testValueTruthyKernel(ToValue(lir, LNotV::Input), lir->temp1(), lir->temp2(),
8326 : ToFloatRegister(lir->tempFloat()),
8327 2 : ifTruthy, ifFalsy, ool, operand);
8328 :
8329 4 : Label join;
8330 2 : Register output = ToRegister(lir->output());
8331 :
8332 : // Note that the testValueTruthyKernel call above may choose to fall through
8333 : // to ifTruthy instead of branching there.
8334 2 : masm.bind(ifTruthy);
8335 2 : masm.move32(Imm32(0), output);
8336 2 : masm.jump(&join);
8337 :
8338 2 : masm.bind(ifFalsy);
8339 2 : masm.move32(Imm32(1), output);
8340 :
8341 : // both branches meet here.
8342 2 : masm.bind(&join);
8343 2 : }
8344 :
8345 : void
8346 1 : CodeGenerator::visitBoundsCheck(LBoundsCheck* lir)
8347 : {
8348 1 : const LAllocation* index = lir->index();
8349 1 : const LAllocation* length = lir->length();
8350 1 : LSnapshot* snapshot = lir->snapshot();
8351 :
8352 1 : if (index->isConstant()) {
8353 : // Use uint32 so that the comparison is unsigned.
8354 0 : uint32_t idx = ToInt32(index);
8355 0 : if (length->isConstant()) {
8356 0 : uint32_t len = ToInt32(lir->length());
8357 0 : if (idx < len)
8358 0 : return;
8359 0 : bailout(snapshot);
8360 0 : return;
8361 : }
8362 :
8363 0 : if (length->isRegister())
8364 0 : bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), snapshot);
8365 : else
8366 0 : bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), snapshot);
8367 0 : return;
8368 : }
8369 :
8370 1 : Register indexReg = ToRegister(index);
8371 1 : if (length->isConstant())
8372 0 : bailoutCmp32(Assembler::AboveOrEqual, indexReg, Imm32(ToInt32(length)), snapshot);
8373 1 : else if (length->isRegister())
8374 1 : bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), indexReg, snapshot);
8375 : else
8376 0 : bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), indexReg, snapshot);
8377 : }
8378 :
8379 : void
8380 0 : CodeGenerator::visitBoundsCheckRange(LBoundsCheckRange* lir)
8381 : {
8382 0 : int32_t min = lir->mir()->minimum();
8383 0 : int32_t max = lir->mir()->maximum();
8384 0 : MOZ_ASSERT(max >= min);
8385 :
8386 0 : const LAllocation* length = lir->length();
8387 0 : LSnapshot* snapshot = lir->snapshot();
8388 0 : Register temp = ToRegister(lir->getTemp(0));
8389 0 : if (lir->index()->isConstant()) {
8390 : int32_t nmin, nmax;
8391 0 : int32_t index = ToInt32(lir->index());
8392 0 : if (SafeAdd(index, min, &nmin) && SafeAdd(index, max, &nmax) && nmin >= 0) {
8393 0 : if (length->isRegister())
8394 0 : bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), Imm32(nmax), snapshot);
8395 : else
8396 0 : bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), Imm32(nmax), snapshot);
8397 0 : return;
8398 : }
8399 0 : masm.mov(ImmWord(index), temp);
8400 : } else {
8401 0 : masm.mov(ToRegister(lir->index()), temp);
8402 : }
8403 :
8404 : // If the minimum and maximum differ then do an underflow check first.
8405 : // If the two are the same then doing an unsigned comparison on the
8406 : // length will also catch a negative index.
8407 0 : if (min != max) {
8408 0 : if (min != 0) {
8409 0 : Label bail;
8410 0 : masm.branchAdd32(Assembler::Overflow, Imm32(min), temp, &bail);
8411 0 : bailoutFrom(&bail, snapshot);
8412 : }
8413 :
8414 0 : bailoutCmp32(Assembler::LessThan, temp, Imm32(0), snapshot);
8415 :
8416 0 : if (min != 0) {
8417 : int32_t diff;
8418 0 : if (SafeSub(max, min, &diff))
8419 0 : max = diff;
8420 : else
8421 0 : masm.sub32(Imm32(min), temp);
8422 : }
8423 : }
8424 :
8425 : // Compute the maximum possible index. No overflow check is needed when
8426 : // max > 0. We can only wraparound to a negative number, which will test as
8427 : // larger than all nonnegative numbers in the unsigned comparison, and the
8428 : // length is required to be nonnegative (else testing a negative length
8429 : // would succeed on any nonnegative index).
8430 0 : if (max != 0) {
8431 0 : if (max < 0) {
8432 0 : Label bail;
8433 0 : masm.branchAdd32(Assembler::Overflow, Imm32(max), temp, &bail);
8434 0 : bailoutFrom(&bail, snapshot);
8435 : } else {
8436 0 : masm.add32(Imm32(max), temp);
8437 : }
8438 : }
8439 :
8440 0 : if (length->isRegister())
8441 0 : bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), temp, snapshot);
8442 : else
8443 0 : bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), temp, snapshot);
8444 : }
8445 :
8446 : void
8447 2 : CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower* lir)
8448 : {
8449 2 : int32_t min = lir->mir()->minimum();
8450 4 : bailoutCmp32(Assembler::LessThan, ToRegister(lir->index()), Imm32(min),
8451 2 : lir->snapshot());
8452 2 : }
8453 :
8454 : class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
8455 : {
8456 : LInstruction* ins_;
8457 : Label rejoinStore_;
8458 :
8459 : public:
8460 1 : explicit OutOfLineStoreElementHole(LInstruction* ins)
8461 1 : : ins_(ins)
8462 : {
8463 1 : MOZ_ASSERT(ins->isStoreElementHoleV() || ins->isStoreElementHoleT() ||
8464 : ins->isFallibleStoreElementV() || ins->isFallibleStoreElementT());
8465 1 : }
8466 :
8467 1 : void accept(CodeGenerator* codegen) {
8468 1 : codegen->visitOutOfLineStoreElementHole(this);
8469 1 : }
8470 1 : LInstruction* ins() const {
8471 1 : return ins_;
8472 : }
8473 1 : Label* rejoinStore() {
8474 1 : return &rejoinStore_;
8475 : }
8476 : };
8477 :
8478 : void
8479 0 : CodeGenerator::emitStoreHoleCheck(Register elements, const LAllocation* index,
8480 : int32_t offsetAdjustment, LSnapshot* snapshot)
8481 : {
8482 0 : Label bail;
8483 0 : if (index->isConstant()) {
8484 0 : Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
8485 0 : masm.branchTestMagic(Assembler::Equal, dest, &bail);
8486 : } else {
8487 0 : BaseIndex dest(elements, ToRegister(index), TimesEight, offsetAdjustment);
8488 0 : masm.branchTestMagic(Assembler::Equal, dest, &bail);
8489 : }
8490 0 : bailoutFrom(&bail, snapshot);
8491 0 : }
8492 :
8493 : static ConstantOrRegister
8494 6 : ToConstantOrRegister(const LAllocation* value, MIRType valueType)
8495 : {
8496 6 : if (value->isConstant())
8497 0 : return ConstantOrRegister(value->toConstant()->toJSValue());
8498 6 : return TypedOrValueRegister(valueType, ToAnyRegister(value));
8499 : }
8500 :
8501 : void
8502 6 : CodeGenerator::emitStoreElementTyped(const LAllocation* value,
8503 : MIRType valueType, MIRType elementType,
8504 : Register elements, const LAllocation* index,
8505 : int32_t offsetAdjustment)
8506 : {
8507 6 : ConstantOrRegister v = ToConstantOrRegister(value, valueType);
8508 6 : if (index->isConstant()) {
8509 4 : Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
8510 4 : masm.storeUnboxedValue(v, valueType, dest, elementType);
8511 : } else {
8512 2 : BaseIndex dest(elements, ToRegister(index), TimesEight, offsetAdjustment);
8513 2 : masm.storeUnboxedValue(v, valueType, dest, elementType);
8514 : }
8515 6 : }
8516 :
8517 : void
8518 4 : CodeGenerator::visitStoreElementT(LStoreElementT* store)
8519 : {
8520 4 : Register elements = ToRegister(store->elements());
8521 4 : const LAllocation* index = store->index();
8522 :
8523 4 : if (store->mir()->needsBarrier())
8524 0 : emitPreBarrier(elements, index, store->mir()->offsetAdjustment());
8525 :
8526 4 : if (store->mir()->needsHoleCheck())
8527 0 : emitStoreHoleCheck(elements, index, store->mir()->offsetAdjustment(), store->snapshot());
8528 :
8529 8 : emitStoreElementTyped(store->value(),
8530 4 : store->mir()->value()->type(), store->mir()->elementType(),
8531 4 : elements, index, store->mir()->offsetAdjustment());
8532 4 : }
8533 :
8534 : void
8535 0 : CodeGenerator::visitStoreElementV(LStoreElementV* lir)
8536 : {
8537 0 : const ValueOperand value = ToValue(lir, LStoreElementV::Value);
8538 0 : Register elements = ToRegister(lir->elements());
8539 0 : const LAllocation* index = lir->index();
8540 :
8541 0 : if (lir->mir()->needsBarrier())
8542 0 : emitPreBarrier(elements, index, lir->mir()->offsetAdjustment());
8543 :
8544 0 : if (lir->mir()->needsHoleCheck())
8545 0 : emitStoreHoleCheck(elements, index, lir->mir()->offsetAdjustment(), lir->snapshot());
8546 :
8547 0 : if (lir->index()->isConstant()) {
8548 : Address dest(elements,
8549 0 : ToInt32(lir->index()) * sizeof(js::Value) + lir->mir()->offsetAdjustment());
8550 0 : masm.storeValue(value, dest);
8551 : } else {
8552 : BaseIndex dest(elements, ToRegister(lir->index()), TimesEight,
8553 0 : lir->mir()->offsetAdjustment());
8554 0 : masm.storeValue(value, dest);
8555 : }
8556 0 : }
8557 :
8558 : template <typename T> void
8559 1 : CodeGenerator::emitStoreElementHoleT(T* lir)
8560 : {
8561 : static_assert(std::is_same<T, LStoreElementHoleT>::value || std::is_same<T, LFallibleStoreElementT>::value,
8562 : "emitStoreElementHoleT called with unexpected argument type");
8563 :
8564 1 : OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
8565 1 : addOutOfLineCode(ool, lir->mir());
8566 :
8567 1 : Register obj = ToRegister(lir->object());
8568 1 : Register elements = ToRegister(lir->elements());
8569 1 : const LAllocation* index = lir->index();
8570 1 : RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
8571 :
8572 1 : JSValueType unboxedType = lir->mir()->unboxedType();
8573 1 : if (unboxedType == JSVAL_TYPE_MAGIC) {
8574 1 : Address initLength(elements, ObjectElements::offsetOfInitializedLength());
8575 1 : masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
8576 :
8577 1 : if (lir->mir()->needsBarrier())
8578 1 : emitPreBarrier(elements, index, 0);
8579 :
8580 1 : masm.bind(ool->rejoinStore());
8581 1 : emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
8582 : elements, index, 0);
8583 : } else {
8584 0 : Register temp = ToRegister(lir->getTemp(0));
8585 0 : Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
8586 0 : masm.load32(initLength, temp);
8587 0 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
8588 0 : masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
8589 :
8590 0 : ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
8591 :
8592 0 : if (index->isConstant()) {
8593 0 : Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
8594 0 : EmitUnboxedPreBarrier(masm, address, unboxedType);
8595 :
8596 0 : masm.bind(ool->rejoinStore());
8597 0 : masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
8598 : } else {
8599 : BaseIndex address(elements, ToRegister(index),
8600 0 : ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
8601 0 : EmitUnboxedPreBarrier(masm, address, unboxedType);
8602 :
8603 0 : masm.bind(ool->rejoinStore());
8604 0 : masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
8605 : }
8606 : }
8607 :
8608 1 : masm.bind(ool->rejoin());
8609 1 : }
8610 :
8611 : void
8612 1 : CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
8613 : {
8614 1 : emitStoreElementHoleT(lir);
8615 1 : }
8616 :
8617 : template <typename T> void
8618 0 : CodeGenerator::emitStoreElementHoleV(T* lir)
8619 : {
8620 : static_assert(std::is_same<T, LStoreElementHoleV>::value || std::is_same<T, LFallibleStoreElementV>::value,
8621 : "emitStoreElementHoleV called with unexpected parameter type");
8622 :
8623 0 : OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
8624 0 : addOutOfLineCode(ool, lir->mir());
8625 :
8626 0 : Register obj = ToRegister(lir->object());
8627 0 : Register elements = ToRegister(lir->elements());
8628 0 : const LAllocation* index = lir->index();
8629 0 : const ValueOperand value = ToValue(lir, T::Value);
8630 0 : RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
8631 :
8632 0 : JSValueType unboxedType = lir->mir()->unboxedType();
8633 0 : if (unboxedType == JSVAL_TYPE_MAGIC) {
8634 0 : Address initLength(elements, ObjectElements::offsetOfInitializedLength());
8635 0 : masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
8636 :
8637 0 : if (lir->mir()->needsBarrier())
8638 0 : emitPreBarrier(elements, index, 0);
8639 :
8640 0 : masm.bind(ool->rejoinStore());
8641 0 : if (index->isConstant())
8642 0 : masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
8643 : else
8644 0 : masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
8645 : } else {
8646 0 : Register temp = ToRegister(lir->getTemp(0));
8647 0 : Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
8648 0 : masm.load32(initLength, temp);
8649 0 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
8650 0 : masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
8651 :
8652 0 : if (index->isConstant()) {
8653 0 : Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
8654 0 : EmitUnboxedPreBarrier(masm, address, unboxedType);
8655 :
8656 0 : masm.bind(ool->rejoinStore());
8657 0 : masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
8658 : } else {
8659 : BaseIndex address(elements, ToRegister(index),
8660 0 : ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
8661 0 : EmitUnboxedPreBarrier(masm, address, unboxedType);
8662 :
8663 0 : masm.bind(ool->rejoinStore());
8664 0 : masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
8665 : }
8666 : }
8667 :
8668 0 : masm.bind(ool->rejoin());
8669 0 : }
8670 :
8671 : void
8672 0 : CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
8673 : {
8674 0 : emitStoreElementHoleV(lir);
8675 0 : }
8676 :
8677 : typedef bool (*ThrowReadOnlyFn)(JSContext*, HandleObject, int32_t);
8678 3 : static const VMFunction ThrowReadOnlyInfo =
8679 6 : FunctionInfo<ThrowReadOnlyFn>(ThrowReadOnlyError, "ThrowReadOnlyError");
8680 :
8681 : void
8682 0 : CodeGenerator::visitFallibleStoreElementT(LFallibleStoreElementT* lir)
8683 : {
8684 0 : Register elements = ToRegister(lir->elements());
8685 :
8686 : // Handle frozen objects
8687 0 : Label isFrozen;
8688 0 : Address flags(elements, ObjectElements::offsetOfFlags());
8689 0 : if (!lir->mir()->strict()) {
8690 0 : masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
8691 : } else {
8692 0 : Register object = ToRegister(lir->object());
8693 0 : const LAllocation* index = lir->index();
8694 : OutOfLineCode* ool;
8695 0 : if (index->isConstant()) {
8696 0 : ool = oolCallVM(ThrowReadOnlyInfo, lir,
8697 0 : ArgList(object, Imm32(ToInt32(index))), StoreNothing());
8698 : } else {
8699 0 : ool = oolCallVM(ThrowReadOnlyInfo, lir,
8700 0 : ArgList(object, ToRegister(index)), StoreNothing());
8701 : }
8702 0 : masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
8703 : // This OOL code should have thrown an exception, so will never return.
8704 : // So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
8705 : // of a jump) does a masm.assumeUnreachable().
8706 : }
8707 :
8708 0 : emitStoreElementHoleT(lir);
8709 :
8710 0 : masm.bind(&isFrozen);
8711 0 : }
8712 :
8713 : void
8714 0 : CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir)
8715 : {
8716 0 : Register elements = ToRegister(lir->elements());
8717 :
8718 : // Handle frozen objects
8719 0 : Label isFrozen;
8720 0 : Address flags(elements, ObjectElements::offsetOfFlags());
8721 0 : if (!lir->mir()->strict()) {
8722 0 : masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
8723 : } else {
8724 0 : Register object = ToRegister(lir->object());
8725 0 : const LAllocation* index = lir->index();
8726 : OutOfLineCode* ool;
8727 0 : if (index->isConstant()) {
8728 0 : ool = oolCallVM(ThrowReadOnlyInfo, lir,
8729 0 : ArgList(object, Imm32(ToInt32(index))), StoreNothing());
8730 : } else {
8731 0 : ool = oolCallVM(ThrowReadOnlyInfo, lir,
8732 0 : ArgList(object, ToRegister(index)), StoreNothing());
8733 : }
8734 0 : masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
8735 : // This OOL code should have thrown an exception, so will never return.
8736 : // So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
8737 : // of a jump) does a masm.assumeUnreachable().
8738 : }
8739 :
8740 0 : emitStoreElementHoleV(lir);
8741 :
8742 0 : masm.bind(&isFrozen);
8743 0 : }
8744 :
8745 : typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
8746 : HandleValue, bool strict);
8747 3 : static const VMFunction SetDenseOrUnboxedArrayElementInfo =
8748 6 : FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement,
8749 : "SetDenseOrUnboxedArrayElement");
8750 :
8751 : void
8752 1 : CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
8753 : {
8754 1 : Register object, elements;
8755 1 : LInstruction* ins = ool->ins();
8756 : const LAllocation* index;
8757 : MIRType valueType;
8758 1 : ConstantOrRegister value;
8759 : JSValueType unboxedType;
8760 1 : LDefinition *temp = nullptr;
8761 :
8762 1 : if (ins->isStoreElementHoleV()) {
8763 0 : LStoreElementHoleV* store = ins->toStoreElementHoleV();
8764 0 : object = ToRegister(store->object());
8765 0 : elements = ToRegister(store->elements());
8766 0 : index = store->index();
8767 0 : valueType = store->mir()->value()->type();
8768 0 : value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
8769 0 : unboxedType = store->mir()->unboxedType();
8770 0 : temp = store->getTemp(0);
8771 1 : } else if (ins->isFallibleStoreElementV()) {
8772 0 : LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
8773 0 : object = ToRegister(store->object());
8774 0 : elements = ToRegister(store->elements());
8775 0 : index = store->index();
8776 0 : valueType = store->mir()->value()->type();
8777 0 : value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
8778 0 : unboxedType = store->mir()->unboxedType();
8779 0 : temp = store->getTemp(0);
8780 1 : } else if (ins->isStoreElementHoleT()) {
8781 1 : LStoreElementHoleT* store = ins->toStoreElementHoleT();
8782 1 : object = ToRegister(store->object());
8783 1 : elements = ToRegister(store->elements());
8784 1 : index = store->index();
8785 1 : valueType = store->mir()->value()->type();
8786 1 : if (store->value()->isConstant())
8787 0 : value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
8788 : else
8789 1 : value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
8790 1 : unboxedType = store->mir()->unboxedType();
8791 1 : temp = store->getTemp(0);
8792 : } else { // ins->isFallibleStoreElementT()
8793 0 : LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
8794 0 : object = ToRegister(store->object());
8795 0 : elements = ToRegister(store->elements());
8796 0 : index = store->index();
8797 0 : valueType = store->mir()->value()->type();
8798 0 : if (store->value()->isConstant())
8799 0 : value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
8800 : else
8801 0 : value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
8802 0 : unboxedType = store->mir()->unboxedType();
8803 0 : temp = store->getTemp(0);
8804 : }
8805 :
8806 1 : RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
8807 :
8808 : // If index == initializedLength, try to bump the initialized length inline.
8809 : // If index > initializedLength, call a stub. Note that this relies on the
8810 : // condition flags sticking from the incoming branch.
8811 2 : Label callStub;
8812 : #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
8813 : // Had to reimplement for MIPS because there are no flags.
8814 : if (unboxedType == JSVAL_TYPE_MAGIC) {
8815 : Address initLength(elements, ObjectElements::offsetOfInitializedLength());
8816 : masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
8817 : } else {
8818 : Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
8819 : masm.load32(initLength, ToRegister(temp));
8820 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
8821 : masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub);
8822 : }
8823 : #else
8824 1 : masm.j(Assembler::NotEqual, &callStub);
8825 : #endif
8826 :
8827 1 : if (unboxedType == JSVAL_TYPE_MAGIC) {
8828 : // Check array capacity.
8829 2 : masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
8830 1 : key, &callStub);
8831 :
8832 : // Update initialized length. The capacity guard above ensures this won't overflow,
8833 : // due to MAX_DENSE_ELEMENTS_COUNT.
8834 1 : masm.inc32(&key);
8835 1 : masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
8836 :
8837 : // Update length if length < initializedLength.
8838 2 : Label dontUpdate;
8839 2 : masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
8840 1 : key, &dontUpdate);
8841 1 : masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
8842 1 : masm.bind(&dontUpdate);
8843 :
8844 1 : masm.dec32(&key);
8845 : } else {
8846 : // Check array capacity.
8847 0 : masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
8848 :
8849 : // Update initialized length.
8850 0 : masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
8851 :
8852 : // Update length if length < initializedLength.
8853 0 : Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
8854 0 : Label dontUpdate;
8855 0 : masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate);
8856 0 : masm.add32(Imm32(1), lengthAddr);
8857 0 : masm.bind(&dontUpdate);
8858 : }
8859 :
8860 2 : if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
8861 2 : unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double)
8862 : {
8863 : // The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
8864 : // the type tag, so we do the store on the OOL path. We use MIRType::None for the element
8865 : // type so that storeElementTyped will always store the type tag.
8866 1 : if (ins->isStoreElementHoleT()) {
8867 1 : emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType::None,
8868 1 : elements, index, 0);
8869 1 : masm.jump(ool->rejoin());
8870 0 : } else if (ins->isFallibleStoreElementT()) {
8871 0 : emitStoreElementTyped(ins->toFallibleStoreElementT()->value(), valueType,
8872 0 : MIRType::None, elements, index, 0);
8873 0 : masm.jump(ool->rejoin());
8874 : }
8875 : } else {
8876 : // Jump to the inline path where we will store the value.
8877 0 : masm.jump(ool->rejoinStore());
8878 : }
8879 :
8880 1 : masm.bind(&callStub);
8881 1 : saveLive(ins);
8882 :
8883 1 : pushArg(Imm32(current->mir()->strict()));
8884 1 : pushArg(value);
8885 1 : if (index->isConstant())
8886 0 : pushArg(Imm32(ToInt32(index)));
8887 : else
8888 1 : pushArg(ToRegister(index));
8889 1 : pushArg(object);
8890 1 : callVM(SetDenseOrUnboxedArrayElementInfo, ins);
8891 :
8892 1 : restoreLive(ins);
8893 1 : masm.jump(ool->rejoin());
8894 1 : }
8895 :
8896 : template <typename T>
8897 : static void
8898 0 : StoreUnboxedPointer(MacroAssembler& masm, T address, MIRType type, const LAllocation* value,
8899 : bool preBarrier)
8900 : {
8901 0 : if (preBarrier)
8902 0 : masm.guardedCallPreBarrier(address, type);
8903 0 : if (value->isConstant()) {
8904 0 : Value v = value->toConstant()->toJSValue();
8905 0 : if (v.isGCThing()) {
8906 0 : masm.storePtr(ImmGCPtr(v.toGCThing()), address);
8907 : } else {
8908 0 : MOZ_ASSERT(v.isNull());
8909 0 : masm.storePtr(ImmWord(0), address);
8910 : }
8911 : } else {
8912 0 : masm.storePtr(ToRegister(value), address);
8913 : }
8914 0 : }
8915 :
8916 : void
8917 0 : CodeGenerator::visitStoreUnboxedPointer(LStoreUnboxedPointer* lir)
8918 : {
8919 : MIRType type;
8920 : int32_t offsetAdjustment;
8921 : bool preBarrier;
8922 0 : if (lir->mir()->isStoreUnboxedObjectOrNull()) {
8923 0 : type = MIRType::Object;
8924 0 : offsetAdjustment = lir->mir()->toStoreUnboxedObjectOrNull()->offsetAdjustment();
8925 0 : preBarrier = lir->mir()->toStoreUnboxedObjectOrNull()->preBarrier();
8926 0 : } else if (lir->mir()->isStoreUnboxedString()) {
8927 0 : type = MIRType::String;
8928 0 : offsetAdjustment = lir->mir()->toStoreUnboxedString()->offsetAdjustment();
8929 0 : preBarrier = lir->mir()->toStoreUnboxedString()->preBarrier();
8930 : } else {
8931 0 : MOZ_CRASH();
8932 : }
8933 :
8934 0 : Register elements = ToRegister(lir->elements());
8935 0 : const LAllocation* index = lir->index();
8936 0 : const LAllocation* value = lir->value();
8937 :
8938 0 : if (index->isConstant()) {
8939 0 : Address address(elements, ToInt32(index) * sizeof(uintptr_t) + offsetAdjustment);
8940 0 : StoreUnboxedPointer(masm, address, type, value, preBarrier);
8941 : } else {
8942 0 : BaseIndex address(elements, ToRegister(index), ScalePointer, offsetAdjustment);
8943 0 : StoreUnboxedPointer(masm, address, type, value, preBarrier);
8944 : }
8945 0 : }
8946 :
8947 : typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*);
8948 3 : static const VMFunction ConvertUnboxedPlainObjectToNativeInfo =
8949 6 : FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedPlainObject::convertToNative,
8950 : "UnboxedPlainObject::convertToNative");
8951 3 : static const VMFunction ConvertUnboxedArrayObjectToNativeInfo =
8952 6 : FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative,
8953 : "UnboxedArrayObject::convertToNative");
8954 :
8955 : void
8956 0 : CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir)
8957 : {
8958 0 : Register object = ToRegister(lir->getOperand(0));
8959 :
8960 0 : OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
8961 : ? ConvertUnboxedArrayObjectToNativeInfo
8962 : : ConvertUnboxedPlainObjectToNativeInfo,
8963 0 : lir, ArgList(object), StoreNothing());
8964 :
8965 0 : masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
8966 0 : ImmGCPtr(lir->mir()->group()), ool->entry());
8967 0 : masm.bind(ool->rejoin());
8968 0 : }
8969 :
8970 : typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue);
8971 3 : static const VMFunction ArrayPopDenseInfo =
8972 6 : FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense, "ArrayPopDense");
8973 3 : static const VMFunction ArrayShiftDenseInfo =
8974 6 : FunctionInfo<ArrayPopShiftFn>(jit::ArrayShiftDense, "ArrayShiftDense");
8975 :
8976 : void
8977 0 : CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
8978 : Register elementsTemp, Register lengthTemp, TypedOrValueRegister out)
8979 : {
8980 : OutOfLineCode* ool;
8981 :
8982 0 : if (mir->mode() == MArrayPopShift::Pop) {
8983 0 : ool = oolCallVM(ArrayPopDenseInfo, lir, ArgList(obj), StoreValueTo(out));
8984 : } else {
8985 0 : MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
8986 0 : ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
8987 : }
8988 :
8989 : // VM call if a write barrier is necessary.
8990 0 : masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
8991 :
8992 : // Load elements and length, and VM call if length != initializedLength.
8993 0 : RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
8994 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
8995 0 : masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
8996 0 : masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
8997 :
8998 0 : Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
8999 0 : masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
9000 : } else {
9001 0 : masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
9002 0 : masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp);
9003 0 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp);
9004 :
9005 0 : Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
9006 0 : masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
9007 : }
9008 :
9009 : // Test for length != 0. On zero length either take a VM call or generate
9010 : // an undefined value, depending on whether the call is known to produce
9011 : // undefined.
9012 0 : Label done;
9013 0 : if (mir->maybeUndefined()) {
9014 0 : Label notEmpty;
9015 0 : masm.branchTest32(Assembler::NonZero, lengthTemp, lengthTemp, ¬Empty);
9016 :
9017 : // According to the spec we need to set the length 0 (which is already 0).
9018 : // This is observable when the array length is made non-writable.
9019 : // Handle this case in the OOL. When freezing an unboxed array it is converted
9020 : // to an normal array.
9021 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9022 0 : Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
9023 0 : Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
9024 0 : masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
9025 : }
9026 :
9027 0 : masm.moveValue(UndefinedValue(), out.valueReg());
9028 0 : masm.jump(&done);
9029 0 : masm.bind(¬Empty);
9030 : } else {
9031 0 : masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
9032 : }
9033 :
9034 0 : masm.dec32(&key);
9035 :
9036 0 : if (mir->mode() == MArrayPopShift::Pop) {
9037 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9038 0 : BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
9039 0 : masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
9040 : } else {
9041 0 : size_t elemSize = UnboxedTypeSize(mir->unboxedType());
9042 0 : BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize));
9043 0 : masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
9044 : }
9045 : } else {
9046 0 : MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
9047 0 : Address addr(elementsTemp, 0);
9048 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC)
9049 0 : masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
9050 : else
9051 0 : masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
9052 : }
9053 :
9054 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9055 : // Handle the failure case when the array length is non-writable in the
9056 : // OOL path. (Unlike in the adding-an-element cases, we can't rely on the
9057 : // capacity <= length invariant for such arrays to avoid an explicit
9058 : // check.)
9059 0 : Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
9060 0 : Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
9061 0 : masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
9062 : }
9063 :
9064 0 : if (mir->mode() == MArrayPopShift::Shift) {
9065 : // Don't save the elementsTemp register.
9066 0 : LiveRegisterSet temps;
9067 0 : temps.add(elementsTemp);
9068 :
9069 0 : saveVolatile(temps);
9070 0 : masm.setupUnalignedABICall(elementsTemp);
9071 0 : masm.passABIArg(obj);
9072 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::ArrayShiftMoveElements));
9073 0 : restoreVolatile(temps);
9074 :
9075 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9076 : // Reload elementsTemp as ArrayShiftMoveElements may have moved it.
9077 0 : masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
9078 : }
9079 : }
9080 :
9081 0 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9082 : // Now adjust length and initializedLength.
9083 0 : masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
9084 0 : masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
9085 : } else {
9086 : // Unboxed arrays always have writable lengths. Adjust length and
9087 : // initializedLength.
9088 0 : masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength()));
9089 0 : masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
9090 : }
9091 :
9092 0 : masm.bind(&done);
9093 0 : masm.bind(ool->rejoin());
9094 0 : }
9095 :
9096 : void
9097 0 : CodeGenerator::visitArrayPopShiftV(LArrayPopShiftV* lir)
9098 : {
9099 0 : Register obj = ToRegister(lir->object());
9100 0 : Register elements = ToRegister(lir->temp0());
9101 0 : Register length = ToRegister(lir->temp1());
9102 0 : TypedOrValueRegister out(ToOutValue(lir));
9103 0 : emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
9104 0 : }
9105 :
9106 : void
9107 0 : CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir)
9108 : {
9109 0 : Register obj = ToRegister(lir->object());
9110 0 : Register elements = ToRegister(lir->temp0());
9111 0 : Register length = ToRegister(lir->temp1());
9112 0 : TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
9113 0 : emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
9114 0 : }
9115 :
9116 : typedef bool (*ArrayPushDenseFn)(JSContext*, HandleObject, HandleValue, uint32_t*);
9117 3 : static const VMFunction ArrayPushDenseInfo =
9118 6 : FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense, "ArrayPushDense");
9119 :
9120 : void
9121 1 : CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register obj,
9122 : const ConstantOrRegister& value, Register elementsTemp, Register length)
9123 : {
9124 1 : OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
9125 :
9126 1 : RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
9127 1 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9128 : // Load elements and length.
9129 1 : masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
9130 1 : masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
9131 :
9132 : // Guard length == initializedLength.
9133 1 : Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
9134 1 : masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
9135 :
9136 : // Guard length < capacity.
9137 1 : Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
9138 1 : masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
9139 :
9140 : // Do the store.
9141 1 : masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
9142 : } else {
9143 : // Load initialized length.
9144 0 : masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length);
9145 0 : masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length);
9146 :
9147 : // Guard length == initializedLength.
9148 0 : Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
9149 0 : masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
9150 :
9151 : // Guard length < capacity.
9152 0 : masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry());
9153 :
9154 : // Load elements and do the store.
9155 0 : masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
9156 0 : size_t elemSize = UnboxedTypeSize(mir->unboxedType());
9157 0 : BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize));
9158 0 : masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr);
9159 : }
9160 :
9161 1 : masm.inc32(&key);
9162 :
9163 : // Update length and initialized length.
9164 1 : if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
9165 1 : masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
9166 1 : masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
9167 : } else {
9168 0 : masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength()));
9169 0 : masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
9170 : }
9171 :
9172 1 : masm.bind(ool->rejoin());
9173 1 : }
9174 :
9175 : void
9176 0 : CodeGenerator::visitArrayPushV(LArrayPushV* lir)
9177 : {
9178 0 : Register obj = ToRegister(lir->object());
9179 0 : Register elementsTemp = ToRegister(lir->temp());
9180 0 : Register length = ToRegister(lir->output());
9181 0 : ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
9182 0 : emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
9183 0 : }
9184 :
9185 : void
9186 1 : CodeGenerator::visitArrayPushT(LArrayPushT* lir)
9187 : {
9188 1 : Register obj = ToRegister(lir->object());
9189 1 : Register elementsTemp = ToRegister(lir->temp());
9190 1 : Register length = ToRegister(lir->output());
9191 1 : ConstantOrRegister value;
9192 1 : if (lir->value()->isConstant())
9193 0 : value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
9194 : else
9195 1 : value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
9196 1 : emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
9197 1 : }
9198 :
9199 : typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
9200 3 : static const VMFunction ArraySliceDenseInfo =
9201 6 : FunctionInfo<ArraySliceDenseFn>(array_slice_dense, "array_slice_dense");
9202 :
9203 : void
9204 0 : CodeGenerator::visitArraySlice(LArraySlice* lir)
9205 : {
9206 0 : Register object = ToRegister(lir->object());
9207 0 : Register begin = ToRegister(lir->begin());
9208 0 : Register end = ToRegister(lir->end());
9209 0 : Register temp1 = ToRegister(lir->temp1());
9210 0 : Register temp2 = ToRegister(lir->temp2());
9211 :
9212 0 : Label call, fail;
9213 :
9214 : // Try to allocate an object.
9215 0 : masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
9216 :
9217 : // Fixup the group of the result in case it doesn't match the template object.
9218 0 : masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp2);
9219 0 : masm.storePtr(temp2, Address(temp1, JSObject::offsetOfGroup()));
9220 :
9221 0 : masm.jump(&call);
9222 : {
9223 0 : masm.bind(&fail);
9224 0 : masm.movePtr(ImmPtr(nullptr), temp1);
9225 : }
9226 0 : masm.bind(&call);
9227 :
9228 0 : pushArg(temp1);
9229 0 : pushArg(end);
9230 0 : pushArg(begin);
9231 0 : pushArg(object);
9232 0 : callVM(ArraySliceDenseInfo, lir);
9233 0 : }
9234 :
9235 : typedef JSString* (*ArrayJoinFn)(JSContext*, HandleObject, HandleString);
9236 3 : static const VMFunction ArrayJoinInfo = FunctionInfo<ArrayJoinFn>(jit::ArrayJoin, "ArrayJoin");
9237 :
9238 : void
9239 1 : CodeGenerator::visitArrayJoin(LArrayJoin* lir)
9240 : {
9241 1 : pushArg(ToRegister(lir->separator()));
9242 1 : pushArg(ToRegister(lir->array()));
9243 :
9244 1 : callVM(ArrayJoinInfo, lir);
9245 1 : }
9246 :
9247 : typedef JSObject* (*ValueToIteratorFn)(JSContext*, uint32_t, HandleValue);
9248 3 : static const VMFunction ValueToIteratorInfo =
9249 6 : FunctionInfo<ValueToIteratorFn>(ValueToIterator, "ValueToIterator");
9250 :
9251 : void
9252 0 : CodeGenerator::visitCallIteratorStartV(LCallIteratorStartV* lir)
9253 : {
9254 0 : pushArg(ToValue(lir, LCallIteratorStartV::Value));
9255 0 : pushArg(Imm32(lir->mir()->flags()));
9256 0 : callVM(ValueToIteratorInfo, lir);
9257 0 : }
9258 :
9259 : typedef JSObject* (*GetIteratorFn)(JSContext*, HandleObject, uint32_t);
9260 3 : static const VMFunction GetIteratorInfo =
9261 6 : FunctionInfo<GetIteratorFn>(GetIterator, "GetIterator");
9262 :
9263 : void
9264 0 : CodeGenerator::visitCallIteratorStartO(LCallIteratorStartO* lir)
9265 : {
9266 0 : pushArg(Imm32(lir->mir()->flags()));
9267 0 : pushArg(ToRegister(lir->object()));
9268 0 : callVM(GetIteratorInfo, lir);
9269 0 : }
9270 :
9271 : void
9272 0 : CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
9273 : {
9274 0 : Label emptyObj;
9275 0 : masm.branchPtr(Assembler::Equal,
9276 0 : Address(obj, NativeObject::offsetOfElements()),
9277 : ImmPtr(js::emptyObjectElements),
9278 0 : &emptyObj);
9279 0 : masm.branchPtr(Assembler::NotEqual,
9280 0 : Address(obj, NativeObject::offsetOfElements()),
9281 : ImmPtr(js::emptyObjectElementsShared),
9282 0 : target);
9283 0 : masm.bind(&emptyObj);
9284 0 : }
9285 :
9286 : void
9287 0 : CodeGenerator::visitIteratorStartO(LIteratorStartO* lir)
9288 : {
9289 0 : const Register obj = ToRegister(lir->object());
9290 0 : const Register output = ToRegister(lir->output());
9291 :
9292 0 : uint32_t flags = lir->mir()->flags();
9293 :
9294 0 : OutOfLineCode* ool = oolCallVM(GetIteratorInfo, lir,
9295 0 : ArgList(obj, Imm32(flags)), StoreRegisterTo(output));
9296 :
9297 0 : const Register temp1 = ToRegister(lir->temp1());
9298 0 : const Register temp2 = ToRegister(lir->temp2());
9299 0 : const Register niTemp = ToRegister(lir->temp3()); // Holds the NativeIterator object.
9300 :
9301 : // Iterators other than for-in should use LCallIteratorStart.
9302 0 : MOZ_ASSERT(flags == JSITER_ENUMERATE);
9303 :
9304 : // Fetch the most recent iterator and ensure it's not nullptr.
9305 0 : masm.loadPtr(AbsoluteAddress(gen->compartment->addressOfLastCachedNativeIterator()), output);
9306 0 : masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
9307 :
9308 : // Load NativeIterator.
9309 0 : masm.loadObjPrivate(output, JSObject::ITER_CLASS_NFIXED_SLOTS, niTemp);
9310 :
9311 : // Ensure the |active| and |unreusable| bits are not set.
9312 0 : masm.branchTest32(Assembler::NonZero, Address(niTemp, offsetof(NativeIterator, flags)),
9313 0 : Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), ool->entry());
9314 :
9315 : // Load the iterator's receiver guard array.
9316 0 : masm.loadPtr(Address(niTemp, offsetof(NativeIterator, guard_array)), temp2);
9317 :
9318 : // Compare object with the first receiver guard. The last iterator can only
9319 : // match for native objects and unboxed objects.
9320 : {
9321 0 : Address groupAddr(temp2, offsetof(ReceiverGuard, group));
9322 0 : Address shapeAddr(temp2, offsetof(ReceiverGuard, shape));
9323 0 : Label guardDone, unboxedObject, noExpando;
9324 : // This is a guard for an unboxed object.
9325 0 : masm.branchPtr(Assembler::NotEqual, groupAddr, ImmWord(0), &unboxedObject);
9326 :
9327 : // Guard for a normal object, make sure the shape matches.
9328 0 : masm.loadObjShape(obj, temp1);
9329 0 : masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
9330 :
9331 : // Ensure the object does not have any elements. The presence of dense
9332 : // elements is not captured by the shape tests above.
9333 0 : branchIfNotEmptyObjectElements(obj, ool->entry());
9334 0 : masm.jump(&guardDone);
9335 :
9336 0 : masm.bind(&unboxedObject);
9337 0 : masm.loadObjGroup(obj, temp1);
9338 0 : masm.branchPtr(Assembler::NotEqual, groupAddr, temp1, ool->entry());
9339 0 : masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), temp1);
9340 0 : masm.branchTestPtr(Assembler::Zero, temp1, temp1, &noExpando);
9341 0 : branchIfNotEmptyObjectElements(temp1, ool->entry());
9342 0 : masm.loadObjShape(temp1, temp1);
9343 0 : masm.bind(&noExpando);
9344 0 : masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
9345 0 : masm.bind(&guardDone);
9346 : }
9347 :
9348 : // Compare shape of object's prototype with the second shape. The prototype
9349 : // must be native, as unboxed objects cannot be prototypes (they cannot
9350 : // have the delegate flag set). Also check for the absence of dense elements.
9351 0 : Address prototypeShapeAddr(temp2, sizeof(ReceiverGuard) + offsetof(ReceiverGuard, shape));
9352 0 : masm.loadObjProto(obj, temp1);
9353 0 : branchIfNotEmptyObjectElements(temp1, ool->entry());
9354 0 : masm.loadObjShape(temp1, temp1);
9355 0 : masm.branchPtr(Assembler::NotEqual, prototypeShapeAddr, temp1, ool->entry());
9356 :
9357 : // Ensure the object's prototype's prototype is nullptr. The last native
9358 : // iterator will always have a prototype chain length of one (i.e. it must
9359 : // be a plain object), so we do not need to generate a loop here.
9360 0 : masm.loadObjProto(obj, temp1);
9361 0 : masm.loadObjProto(temp1, temp1);
9362 0 : masm.branchTestPtr(Assembler::NonZero, temp1, temp1, ool->entry());
9363 :
9364 : // Pre-write barrier for store to 'obj'.
9365 0 : masm.guardedCallPreBarrier(Address(niTemp, offsetof(NativeIterator, obj)), MIRType::Object);
9366 :
9367 : // Mark iterator as active.
9368 0 : masm.storePtr(obj, Address(niTemp, offsetof(NativeIterator, obj)));
9369 0 : masm.or32(Imm32(JSITER_ACTIVE), Address(niTemp, offsetof(NativeIterator, flags)));
9370 :
9371 : // Post-write barrier for stores to 'obj'. The iterator JSObject is never
9372 : // nursery allocated. Put this in the whole cell buffer is we wrote a
9373 : // nursery pointer into it.
9374 : {
9375 0 : Label skipBarrier;
9376 0 : masm.branchPtrInNurseryChunk(Assembler::NotEqual, obj, temp1, &skipBarrier);
9377 :
9378 0 : LiveRegisterSet temps;
9379 0 : temps.add(temp1);
9380 0 : temps.add(temp2);
9381 0 : saveVolatile(temps);
9382 0 : emitPostWriteBarrier(output);
9383 0 : restoreVolatile(temps);
9384 0 : masm.bind(&skipBarrier);
9385 : }
9386 :
9387 : // Chain onto the active iterator stack.
9388 0 : masm.loadPtr(AbsoluteAddress(gen->compartment->addressOfEnumerators()), temp1);
9389 :
9390 : // ni->next = list
9391 0 : masm.storePtr(temp1, Address(niTemp, NativeIterator::offsetOfNext()));
9392 :
9393 : // ni->prev = list->prev
9394 0 : masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), temp2);
9395 0 : masm.storePtr(temp2, Address(niTemp, NativeIterator::offsetOfPrev()));
9396 :
9397 : // list->prev->next = ni
9398 0 : masm.storePtr(niTemp, Address(temp2, NativeIterator::offsetOfNext()));
9399 :
9400 : // list->prev = ni
9401 0 : masm.storePtr(niTemp, Address(temp1, NativeIterator::offsetOfPrev()));
9402 :
9403 0 : masm.bind(ool->rejoin());
9404 0 : }
9405 :
9406 : static void
9407 0 : LoadNativeIterator(MacroAssembler& masm, Register obj, Register dest, Label* failures)
9408 : {
9409 0 : MOZ_ASSERT(obj != dest);
9410 :
9411 : // Test class.
9412 0 : masm.branchTestObjClass(Assembler::NotEqual, obj, dest, &PropertyIteratorObject::class_, failures);
9413 :
9414 : // Load NativeIterator object.
9415 0 : masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, dest);
9416 0 : }
9417 :
9418 : typedef bool (*IteratorMoreFn)(JSContext*, HandleObject, MutableHandleValue);
9419 3 : static const VMFunction IteratorMoreInfo =
9420 6 : FunctionInfo<IteratorMoreFn>(IteratorMore, "IteratorMore");
9421 :
9422 : void
9423 0 : CodeGenerator::visitIteratorMore(LIteratorMore* lir)
9424 : {
9425 0 : const Register obj = ToRegister(lir->object());
9426 0 : const ValueOperand output = ToOutValue(lir);
9427 0 : const Register temp = ToRegister(lir->temp());
9428 :
9429 0 : OutOfLineCode* ool = oolCallVM(IteratorMoreInfo, lir, ArgList(obj), StoreValueTo(output));
9430 :
9431 0 : Register outputScratch = output.scratchReg();
9432 0 : LoadNativeIterator(masm, obj, outputScratch, ool->entry());
9433 :
9434 0 : masm.branchTest32(Assembler::NonZero, Address(outputScratch, offsetof(NativeIterator, flags)),
9435 0 : Imm32(JSITER_FOREACH), ool->entry());
9436 :
9437 : // If props_cursor < props_end, load the next string and advance the cursor.
9438 : // Else, return MagicValue(JS_NO_ITER_VALUE).
9439 0 : Label iterDone;
9440 0 : Address cursorAddr(outputScratch, offsetof(NativeIterator, props_cursor));
9441 0 : Address cursorEndAddr(outputScratch, offsetof(NativeIterator, props_end));
9442 0 : masm.loadPtr(cursorAddr, temp);
9443 0 : masm.branchPtr(Assembler::BelowOrEqual, cursorEndAddr, temp, &iterDone);
9444 :
9445 : // Get next string.
9446 0 : masm.loadPtr(Address(temp, 0), temp);
9447 :
9448 : // Increase the cursor.
9449 0 : masm.addPtr(Imm32(sizeof(JSString*)), cursorAddr);
9450 :
9451 0 : masm.tagValue(JSVAL_TYPE_STRING, temp, output);
9452 0 : masm.jump(ool->rejoin());
9453 :
9454 0 : masm.bind(&iterDone);
9455 0 : masm.moveValue(MagicValue(JS_NO_ITER_VALUE), output);
9456 :
9457 0 : masm.bind(ool->rejoin());
9458 0 : }
9459 :
9460 : void
9461 0 : CodeGenerator::visitIsNoIterAndBranch(LIsNoIterAndBranch* lir)
9462 : {
9463 0 : ValueOperand input = ToValue(lir, LIsNoIterAndBranch::Input);
9464 0 : Label* ifTrue = getJumpLabelForBranch(lir->ifTrue());
9465 0 : Label* ifFalse = getJumpLabelForBranch(lir->ifFalse());
9466 :
9467 0 : masm.branchTestMagic(Assembler::Equal, input, ifTrue);
9468 :
9469 0 : if (!isNextBlock(lir->ifFalse()->lir()))
9470 0 : masm.jump(ifFalse);
9471 0 : }
9472 :
9473 : typedef bool (*CloseIteratorFn)(JSContext*, HandleObject);
9474 3 : static const VMFunction CloseIteratorInfo =
9475 6 : FunctionInfo<CloseIteratorFn>(CloseIterator, "CloseIterator");
9476 :
9477 : void
9478 0 : CodeGenerator::visitIteratorEnd(LIteratorEnd* lir)
9479 : {
9480 0 : const Register obj = ToRegister(lir->object());
9481 0 : const Register temp1 = ToRegister(lir->temp1());
9482 0 : const Register temp2 = ToRegister(lir->temp2());
9483 0 : const Register temp3 = ToRegister(lir->temp3());
9484 :
9485 0 : OutOfLineCode* ool = oolCallVM(CloseIteratorInfo, lir, ArgList(obj), StoreNothing());
9486 :
9487 0 : LoadNativeIterator(masm, obj, temp1, ool->entry());
9488 :
9489 0 : masm.branchTest32(Assembler::Zero, Address(temp1, offsetof(NativeIterator, flags)),
9490 0 : Imm32(JSITER_ENUMERATE), ool->entry());
9491 :
9492 : // Clear active bit.
9493 0 : masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
9494 :
9495 : // Reset property cursor.
9496 0 : masm.loadPtr(Address(temp1, offsetof(NativeIterator, props_array)), temp2);
9497 0 : masm.storePtr(temp2, Address(temp1, offsetof(NativeIterator, props_cursor)));
9498 :
9499 : // Unlink from the iterator list.
9500 0 : const Register next = temp2;
9501 0 : const Register prev = temp3;
9502 0 : masm.loadPtr(Address(temp1, NativeIterator::offsetOfNext()), next);
9503 0 : masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), prev);
9504 0 : masm.storePtr(prev, Address(next, NativeIterator::offsetOfPrev()));
9505 0 : masm.storePtr(next, Address(prev, NativeIterator::offsetOfNext()));
9506 : #ifdef DEBUG
9507 0 : masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfNext()));
9508 0 : masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfPrev()));
9509 : #endif
9510 :
9511 0 : masm.bind(ool->rejoin());
9512 0 : }
9513 :
9514 : void
9515 2 : CodeGenerator::visitArgumentsLength(LArgumentsLength* lir)
9516 : {
9517 : // read number of actual arguments from the JS frame.
9518 2 : Register argc = ToRegister(lir->output());
9519 2 : Address ptr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfNumActualArgs());
9520 :
9521 2 : masm.loadPtr(ptr, argc);
9522 2 : }
9523 :
9524 : void
9525 1 : CodeGenerator::visitGetFrameArgument(LGetFrameArgument* lir)
9526 : {
9527 1 : ValueOperand result = GetValueOutput(lir);
9528 1 : const LAllocation* index = lir->index();
9529 1 : size_t argvOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
9530 :
9531 1 : if (index->isConstant()) {
9532 1 : int32_t i = index->toConstant()->toInt32();
9533 1 : Address argPtr(masm.getStackPointer(), sizeof(Value) * i + argvOffset);
9534 1 : masm.loadValue(argPtr, result);
9535 : } else {
9536 0 : Register i = ToRegister(index);
9537 0 : BaseValueIndex argPtr(masm.getStackPointer(), i, argvOffset);
9538 0 : masm.loadValue(argPtr, result);
9539 : }
9540 1 : }
9541 :
9542 : void
9543 0 : CodeGenerator::visitSetFrameArgumentT(LSetFrameArgumentT* lir)
9544 : {
9545 0 : size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
9546 0 : (sizeof(Value) * lir->mir()->argno());
9547 :
9548 0 : MIRType type = lir->mir()->value()->type();
9549 :
9550 0 : if (type == MIRType::Double) {
9551 : // Store doubles directly.
9552 0 : FloatRegister input = ToFloatRegister(lir->input());
9553 0 : masm.storeDouble(input, Address(masm.getStackPointer(), argOffset));
9554 :
9555 : } else {
9556 0 : Register input = ToRegister(lir->input());
9557 0 : masm.storeValue(ValueTypeFromMIRType(type), input, Address(masm.getStackPointer(), argOffset));
9558 : }
9559 0 : }
9560 :
9561 : void
9562 0 : CodeGenerator:: visitSetFrameArgumentC(LSetFrameArgumentC* lir)
9563 : {
9564 0 : size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
9565 0 : (sizeof(Value) * lir->mir()->argno());
9566 0 : masm.storeValue(lir->val(), Address(masm.getStackPointer(), argOffset));
9567 0 : }
9568 :
9569 : void
9570 0 : CodeGenerator:: visitSetFrameArgumentV(LSetFrameArgumentV* lir)
9571 : {
9572 0 : const ValueOperand val = ToValue(lir, LSetFrameArgumentV::Input);
9573 0 : size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
9574 0 : (sizeof(Value) * lir->mir()->argno());
9575 0 : masm.storeValue(val, Address(masm.getStackPointer(), argOffset));
9576 0 : }
9577 :
9578 : typedef bool (*RunOnceScriptPrologueFn)(JSContext*, HandleScript);
9579 3 : static const VMFunction RunOnceScriptPrologueInfo =
9580 6 : FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue, "RunOnceScriptPrologue");
9581 :
9582 : void
9583 0 : CodeGenerator::visitRunOncePrologue(LRunOncePrologue* lir)
9584 : {
9585 0 : pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
9586 0 : callVM(RunOnceScriptPrologueInfo, lir);
9587 0 : }
9588 :
9589 : typedef JSObject* (*InitRestParameterFn)(JSContext*, uint32_t, Value*, HandleObject,
9590 : HandleObject);
9591 3 : static const VMFunction InitRestParameterInfo =
9592 6 : FunctionInfo<InitRestParameterFn>(InitRestParameter, "InitRestParameter");
9593 :
9594 : void
9595 1 : CodeGenerator::emitRest(LInstruction* lir, Register array, Register numActuals,
9596 : Register temp0, Register temp1, unsigned numFormals,
9597 : JSObject* templateObject, bool saveAndRestore, Register resultreg)
9598 : {
9599 : // Compute actuals() + numFormals.
9600 1 : size_t actualsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
9601 1 : masm.moveStackPtrTo(temp1);
9602 1 : masm.addPtr(Imm32(sizeof(Value) * numFormals + actualsOffset), temp1);
9603 :
9604 : // Compute numActuals - numFormals.
9605 2 : Label emptyLength, joinLength;
9606 1 : masm.movePtr(numActuals, temp0);
9607 1 : masm.branch32(Assembler::LessThanOrEqual, temp0, Imm32(numFormals), &emptyLength);
9608 1 : masm.sub32(Imm32(numFormals), temp0);
9609 1 : masm.jump(&joinLength);
9610 : {
9611 1 : masm.bind(&emptyLength);
9612 1 : masm.move32(Imm32(0), temp0);
9613 : }
9614 1 : masm.bind(&joinLength);
9615 :
9616 1 : if (saveAndRestore)
9617 0 : saveLive(lir);
9618 :
9619 1 : pushArg(array);
9620 1 : pushArg(ImmGCPtr(templateObject));
9621 1 : pushArg(temp1);
9622 1 : pushArg(temp0);
9623 :
9624 1 : callVM(InitRestParameterInfo, lir);
9625 :
9626 1 : if (saveAndRestore) {
9627 0 : storeResultTo(resultreg);
9628 0 : restoreLive(lir);
9629 : }
9630 1 : }
9631 :
9632 : void
9633 1 : CodeGenerator::visitRest(LRest* lir)
9634 : {
9635 1 : Register numActuals = ToRegister(lir->numActuals());
9636 1 : Register temp0 = ToRegister(lir->getTemp(0));
9637 1 : Register temp1 = ToRegister(lir->getTemp(1));
9638 1 : Register temp2 = ToRegister(lir->getTemp(2));
9639 1 : unsigned numFormals = lir->mir()->numFormals();
9640 1 : ArrayObject* templateObject = lir->mir()->templateObject();
9641 :
9642 2 : Label joinAlloc, failAlloc;
9643 1 : masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
9644 1 : masm.jump(&joinAlloc);
9645 : {
9646 1 : masm.bind(&failAlloc);
9647 1 : masm.movePtr(ImmPtr(nullptr), temp2);
9648 : }
9649 1 : masm.bind(&joinAlloc);
9650 :
9651 1 : emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, false, ToRegister(lir->output()));
9652 1 : }
9653 :
9654 : bool
9655 0 : CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffset,
9656 : wasm::FuncOffsets* offsets)
9657 : {
9658 0 : JitSpew(JitSpew_Codegen, "# Emitting wasm code");
9659 :
9660 0 : wasm::GenerateFunctionPrologue(masm, frameSize(), sigId, offsets);
9661 :
9662 : // Overflow checks are omitted by CodeGenerator in some cases (leaf
9663 : // functions with small framePushed). Perform overflow-checking after
9664 : // pushing framePushed to catch cases with really large frames.
9665 0 : Label onOverflow;
9666 0 : if (!omitOverRecursedCheck())
9667 0 : masm.wasmEmitStackCheck(masm.getStackPointer(), ABINonArgReg0, &onOverflow);
9668 :
9669 0 : if (!generateBody())
9670 0 : return false;
9671 :
9672 0 : masm.bind(&returnLabel_);
9673 0 : wasm::GenerateFunctionEpilogue(masm, frameSize(), offsets);
9674 :
9675 0 : if (!omitOverRecursedCheck()) {
9676 : // Since we just overflowed the stack, to be on the safe side, pop the
9677 : // stack so that, when the trap exit stub executes, it is a safe
9678 : // distance away from the end of the native stack.
9679 0 : wasm::TrapDesc trap(trapOffset, wasm::Trap::StackOverflow, /* framePushed = */ 0);
9680 0 : if (frameSize() > 0) {
9681 0 : masm.bind(&onOverflow);
9682 0 : masm.addToStackPtr(Imm32(frameSize()));
9683 0 : masm.jump(trap);
9684 : } else {
9685 0 : masm.bindLater(&onOverflow, trap);
9686 : }
9687 : }
9688 :
9689 : #if defined(JS_ION_PERF)
9690 : // Note the end of the inline code and start of the OOL code.
9691 : gen->perfSpewer().noteEndInlineCode(masm);
9692 : #endif
9693 :
9694 0 : if (!generateOutOfLineCode())
9695 0 : return false;
9696 :
9697 0 : masm.wasmEmitTrapOutOfLineCode();
9698 :
9699 0 : masm.flush();
9700 0 : if (masm.oom())
9701 0 : return false;
9702 :
9703 0 : offsets->end = masm.currentOffset();
9704 :
9705 0 : MOZ_ASSERT(!masm.failureLabel()->used());
9706 0 : MOZ_ASSERT(snapshots_.listSize() == 0);
9707 0 : MOZ_ASSERT(snapshots_.RVATableSize() == 0);
9708 0 : MOZ_ASSERT(recovers_.size() == 0);
9709 0 : MOZ_ASSERT(bailouts_.empty());
9710 0 : MOZ_ASSERT(graph.numConstants() == 0);
9711 0 : MOZ_ASSERT(safepointIndices_.empty());
9712 0 : MOZ_ASSERT(osiIndices_.empty());
9713 0 : MOZ_ASSERT(icList_.empty());
9714 0 : MOZ_ASSERT(safepoints_.size() == 0);
9715 0 : MOZ_ASSERT(!scriptCounts_);
9716 0 : return true;
9717 : }
9718 :
9719 : bool
9720 8 : CodeGenerator::generate()
9721 : {
9722 16 : JitSpew(JitSpew_Codegen, "# Emitting code for script %s:%" PRIuSIZE,
9723 8 : gen->info().script()->filename(),
9724 16 : gen->info().script()->lineno());
9725 :
9726 : // Initialize native code table with an entry to the start of
9727 : // top-level script.
9728 8 : InlineScriptTree* tree = gen->info().inlineScriptTree();
9729 8 : jsbytecode* startPC = tree->script()->code();
9730 8 : BytecodeSite* startSite = new(gen->alloc()) BytecodeSite(tree, startPC);
9731 8 : if (!addNativeToBytecodeEntry(startSite))
9732 0 : return false;
9733 :
9734 8 : if (!snapshots_.init())
9735 0 : return false;
9736 :
9737 8 : if (!safepoints_.init(gen->alloc()))
9738 0 : return false;
9739 :
9740 8 : if (!generatePrologue())
9741 0 : return false;
9742 :
9743 : // Before generating any code, we generate type checks for all parameters.
9744 : // This comes before deoptTable_, because we can't use deopt tables without
9745 : // creating the actual frame.
9746 8 : generateArgumentsChecks();
9747 :
9748 8 : if (frameClass_ != FrameSizeClass::None()) {
9749 0 : deoptTable_ = gen->jitRuntime()->getBailoutTable(frameClass_);
9750 0 : if (!deoptTable_)
9751 0 : return false;
9752 : }
9753 :
9754 : // Skip over the alternative entry to IonScript code.
9755 16 : Label skipPrologue;
9756 8 : masm.jump(&skipPrologue);
9757 :
9758 : // An alternative entry to the IonScript code, which doesn't test the
9759 : // arguments.
9760 8 : masm.flushBuffer();
9761 8 : setSkipArgCheckEntryOffset(masm.size());
9762 8 : masm.setFramePushed(0);
9763 8 : if (!generatePrologue())
9764 0 : return false;
9765 :
9766 8 : masm.bind(&skipPrologue);
9767 :
9768 : #ifdef DEBUG
9769 : // Assert that the argument types are correct.
9770 8 : generateArgumentsChecks(/* bailout = */ false);
9771 : #endif
9772 :
9773 : // Reset native => bytecode map table with top-level script and startPc.
9774 8 : if (!addNativeToBytecodeEntry(startSite))
9775 0 : return false;
9776 :
9777 8 : if (!generateBody())
9778 0 : return false;
9779 :
9780 : // Reset native => bytecode map table with top-level script and startPc.
9781 8 : if (!addNativeToBytecodeEntry(startSite))
9782 0 : return false;
9783 :
9784 8 : if (!generateEpilogue())
9785 0 : return false;
9786 :
9787 : // Reset native => bytecode map table with top-level script and startPc.
9788 8 : if (!addNativeToBytecodeEntry(startSite))
9789 0 : return false;
9790 :
9791 8 : generateInvalidateEpilogue();
9792 : #if defined(JS_ION_PERF)
9793 : // Note the end of the inline code and start of the OOL code.
9794 : perfSpewer_.noteEndInlineCode(masm);
9795 : #endif
9796 :
9797 : // native => bytecode entries for OOL code will be added
9798 : // by CodeGeneratorShared::generateOutOfLineCode
9799 8 : if (!generateOutOfLineCode())
9800 0 : return false;
9801 :
9802 : // Add terminal entry.
9803 8 : if (!addNativeToBytecodeEntry(startSite))
9804 0 : return false;
9805 :
9806 : // Dump Native to bytecode entries to spew.
9807 8 : dumpNativeToBytecodeEntries();
9808 :
9809 8 : return !masm.oom();
9810 : }
9811 :
9812 : bool
9813 7 : CodeGenerator::linkSharedStubs(JSContext* cx)
9814 : {
9815 7 : for (uint32_t i = 0; i < sharedStubs_.length(); i++) {
9816 0 : ICStub *stub = nullptr;
9817 :
9818 0 : switch (sharedStubs_[i].kind) {
9819 : case ICStub::Kind::BinaryArith_Fallback: {
9820 0 : ICBinaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
9821 0 : stub = stubCompiler.getStub(&stubSpace_);
9822 0 : break;
9823 : }
9824 : case ICStub::Kind::UnaryArith_Fallback: {
9825 0 : ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
9826 0 : stub = stubCompiler.getStub(&stubSpace_);
9827 0 : break;
9828 : }
9829 : case ICStub::Kind::Compare_Fallback: {
9830 0 : ICCompare_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
9831 0 : stub = stubCompiler.getStub(&stubSpace_);
9832 0 : break;
9833 : }
9834 : case ICStub::Kind::GetProp_Fallback: {
9835 0 : ICGetProp_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
9836 0 : stub = stubCompiler.getStub(&stubSpace_);
9837 0 : break;
9838 : }
9839 : case ICStub::Kind::NewArray_Fallback: {
9840 0 : JSScript* script = sharedStubs_[i].entry.script();
9841 0 : jsbytecode* pc = sharedStubs_[i].entry.pc(script);
9842 0 : ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
9843 0 : if (!group)
9844 0 : return false;
9845 :
9846 0 : ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::IonSharedIC);
9847 0 : stub = stubCompiler.getStub(&stubSpace_);
9848 0 : break;
9849 : }
9850 : case ICStub::Kind::NewObject_Fallback: {
9851 0 : ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
9852 0 : stub = stubCompiler.getStub(&stubSpace_);
9853 0 : break;
9854 : }
9855 : default:
9856 0 : MOZ_CRASH("Unsupported shared stub.");
9857 : }
9858 :
9859 0 : if (!stub)
9860 0 : return false;
9861 :
9862 0 : sharedStubs_[i].entry.setFirstStub(stub);
9863 : }
9864 7 : return true;
9865 : }
9866 :
9867 : bool
9868 7 : CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
9869 : {
9870 14 : RootedScript script(cx, gen->info().script());
9871 7 : OptimizationLevel optimizationLevel = gen->optimizationInfo().level();
9872 :
9873 : // Capture the SIMD template objects which are used during the
9874 : // compilation. This iterates over the template objects, using read-barriers
9875 : // to let the GC know that the generated code relies on these template
9876 : // objects.
9877 7 : captureSimdTemplate(cx);
9878 :
9879 : // We finished the new IonScript. Invalidate the current active IonScript,
9880 : // so we can replace it with this new (probably higher optimized) version.
9881 7 : if (script->hasIonScript()) {
9882 0 : MOZ_ASSERT(script->ionScript()->isRecompiling());
9883 : // Do a normal invalidate, except don't cancel offThread compilations,
9884 : // since that will cancel this compilation too.
9885 0 : Invalidate(cx, script, /* resetUses */ false, /* cancelOffThread*/ false);
9886 : }
9887 :
9888 7 : if (scriptCounts_ && !script->hasScriptCounts() && !script->initScriptCounts(cx))
9889 0 : return false;
9890 :
9891 7 : if (!linkSharedStubs(cx))
9892 0 : return false;
9893 :
9894 : // Check to make sure we didn't have a mid-build invalidation. If so, we
9895 : // will trickle to jit::Compile() and return Method_Skipped.
9896 7 : uint32_t warmUpCount = script->getWarmUpCount();
9897 :
9898 : // Record constraints. If an error occured, returns false and potentially
9899 : // prevent future compilations. Otherwise, if an invalidation occured, then
9900 : // skip the current compilation.
9901 7 : RecompileInfo recompileInfo;
9902 7 : bool validRecompiledInfo = false;
9903 7 : if (!FinishCompilation(cx, script, constraints, &recompileInfo, &validRecompiledInfo))
9904 0 : return false;
9905 7 : if (!validRecompiledInfo)
9906 2 : return true;
9907 0 : auto guardRecordedConstraints = mozilla::MakeScopeExit([&] {
9908 : // In case of error, invalidate the current recompileInfo.
9909 0 : recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
9910 10 : });
9911 :
9912 : // IonMonkey could have inferred better type information during
9913 : // compilation. Since adding the new information to the actual type
9914 : // information can reset the usecount, increase it back to what it was
9915 : // before.
9916 5 : if (warmUpCount > script->getWarmUpCount())
9917 0 : script->incWarmUpCounter(warmUpCount - script->getWarmUpCount());
9918 :
9919 5 : uint32_t argumentSlots = (gen->info().nargs() + 1) * sizeof(Value);
9920 10 : uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
9921 5 : ? frameDepth_
9922 5 : : FrameSizeClass::FromDepth(frameDepth_).frameSize();
9923 :
9924 : // We encode safepoints after the OSI-point offsets have been determined.
9925 5 : if (!encodeSafepoints())
9926 0 : return false;
9927 :
9928 : IonScript* ionScript =
9929 15 : IonScript::New(cx, recompileInfo,
9930 5 : graph.totalSlotCount(), argumentSlots, scriptFrameSize,
9931 : snapshots_.listSize(), snapshots_.RVATableSize(),
9932 5 : recovers_.size(), bailouts_.length(), graph.numConstants(),
9933 : safepointIndices_.length(), osiIndices_.length(),
9934 : icList_.length(), runtimeData_.length(),
9935 : safepoints_.size(), patchableBackedges_.length(),
9936 5 : sharedStubs_.length(), optimizationLevel);
9937 5 : if (!ionScript)
9938 0 : return false;
9939 0 : auto guardIonScript = mozilla::MakeScopeExit([&ionScript] {
9940 : // Use js_free instead of IonScript::Destroy: the cache list and
9941 : // backedge list are still uninitialized.
9942 0 : js_free(ionScript);
9943 10 : });
9944 :
9945 : // Also, note that creating the code here during an incremental GC will
9946 : // trace the code and mark all GC things it refers to. This captures any
9947 : // read barriers which were skipped while compiling the script off thread.
9948 10 : Linker linker(masm);
9949 10 : AutoFlushICache afc("IonLink");
9950 5 : JitCode* code = linker.newCode<CanGC>(cx, ION_CODE, !patchableBackedges_.empty());
9951 5 : if (!code)
9952 0 : return false;
9953 :
9954 : // Encode native to bytecode map if profiling is enabled.
9955 5 : if (isProfilerInstrumentationEnabled()) {
9956 : // Generate native-to-bytecode main table.
9957 0 : if (!generateCompactNativeToBytecodeMap(cx, code))
9958 0 : return false;
9959 :
9960 0 : uint8_t* ionTableAddr = ((uint8_t*) nativeToBytecodeMap_) + nativeToBytecodeTableOffset_;
9961 0 : JitcodeIonTable* ionTable = (JitcodeIonTable*) ionTableAddr;
9962 :
9963 : // Construct the IonEntry that will go into the global table.
9964 : JitcodeGlobalEntry::IonEntry entry;
9965 0 : if (!ionTable->makeIonEntry(cx, code, nativeToBytecodeScriptListLength_,
9966 : nativeToBytecodeScriptList_, entry))
9967 : {
9968 0 : js_free(nativeToBytecodeScriptList_);
9969 0 : js_free(nativeToBytecodeMap_);
9970 0 : return false;
9971 : }
9972 :
9973 : // nativeToBytecodeScriptList_ is no longer needed.
9974 0 : js_free(nativeToBytecodeScriptList_);
9975 :
9976 : // Generate the tracked optimizations map.
9977 0 : if (isOptimizationTrackingEnabled()) {
9978 : // Treat OOMs and failures as if optimization tracking were turned off.
9979 0 : IonTrackedTypeVector* allTypes = cx->new_<IonTrackedTypeVector>();
9980 0 : if (allTypes && generateCompactTrackedOptimizationsMap(cx, code, allTypes)) {
9981 0 : const uint8_t* optsRegionTableAddr = trackedOptimizationsMap_ +
9982 0 : trackedOptimizationsRegionTableOffset_;
9983 : const IonTrackedOptimizationsRegionTable* optsRegionTable =
9984 0 : (const IonTrackedOptimizationsRegionTable*) optsRegionTableAddr;
9985 0 : const uint8_t* optsTypesTableAddr = trackedOptimizationsMap_ +
9986 0 : trackedOptimizationsTypesTableOffset_;
9987 : const IonTrackedOptimizationsTypesTable* optsTypesTable =
9988 0 : (const IonTrackedOptimizationsTypesTable*) optsTypesTableAddr;
9989 0 : const uint8_t* optsAttemptsTableAddr = trackedOptimizationsMap_ +
9990 0 : trackedOptimizationsAttemptsTableOffset_;
9991 : const IonTrackedOptimizationsAttemptsTable* optsAttemptsTable =
9992 0 : (const IonTrackedOptimizationsAttemptsTable*) optsAttemptsTableAddr;
9993 : entry.initTrackedOptimizations(optsRegionTable, optsTypesTable, optsAttemptsTable,
9994 0 : allTypes);
9995 : } else {
9996 0 : cx->recoverFromOutOfMemory();
9997 : }
9998 : }
9999 :
10000 : // Add entry to the global table.
10001 0 : JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
10002 0 : if (!globalTable->addEntry(entry, cx->runtime())) {
10003 : // Memory may have been allocated for the entry.
10004 0 : entry.destroy();
10005 0 : return false;
10006 : }
10007 :
10008 : // Mark the jitcode as having a bytecode map.
10009 0 : code->setHasBytecodeMap();
10010 : } else {
10011 : // Add a dumy jitcodeGlobalTable entry.
10012 : JitcodeGlobalEntry::DummyEntry entry;
10013 5 : entry.init(code, code->raw(), code->rawEnd());
10014 :
10015 : // Add entry to the global table.
10016 5 : JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
10017 5 : if (!globalTable->addEntry(entry, cx->runtime())) {
10018 : // Memory may have been allocated for the entry.
10019 0 : entry.destroy();
10020 0 : return false;
10021 : }
10022 :
10023 : // Mark the jitcode as having a bytecode map.
10024 5 : code->setHasBytecodeMap();
10025 : }
10026 :
10027 5 : ionScript->setMethod(code);
10028 5 : ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
10029 :
10030 : // If the Gecko Profiler is enabled, mark IonScript as having been
10031 : // instrumented accordingly.
10032 5 : if (isProfilerInstrumentationEnabled())
10033 0 : ionScript->setHasProfilingInstrumentation();
10034 :
10035 5 : script->setIonScript(cx->runtime(), ionScript);
10036 :
10037 : // Adopt fallback shared stubs from the compiler into the ion script.
10038 5 : ionScript->adoptFallbackStubs(&stubSpace_);
10039 :
10040 10 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
10041 : ImmPtr(ionScript),
10042 5 : ImmPtr((void*)-1));
10043 :
10044 105 : for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
10045 200 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
10046 : ImmPtr(ionScript),
10047 100 : ImmPtr((void*)-1));
10048 : }
10049 :
10050 : #ifdef JS_TRACE_LOGGING
10051 5 : bool TLFailed = false;
10052 :
10053 5 : for (uint32_t i = 0; i < patchableTLEvents_.length(); i++) {
10054 0 : TraceLoggerEvent event(patchableTLEvents_[i].event);
10055 0 : if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event)) {
10056 0 : TLFailed = true;
10057 0 : break;
10058 : }
10059 0 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLEvents_[i].offset),
10060 0 : ImmPtr((void*) uintptr_t(event.textId())),
10061 0 : ImmPtr((void*)0));
10062 : }
10063 :
10064 5 : if (!TLFailed && patchableTLScripts_.length() > 0) {
10065 0 : MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
10066 0 : TraceLoggerEvent event(TraceLogger_Scripts, script);
10067 0 : if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event))
10068 0 : TLFailed = true;
10069 0 : if (!TLFailed) {
10070 0 : uint32_t textId = event.textId();
10071 0 : for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
10072 0 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
10073 0 : ImmPtr((void*) uintptr_t(textId)),
10074 0 : ImmPtr((void*)0));
10075 : }
10076 : }
10077 : }
10078 : #endif
10079 :
10080 : // Patch shared stub IC loads using IC entries
10081 5 : for (size_t i = 0; i < sharedStubs_.length(); i++) {
10082 0 : CodeOffset label = sharedStubs_[i].label;
10083 :
10084 0 : IonICEntry& entry = ionScript->sharedStubList()[i];
10085 0 : entry = sharedStubs_[i].entry;
10086 0 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
10087 : ImmPtr(&entry),
10088 0 : ImmPtr((void*)-1));
10089 :
10090 0 : MOZ_ASSERT(entry.hasStub());
10091 0 : MOZ_ASSERT(entry.firstStub()->isFallback());
10092 :
10093 0 : entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
10094 : }
10095 :
10096 : // for generating inline caches during the execution.
10097 5 : if (runtimeData_.length())
10098 4 : ionScript->copyRuntimeData(&runtimeData_[0]);
10099 5 : if (icList_.length())
10100 4 : ionScript->copyICEntries(&icList_[0], masm);
10101 :
10102 19 : for (size_t i = 0; i < icInfo_.length(); i++) {
10103 14 : IonIC& ic = ionScript->getICFromIndex(i);
10104 42 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForJump),
10105 14 : ImmPtr(ic.codeRawPtr()),
10106 14 : ImmPtr((void*)-1));
10107 28 : Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForPush),
10108 : ImmPtr(&ic),
10109 14 : ImmPtr((void*)-1));
10110 : }
10111 :
10112 5 : JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
10113 10 : (void*) ionScript, (void*) code->raw());
10114 :
10115 5 : ionScript->setInvalidationEpilogueDataOffset(invalidateEpilogueData_.offset());
10116 5 : ionScript->setOsrPc(gen->info().osrPc());
10117 5 : ionScript->setOsrEntryOffset(getOsrEntryOffset());
10118 5 : ionScript->setInvalidationEpilogueOffset(invalidate_.offset());
10119 :
10120 5 : ionScript->setDeoptTable(deoptTable_);
10121 :
10122 : #if defined(JS_ION_PERF)
10123 : if (PerfEnabled())
10124 : perfSpewer_.writeProfile(script, code, masm);
10125 : #endif
10126 :
10127 : #ifdef MOZ_VTUNE
10128 5 : vtune::MarkScript(code, script, "ion");
10129 : #endif
10130 :
10131 : // for marking during GC.
10132 5 : if (safepointIndices_.length())
10133 4 : ionScript->copySafepointIndices(&safepointIndices_[0], masm);
10134 5 : if (safepoints_.size())
10135 4 : ionScript->copySafepoints(&safepoints_);
10136 :
10137 : // for reconvering from an Ion Frame.
10138 5 : if (bailouts_.length())
10139 0 : ionScript->copyBailoutTable(&bailouts_[0]);
10140 5 : if (osiIndices_.length())
10141 5 : ionScript->copyOsiIndices(&osiIndices_[0], masm);
10142 5 : if (snapshots_.listSize())
10143 5 : ionScript->copySnapshots(&snapshots_);
10144 5 : MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
10145 5 : if (recovers_.size())
10146 5 : ionScript->copyRecovers(&recovers_);
10147 5 : if (graph.numConstants()) {
10148 3 : const Value* vp = graph.constantPool();
10149 3 : ionScript->copyConstants(vp);
10150 18 : for (size_t i = 0; i < graph.numConstants(); i++) {
10151 15 : const Value& v = vp[i];
10152 15 : if (v.isObject() && IsInsideNursery(&v.toObject())) {
10153 0 : cx->zone()->group()->storeBuffer().putWholeCell(script);
10154 0 : break;
10155 : }
10156 : }
10157 : }
10158 5 : if (patchableBackedges_.length() > 0)
10159 0 : ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
10160 :
10161 : // Attach any generated script counts to the script.
10162 5 : if (IonScriptCounts* counts = extractScriptCounts())
10163 0 : script->addIonCounts(counts);
10164 :
10165 5 : guardIonScript.release();
10166 5 : guardRecordedConstraints.release();
10167 5 : return true;
10168 : }
10169 :
10170 : // An out-of-line path to convert a boxed int32 to either a float or double.
10171 : class OutOfLineUnboxFloatingPoint : public OutOfLineCodeBase<CodeGenerator>
10172 : {
10173 : LUnboxFloatingPoint* unboxFloatingPoint_;
10174 :
10175 : public:
10176 0 : explicit OutOfLineUnboxFloatingPoint(LUnboxFloatingPoint* unboxFloatingPoint)
10177 0 : : unboxFloatingPoint_(unboxFloatingPoint)
10178 0 : { }
10179 :
10180 0 : void accept(CodeGenerator* codegen) {
10181 0 : codegen->visitOutOfLineUnboxFloatingPoint(this);
10182 0 : }
10183 :
10184 0 : LUnboxFloatingPoint* unboxFloatingPoint() const {
10185 0 : return unboxFloatingPoint_;
10186 : }
10187 : };
10188 :
10189 : void
10190 0 : CodeGenerator::visitUnboxFloatingPoint(LUnboxFloatingPoint* lir)
10191 : {
10192 0 : const ValueOperand box = ToValue(lir, LUnboxFloatingPoint::Input);
10193 0 : const LDefinition* result = lir->output();
10194 :
10195 : // Out-of-line path to convert int32 to double or bailout
10196 : // if this instruction is fallible.
10197 0 : OutOfLineUnboxFloatingPoint* ool = new(alloc()) OutOfLineUnboxFloatingPoint(lir);
10198 0 : addOutOfLineCode(ool, lir->mir());
10199 :
10200 0 : FloatRegister resultReg = ToFloatRegister(result);
10201 0 : masm.branchTestDouble(Assembler::NotEqual, box, ool->entry());
10202 0 : masm.unboxDouble(box, resultReg);
10203 0 : if (lir->type() == MIRType::Float32)
10204 0 : masm.convertDoubleToFloat32(resultReg, resultReg);
10205 0 : masm.bind(ool->rejoin());
10206 0 : }
10207 :
10208 : void
10209 0 : CodeGenerator::visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool)
10210 : {
10211 0 : LUnboxFloatingPoint* ins = ool->unboxFloatingPoint();
10212 0 : const ValueOperand value = ToValue(ins, LUnboxFloatingPoint::Input);
10213 :
10214 0 : if (ins->mir()->fallible()) {
10215 0 : Label bail;
10216 0 : masm.branchTestInt32(Assembler::NotEqual, value, &bail);
10217 0 : bailoutFrom(&bail, ins->snapshot());
10218 : }
10219 0 : masm.int32ValueToFloatingPoint(value, ToFloatRegister(ins->output()), ins->type());
10220 0 : masm.jump(ool->rejoin());
10221 0 : }
10222 :
10223 : typedef JSObject* (*BindVarFn)(JSContext*, HandleObject);
10224 3 : static const VMFunction BindVarInfo = FunctionInfo<BindVarFn>(jit::BindVar, "BindVar");
10225 :
10226 : void
10227 0 : CodeGenerator::visitCallBindVar(LCallBindVar* lir)
10228 : {
10229 0 : pushArg(ToRegister(lir->environmentChain()));
10230 0 : callVM(BindVarInfo, lir);
10231 0 : }
10232 :
10233 : typedef bool (*GetPropertyFn)(JSContext*, HandleValue, HandlePropertyName, MutableHandleValue);
10234 3 : static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty, "GetProperty");
10235 :
10236 : void
10237 3 : CodeGenerator::visitCallGetProperty(LCallGetProperty* lir)
10238 : {
10239 3 : pushArg(ImmGCPtr(lir->mir()->name()));
10240 3 : pushArg(ToValue(lir, LCallGetProperty::Value));
10241 :
10242 3 : callVM(GetPropertyInfo, lir);
10243 3 : }
10244 :
10245 : typedef bool (*GetOrCallElementFn)(JSContext*, MutableHandleValue, HandleValue, MutableHandleValue);
10246 3 : static const VMFunction GetElementInfo =
10247 6 : FunctionInfo<GetOrCallElementFn>(js::GetElement, "GetElement");
10248 3 : static const VMFunction CallElementInfo =
10249 6 : FunctionInfo<GetOrCallElementFn>(js::CallElement, "CallElement");
10250 :
10251 : void
10252 0 : CodeGenerator::visitCallGetElement(LCallGetElement* lir)
10253 : {
10254 0 : pushArg(ToValue(lir, LCallGetElement::RhsInput));
10255 0 : pushArg(ToValue(lir, LCallGetElement::LhsInput));
10256 :
10257 0 : JSOp op = JSOp(*lir->mir()->resumePoint()->pc());
10258 :
10259 0 : if (op == JSOP_GETELEM) {
10260 0 : callVM(GetElementInfo, lir);
10261 : } else {
10262 0 : MOZ_ASSERT(op == JSOP_CALLELEM);
10263 0 : callVM(CallElementInfo, lir);
10264 : }
10265 0 : }
10266 :
10267 : typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue, HandleValue,
10268 : bool strict);
10269 3 : static const VMFunction SetObjectElementInfo =
10270 6 : FunctionInfo<SetObjectElementFn>(SetObjectElement, "SetObjectElement");
10271 :
10272 : void
10273 0 : CodeGenerator::visitCallSetElement(LCallSetElement* lir)
10274 : {
10275 0 : pushArg(Imm32(lir->mir()->strict()));
10276 0 : pushArg(ToValue(lir, LCallSetElement::Value));
10277 0 : pushArg(ToValue(lir, LCallSetElement::Index));
10278 0 : pushArg(ToRegister(lir->getOperand(0)));
10279 0 : callVM(SetObjectElementInfo, lir);
10280 0 : }
10281 :
10282 : typedef bool (*InitElementArrayFn)(JSContext*, jsbytecode*, HandleObject, uint32_t, HandleValue);
10283 3 : static const VMFunction InitElementArrayInfo =
10284 6 : FunctionInfo<InitElementArrayFn>(js::InitElementArray, "InitElementArray");
10285 :
10286 : void
10287 0 : CodeGenerator::visitCallInitElementArray(LCallInitElementArray* lir)
10288 : {
10289 0 : pushArg(ToValue(lir, LCallInitElementArray::Value));
10290 0 : if (lir->index()->isConstant())
10291 0 : pushArg(Imm32(ToInt32(lir->index())));
10292 : else
10293 0 : pushArg(ToRegister(lir->index()));
10294 0 : pushArg(ToRegister(lir->object()));
10295 0 : pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
10296 0 : callVM(InitElementArrayInfo, lir);
10297 0 : }
10298 :
10299 : void
10300 29 : CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV* ins)
10301 : {
10302 29 : const Register obj = ToRegister(ins->getOperand(0));
10303 29 : size_t slot = ins->mir()->slot();
10304 29 : ValueOperand result = GetValueOutput(ins);
10305 :
10306 29 : masm.loadValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), result);
10307 29 : }
10308 :
10309 : void
10310 5 : CodeGenerator::visitLoadFixedSlotT(LLoadFixedSlotT* ins)
10311 : {
10312 5 : const Register obj = ToRegister(ins->getOperand(0));
10313 5 : size_t slot = ins->mir()->slot();
10314 5 : AnyRegister result = ToAnyRegister(ins->getDef(0));
10315 5 : MIRType type = ins->mir()->type();
10316 :
10317 5 : masm.loadUnboxedValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), type, result);
10318 5 : }
10319 :
10320 : void
10321 1 : CodeGenerator::visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* ins)
10322 : {
10323 1 : const MLoadFixedSlotAndUnbox* mir = ins->mir();
10324 1 : MIRType type = mir->type();
10325 1 : const Register input = ToRegister(ins->getOperand(0));
10326 1 : AnyRegister result = ToAnyRegister(ins->output());
10327 1 : size_t slot = mir->slot();
10328 :
10329 1 : Address address(input, NativeObject::getFixedSlotOffset(slot));
10330 2 : Label bail;
10331 1 : if (type == MIRType::Double) {
10332 0 : MOZ_ASSERT(result.isFloat());
10333 0 : masm.ensureDouble(address, result.fpu(), &bail);
10334 0 : if (mir->fallible())
10335 0 : bailoutFrom(&bail, ins->snapshot());
10336 0 : return;
10337 : }
10338 1 : if (mir->fallible()) {
10339 1 : switch (type) {
10340 : case MIRType::Int32:
10341 1 : masm.branchTestInt32(Assembler::NotEqual, address, &bail);
10342 1 : break;
10343 : case MIRType::Boolean:
10344 0 : masm.branchTestBoolean(Assembler::NotEqual, address, &bail);
10345 0 : break;
10346 : default:
10347 0 : MOZ_CRASH("Given MIRType cannot be unboxed.");
10348 : }
10349 1 : bailoutFrom(&bail, ins->snapshot());
10350 : }
10351 1 : masm.loadUnboxedValue(address, type, result);
10352 : }
10353 :
10354 : void
10355 1 : CodeGenerator::visitStoreFixedSlotV(LStoreFixedSlotV* ins)
10356 : {
10357 1 : const Register obj = ToRegister(ins->getOperand(0));
10358 1 : size_t slot = ins->mir()->slot();
10359 :
10360 1 : const ValueOperand value = ToValue(ins, LStoreFixedSlotV::Value);
10361 :
10362 1 : Address address(obj, NativeObject::getFixedSlotOffset(slot));
10363 1 : if (ins->mir()->needsBarrier())
10364 1 : emitPreBarrier(address);
10365 :
10366 1 : masm.storeValue(value, address);
10367 1 : }
10368 :
10369 : void
10370 31 : CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT* ins)
10371 : {
10372 31 : const Register obj = ToRegister(ins->getOperand(0));
10373 31 : size_t slot = ins->mir()->slot();
10374 :
10375 31 : const LAllocation* value = ins->value();
10376 31 : MIRType valueType = ins->mir()->value()->type();
10377 :
10378 31 : Address address(obj, NativeObject::getFixedSlotOffset(slot));
10379 31 : if (ins->mir()->needsBarrier())
10380 22 : emitPreBarrier(address);
10381 :
10382 31 : if (valueType == MIRType::ObjectOrNull) {
10383 0 : Register nvalue = ToRegister(value);
10384 0 : masm.storeObjectOrNull(nvalue, address);
10385 : } else {
10386 31 : ConstantOrRegister nvalue = value->isConstant()
10387 71 : ? ConstantOrRegister(value->toConstant()->toJSValue())
10388 62 : : TypedOrValueRegister(valueType, ToAnyRegister(value));
10389 31 : masm.storeConstantOrRegister(nvalue, address);
10390 : }
10391 31 : }
10392 :
10393 : void
10394 4 : CodeGenerator::visitGetNameCache(LGetNameCache* ins)
10395 : {
10396 4 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10397 4 : Register envChain = ToRegister(ins->envObj());
10398 4 : ValueOperand output(GetValueOutput(ins));
10399 4 : Register temp = ToRegister(ins->temp());
10400 :
10401 4 : IonGetNameIC ic(liveRegs, envChain, output, temp);
10402 4 : addIC(ins, allocateIC(ic));
10403 4 : }
10404 :
10405 : void
10406 23 : CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
10407 : TypedOrValueRegister value, const ConstantOrRegister& id,
10408 : TypedOrValueRegister output, Register maybeTemp,
10409 : bool monitoredResult, bool allowDoubleResult,
10410 : jsbytecode* profilerLeavePc)
10411 : {
10412 23 : CacheKind kind = CacheKind::GetElem;
10413 23 : if (id.constant() && id.value().isString()) {
10414 11 : JSString* idString = id.value().toString();
10415 : uint32_t dummy;
10416 11 : if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
10417 11 : kind = CacheKind::GetProp;
10418 : }
10419 : IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, monitoredResult,
10420 23 : allowDoubleResult);
10421 23 : addIC(ins, allocateIC(cache));
10422 23 : }
10423 :
10424 : void
10425 6 : CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
10426 : Register temp, FloatRegister tempDouble,
10427 : FloatRegister tempF32, const ConstantOrRegister& id,
10428 : const ConstantOrRegister& value,
10429 : bool strict, bool needsPostBarrier, bool needsTypeBarrier,
10430 : bool guardHoles, jsbytecode* profilerLeavePc)
10431 : {
10432 6 : CacheKind kind = CacheKind::SetElem;
10433 6 : if (id.constant() && id.value().isString()) {
10434 6 : JSString* idString = id.value().toString();
10435 : uint32_t dummy;
10436 6 : if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
10437 6 : kind = CacheKind::SetProp;
10438 : }
10439 : IonSetPropertyIC cache(kind, liveRegs, objReg, temp, tempDouble, tempF32,
10440 6 : id, value, strict, needsPostBarrier, needsTypeBarrier, guardHoles);
10441 6 : addIC(ins, allocateIC(cache));
10442 6 : }
10443 :
10444 : ConstantOrRegister
10445 60 : CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type)
10446 : {
10447 60 : if (type == MIRType::Value)
10448 5 : return TypedOrValueRegister(ToValue(lir, n));
10449 :
10450 55 : const LAllocation* value = lir->getOperand(n);
10451 55 : if (value->isConstant())
10452 19 : return ConstantOrRegister(value->toConstant()->toJSValue());
10453 :
10454 36 : return TypedOrValueRegister(type, ToAnyRegister(value));
10455 : }
10456 :
10457 : void
10458 17 : CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
10459 : {
10460 17 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10461 : TypedOrValueRegister value =
10462 17 : toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
10463 17 : ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheV::Id, ins->mir()->idval()->type());
10464 17 : bool monitoredResult = ins->mir()->monitoredResult();
10465 17 : TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
10466 17 : Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
10467 :
10468 51 : addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
10469 51 : ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
10470 17 : }
10471 :
10472 : void
10473 6 : CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
10474 : {
10475 6 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10476 : TypedOrValueRegister value =
10477 6 : toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
10478 6 : ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheT::Id, ins->mir()->idval()->type());
10479 6 : bool monitoredResult = ins->mir()->monitoredResult();
10480 6 : TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
10481 6 : Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
10482 :
10483 18 : addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
10484 18 : ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
10485 6 : }
10486 :
10487 : void
10488 0 : CodeGenerator::visitBindNameCache(LBindNameCache* ins)
10489 : {
10490 0 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10491 0 : Register envChain = ToRegister(ins->environmentChain());
10492 0 : Register output = ToRegister(ins->output());
10493 0 : Register temp = ToRegister(ins->temp());
10494 :
10495 0 : IonBindNameIC ic(liveRegs, envChain, output, temp);
10496 0 : addIC(ins, allocateIC(ic));
10497 0 : }
10498 :
10499 : void
10500 0 : CodeGenerator::visitHasOwnCache(LHasOwnCache* ins)
10501 : {
10502 0 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10503 : TypedOrValueRegister value =
10504 0 : toConstantOrRegister(ins, LHasOwnCache::Value, ins->mir()->value()->type()).reg();
10505 : TypedOrValueRegister id =
10506 0 : toConstantOrRegister(ins, LHasOwnCache::Id, ins->mir()->idval()->type()).reg();
10507 0 : Register output = ToRegister(ins->output());
10508 :
10509 0 : IonHasOwnIC cache(liveRegs, value, id, output);
10510 0 : addIC(ins, allocateIC(cache));
10511 0 : }
10512 :
10513 : typedef bool (*SetPropertyFn)(JSContext*, HandleObject,
10514 : HandlePropertyName, const HandleValue, bool, jsbytecode*);
10515 3 : static const VMFunction SetPropertyInfo = FunctionInfo<SetPropertyFn>(SetProperty, "SetProperty");
10516 :
10517 : void
10518 0 : CodeGenerator::visitCallSetProperty(LCallSetProperty* ins)
10519 : {
10520 0 : ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
10521 :
10522 0 : const Register objReg = ToRegister(ins->getOperand(0));
10523 :
10524 0 : pushArg(ImmPtr(ins->mir()->resumePoint()->pc()));
10525 0 : pushArg(Imm32(ins->mir()->strict()));
10526 :
10527 0 : pushArg(value);
10528 0 : pushArg(ImmGCPtr(ins->mir()->name()));
10529 0 : pushArg(objReg);
10530 :
10531 0 : callVM(SetPropertyInfo, ins);
10532 0 : }
10533 :
10534 : typedef bool (*DeletePropertyFn)(JSContext*, HandleValue, HandlePropertyName, bool*);
10535 3 : static const VMFunction DeletePropertyStrictInfo =
10536 6 : FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>, "DeletePropertyStrictJit");
10537 3 : static const VMFunction DeletePropertyNonStrictInfo =
10538 6 : FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>, "DeletePropertyNonStrictJit");
10539 :
10540 : void
10541 0 : CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty* lir)
10542 : {
10543 0 : pushArg(ImmGCPtr(lir->mir()->name()));
10544 0 : pushArg(ToValue(lir, LCallDeleteProperty::Value));
10545 :
10546 0 : if (lir->mir()->strict())
10547 0 : callVM(DeletePropertyStrictInfo, lir);
10548 : else
10549 0 : callVM(DeletePropertyNonStrictInfo, lir);
10550 0 : }
10551 :
10552 : typedef bool (*DeleteElementFn)(JSContext*, HandleValue, HandleValue, bool*);
10553 3 : static const VMFunction DeleteElementStrictInfo =
10554 6 : FunctionInfo<DeleteElementFn>(DeleteElementJit<true>, "DeleteElementStrictJit");
10555 3 : static const VMFunction DeleteElementNonStrictInfo =
10556 6 : FunctionInfo<DeleteElementFn>(DeleteElementJit<false>, "DeleteElementNonStrictJit");
10557 :
10558 : void
10559 0 : CodeGenerator::visitCallDeleteElement(LCallDeleteElement* lir)
10560 : {
10561 0 : pushArg(ToValue(lir, LCallDeleteElement::Index));
10562 0 : pushArg(ToValue(lir, LCallDeleteElement::Value));
10563 :
10564 0 : if (lir->mir()->strict())
10565 0 : callVM(DeleteElementStrictInfo, lir);
10566 : else
10567 0 : callVM(DeleteElementNonStrictInfo, lir);
10568 0 : }
10569 :
10570 : void
10571 6 : CodeGenerator::visitSetPropertyCache(LSetPropertyCache* ins)
10572 : {
10573 6 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
10574 6 : Register objReg = ToRegister(ins->getOperand(0));
10575 6 : Register temp = ToRegister(ins->temp());
10576 6 : FloatRegister tempDouble = ToTempFloatRegisterOrInvalid(ins->tempDouble());
10577 6 : FloatRegister tempF32 = ToTempFloatRegisterOrInvalid(ins->tempFloat32());
10578 :
10579 : ConstantOrRegister id =
10580 6 : toConstantOrRegister(ins, LSetPropertyCache::Id, ins->mir()->idval()->type());
10581 : ConstantOrRegister value =
10582 6 : toConstantOrRegister(ins, LSetPropertyCache::Value, ins->mir()->value()->type());
10583 :
10584 36 : addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32,
10585 12 : id, value, ins->mir()->strict(), ins->mir()->needsPostBarrier(),
10586 12 : ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles(),
10587 12 : ins->mir()->profilerLeavePc());
10588 6 : }
10589 :
10590 : typedef bool (*ThrowFn)(JSContext*, HandleValue);
10591 3 : static const VMFunction ThrowInfoCodeGen = FunctionInfo<ThrowFn>(js::Throw, "Throw");
10592 :
10593 : void
10594 1 : CodeGenerator::visitThrow(LThrow* lir)
10595 : {
10596 1 : pushArg(ToValue(lir, LThrow::Value));
10597 1 : callVM(ThrowInfoCodeGen, lir);
10598 1 : }
10599 :
10600 : typedef bool (*BitNotFn)(JSContext*, HandleValue, int* p);
10601 3 : static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot, "BitNot");
10602 :
10603 : void
10604 0 : CodeGenerator::visitBitNotV(LBitNotV* lir)
10605 : {
10606 0 : pushArg(ToValue(lir, LBitNotV::Input));
10607 0 : callVM(BitNotInfo, lir);
10608 0 : }
10609 :
10610 : typedef bool (*BitopFn)(JSContext*, HandleValue, HandleValue, int* p);
10611 3 : static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd, "BitAnd");
10612 3 : static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr, "BitOr");
10613 3 : static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor, "BitXor");
10614 3 : static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh, "BitLsh");
10615 3 : static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh, "BitRsh");
10616 :
10617 : void
10618 0 : CodeGenerator::visitBitOpV(LBitOpV* lir)
10619 : {
10620 0 : pushArg(ToValue(lir, LBitOpV::RhsInput));
10621 0 : pushArg(ToValue(lir, LBitOpV::LhsInput));
10622 :
10623 0 : switch (lir->jsop()) {
10624 : case JSOP_BITAND:
10625 0 : callVM(BitAndInfo, lir);
10626 0 : break;
10627 : case JSOP_BITOR:
10628 0 : callVM(BitOrInfo, lir);
10629 0 : break;
10630 : case JSOP_BITXOR:
10631 0 : callVM(BitXorInfo, lir);
10632 0 : break;
10633 : case JSOP_LSH:
10634 0 : callVM(BitLhsInfo, lir);
10635 0 : break;
10636 : case JSOP_RSH:
10637 0 : callVM(BitRhsInfo, lir);
10638 0 : break;
10639 : default:
10640 0 : MOZ_CRASH("unexpected bitop");
10641 : }
10642 0 : }
10643 :
10644 : class OutOfLineTypeOfV : public OutOfLineCodeBase<CodeGenerator>
10645 : {
10646 : LTypeOfV* ins_;
10647 :
10648 : public:
10649 0 : explicit OutOfLineTypeOfV(LTypeOfV* ins)
10650 0 : : ins_(ins)
10651 0 : { }
10652 :
10653 0 : void accept(CodeGenerator* codegen) {
10654 0 : codegen->visitOutOfLineTypeOfV(this);
10655 0 : }
10656 0 : LTypeOfV* ins() const {
10657 0 : return ins_;
10658 : }
10659 : };
10660 :
10661 : void
10662 0 : CodeGenerator::visitTypeOfV(LTypeOfV* lir)
10663 : {
10664 0 : const ValueOperand value = ToValue(lir, LTypeOfV::Input);
10665 0 : Register output = ToRegister(lir->output());
10666 0 : Register tag = masm.splitTagForTest(value);
10667 :
10668 0 : const JSAtomState& names = GetJitContext()->runtime->names();
10669 0 : Label done;
10670 :
10671 0 : MDefinition* input = lir->mir()->input();
10672 :
10673 0 : bool testObject = input->mightBeType(MIRType::Object);
10674 0 : bool testNumber = input->mightBeType(MIRType::Int32) || input->mightBeType(MIRType::Double);
10675 0 : bool testBoolean = input->mightBeType(MIRType::Boolean);
10676 0 : bool testUndefined = input->mightBeType(MIRType::Undefined);
10677 0 : bool testNull = input->mightBeType(MIRType::Null);
10678 0 : bool testString = input->mightBeType(MIRType::String);
10679 0 : bool testSymbol = input->mightBeType(MIRType::Symbol);
10680 :
10681 0 : unsigned numTests = unsigned(testObject) + unsigned(testNumber) + unsigned(testBoolean) +
10682 0 : unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol);
10683 :
10684 0 : MOZ_ASSERT_IF(!input->emptyResultTypeSet(), numTests > 0);
10685 :
10686 0 : OutOfLineTypeOfV* ool = nullptr;
10687 0 : if (testObject) {
10688 0 : if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) {
10689 : // The input may be a callable object (result is "function") or may
10690 : // emulate undefined (result is "undefined"). Use an OOL path.
10691 0 : ool = new(alloc()) OutOfLineTypeOfV(lir);
10692 0 : addOutOfLineCode(ool, lir->mir());
10693 :
10694 0 : if (numTests > 1)
10695 0 : masm.branchTestObject(Assembler::Equal, tag, ool->entry());
10696 : else
10697 0 : masm.jump(ool->entry());
10698 : } else {
10699 : // Input is not callable and does not emulate undefined, so if
10700 : // it's an object the result is always "object".
10701 0 : Label notObject;
10702 0 : if (numTests > 1)
10703 0 : masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
10704 0 : masm.movePtr(ImmGCPtr(names.object), output);
10705 0 : if (numTests > 1)
10706 0 : masm.jump(&done);
10707 0 : masm.bind(¬Object);
10708 : }
10709 0 : numTests--;
10710 : }
10711 :
10712 0 : if (testNumber) {
10713 0 : Label notNumber;
10714 0 : if (numTests > 1)
10715 0 : masm.branchTestNumber(Assembler::NotEqual, tag, ¬Number);
10716 0 : masm.movePtr(ImmGCPtr(names.number), output);
10717 0 : if (numTests > 1)
10718 0 : masm.jump(&done);
10719 0 : masm.bind(¬Number);
10720 0 : numTests--;
10721 : }
10722 :
10723 0 : if (testUndefined) {
10724 0 : Label notUndefined;
10725 0 : if (numTests > 1)
10726 0 : masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined);
10727 0 : masm.movePtr(ImmGCPtr(names.undefined), output);
10728 0 : if (numTests > 1)
10729 0 : masm.jump(&done);
10730 0 : masm.bind(¬Undefined);
10731 0 : numTests--;
10732 : }
10733 :
10734 0 : if (testNull) {
10735 0 : Label notNull;
10736 0 : if (numTests > 1)
10737 0 : masm.branchTestNull(Assembler::NotEqual, tag, ¬Null);
10738 0 : masm.movePtr(ImmGCPtr(names.object), output);
10739 0 : if (numTests > 1)
10740 0 : masm.jump(&done);
10741 0 : masm.bind(¬Null);
10742 0 : numTests--;
10743 : }
10744 :
10745 0 : if (testBoolean) {
10746 0 : Label notBoolean;
10747 0 : if (numTests > 1)
10748 0 : masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
10749 0 : masm.movePtr(ImmGCPtr(names.boolean), output);
10750 0 : if (numTests > 1)
10751 0 : masm.jump(&done);
10752 0 : masm.bind(¬Boolean);
10753 0 : numTests--;
10754 : }
10755 :
10756 0 : if (testString) {
10757 0 : Label notString;
10758 0 : if (numTests > 1)
10759 0 : masm.branchTestString(Assembler::NotEqual, tag, ¬String);
10760 0 : masm.movePtr(ImmGCPtr(names.string), output);
10761 0 : if (numTests > 1)
10762 0 : masm.jump(&done);
10763 0 : masm.bind(¬String);
10764 0 : numTests--;
10765 : }
10766 :
10767 0 : if (testSymbol) {
10768 0 : Label notSymbol;
10769 0 : if (numTests > 1)
10770 0 : masm.branchTestSymbol(Assembler::NotEqual, tag, ¬Symbol);
10771 0 : masm.movePtr(ImmGCPtr(names.symbol), output);
10772 0 : if (numTests > 1)
10773 0 : masm.jump(&done);
10774 0 : masm.bind(¬Symbol);
10775 0 : numTests--;
10776 : }
10777 :
10778 0 : MOZ_ASSERT(numTests == 0);
10779 :
10780 0 : masm.bind(&done);
10781 0 : if (ool)
10782 0 : masm.bind(ool->rejoin());
10783 0 : }
10784 :
10785 : void
10786 0 : CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
10787 : {
10788 0 : LTypeOfV* ins = ool->ins();
10789 0 : const JSAtomState& names = GetJitContext()->runtime->names();
10790 :
10791 0 : ValueOperand input = ToValue(ins, LTypeOfV::Input);
10792 0 : Register temp = ToTempUnboxRegister(ins->tempToUnbox());
10793 0 : Register output = ToRegister(ins->output());
10794 :
10795 0 : Register obj = masm.extractObject(input, temp);
10796 :
10797 0 : Label slowCheck, isObject, isCallable, isUndefined, done;
10798 0 : masm.typeOfObject(obj, output, &slowCheck, &isObject, &isCallable, &isUndefined);
10799 :
10800 0 : masm.bind(&isCallable);
10801 0 : masm.movePtr(ImmGCPtr(names.function), output);
10802 0 : masm.jump(ool->rejoin());
10803 :
10804 0 : masm.bind(&isUndefined);
10805 0 : masm.movePtr(ImmGCPtr(names.undefined), output);
10806 0 : masm.jump(ool->rejoin());
10807 :
10808 0 : masm.bind(&isObject);
10809 0 : masm.movePtr(ImmGCPtr(names.object), output);
10810 0 : masm.jump(ool->rejoin());
10811 :
10812 0 : masm.bind(&slowCheck);
10813 :
10814 0 : saveVolatile(output);
10815 0 : masm.setupUnalignedABICall(output);
10816 0 : masm.passABIArg(obj);
10817 0 : masm.movePtr(ImmPtr(GetJitContext()->runtime), output);
10818 0 : masm.passABIArg(output);
10819 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, TypeOfObject));
10820 0 : masm.storeCallWordResult(output);
10821 0 : restoreVolatile(output);
10822 :
10823 0 : masm.jump(ool->rejoin());
10824 0 : }
10825 :
10826 : typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
10827 3 : static const VMFunction ToAsyncInfo = FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
10828 :
10829 : void
10830 0 : CodeGenerator::visitToAsync(LToAsync* lir)
10831 : {
10832 0 : pushArg(ToRegister(lir->unwrapped()));
10833 0 : callVM(ToAsyncInfo, lir);
10834 0 : }
10835 :
10836 : typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
10837 3 : static const VMFunction ToAsyncGenInfo =
10838 6 : FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
10839 :
10840 : void
10841 0 : CodeGenerator::visitToAsyncGen(LToAsyncGen* lir)
10842 : {
10843 0 : pushArg(ToRegister(lir->unwrapped()));
10844 0 : callVM(ToAsyncGenInfo, lir);
10845 0 : }
10846 :
10847 : typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
10848 3 : static const VMFunction ToAsyncIterInfo =
10849 6 : FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
10850 :
10851 : void
10852 0 : CodeGenerator::visitToAsyncIter(LToAsyncIter* lir)
10853 : {
10854 0 : pushArg(ToRegister(lir->unwrapped()));
10855 0 : callVM(ToAsyncIterInfo, lir);
10856 0 : }
10857 :
10858 : typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
10859 : MutableHandleValue);
10860 3 : static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation, "ToIdOperation");
10861 :
10862 : void
10863 0 : CodeGenerator::visitToIdV(LToIdV* lir)
10864 : {
10865 0 : Label notInt32;
10866 0 : FloatRegister temp = ToFloatRegister(lir->tempFloat());
10867 0 : const ValueOperand out = ToOutValue(lir);
10868 0 : ValueOperand input = ToValue(lir, LToIdV::Input);
10869 :
10870 0 : OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
10871 0 : ArgList(ImmGCPtr(current->mir()->info().script()),
10872 0 : ImmPtr(lir->mir()->resumePoint()->pc()),
10873 0 : ToValue(lir, LToIdV::Input)),
10874 0 : StoreValueTo(out));
10875 :
10876 0 : Register tag = masm.splitTagForTest(input);
10877 :
10878 0 : masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
10879 0 : masm.moveValue(input, out);
10880 0 : masm.jump(ool->rejoin());
10881 :
10882 0 : masm.bind(¬Int32);
10883 0 : masm.branchTestDouble(Assembler::NotEqual, tag, ool->entry());
10884 0 : masm.unboxDouble(input, temp);
10885 0 : masm.convertDoubleToInt32(temp, out.scratchReg(), ool->entry(), true);
10886 0 : masm.tagValue(JSVAL_TYPE_INT32, out.scratchReg(), out);
10887 :
10888 0 : masm.bind(ool->rejoin());
10889 0 : }
10890 :
10891 : template<typename T>
10892 : void
10893 1 : CodeGenerator::emitLoadElementT(LLoadElementT* lir, const T& source)
10894 : {
10895 1 : if (LIRGenerator::allowTypedElementHoleCheck()) {
10896 0 : if (lir->mir()->needsHoleCheck()) {
10897 0 : Label bail;
10898 0 : masm.branchTestMagic(Assembler::Equal, source, &bail);
10899 0 : bailoutFrom(&bail, lir->snapshot());
10900 : }
10901 : } else {
10902 1 : MOZ_ASSERT(!lir->mir()->needsHoleCheck());
10903 : }
10904 :
10905 1 : AnyRegister output = ToAnyRegister(lir->output());
10906 1 : if (lir->mir()->loadDoubles())
10907 0 : masm.loadDouble(source, output.fpu());
10908 : else
10909 1 : masm.loadUnboxedValue(source, lir->mir()->type(), output);
10910 1 : }
10911 :
10912 : void
10913 1 : CodeGenerator::visitLoadElementT(LLoadElementT* lir)
10914 : {
10915 1 : Register elements = ToRegister(lir->elements());
10916 1 : const LAllocation* index = lir->index();
10917 1 : if (index->isConstant()) {
10918 0 : int32_t offset = ToInt32(index) * sizeof(js::Value) + lir->mir()->offsetAdjustment();
10919 0 : emitLoadElementT(lir, Address(elements, offset));
10920 : } else {
10921 2 : emitLoadElementT(lir, BaseIndex(elements, ToRegister(index), TimesEight,
10922 1 : lir->mir()->offsetAdjustment()));
10923 : }
10924 1 : }
10925 :
10926 : void
10927 0 : CodeGenerator::visitLoadElementV(LLoadElementV* load)
10928 : {
10929 0 : Register elements = ToRegister(load->elements());
10930 0 : const ValueOperand out = ToOutValue(load);
10931 :
10932 0 : if (load->index()->isConstant()) {
10933 0 : NativeObject::elementsSizeMustNotOverflow();
10934 0 : int32_t offset = ToInt32(load->index()) * sizeof(Value) + load->mir()->offsetAdjustment();
10935 0 : masm.loadValue(Address(elements, offset), out);
10936 : } else {
10937 0 : masm.loadValue(BaseObjectElementIndex(elements, ToRegister(load->index()),
10938 0 : load->mir()->offsetAdjustment()), out);
10939 : }
10940 :
10941 0 : if (load->mir()->needsHoleCheck()) {
10942 0 : Label testMagic;
10943 0 : masm.branchTestMagic(Assembler::Equal, out, &testMagic);
10944 0 : bailoutFrom(&testMagic, load->snapshot());
10945 : }
10946 0 : }
10947 :
10948 : void
10949 0 : CodeGenerator::visitLoadElementHole(LLoadElementHole* lir)
10950 : {
10951 0 : Register elements = ToRegister(lir->elements());
10952 0 : Register initLength = ToRegister(lir->initLength());
10953 0 : const ValueOperand out = ToOutValue(lir);
10954 :
10955 0 : const MLoadElementHole* mir = lir->mir();
10956 :
10957 : // If the index is out of bounds, load |undefined|. Otherwise, load the
10958 : // value.
10959 0 : Label undefined, done;
10960 0 : if (lir->index()->isConstant())
10961 0 : masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(ToInt32(lir->index())), &undefined);
10962 : else
10963 0 : masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
10964 :
10965 0 : if (mir->unboxedType() != JSVAL_TYPE_MAGIC) {
10966 0 : size_t width = UnboxedTypeSize(mir->unboxedType());
10967 0 : if (lir->index()->isConstant()) {
10968 0 : Address addr(elements, ToInt32(lir->index()) * width);
10969 0 : masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
10970 : } else {
10971 0 : BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
10972 0 : masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
10973 : }
10974 : } else {
10975 0 : if (lir->index()->isConstant()) {
10976 0 : NativeObject::elementsSizeMustNotOverflow();
10977 0 : masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
10978 : } else {
10979 0 : masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
10980 : }
10981 : }
10982 :
10983 : // If a hole check is needed, and the value wasn't a hole, we're done.
10984 : // Otherwise, we'll load undefined.
10985 0 : if (lir->mir()->needsHoleCheck())
10986 0 : masm.branchTestMagic(Assembler::NotEqual, out, &done);
10987 : else
10988 0 : masm.jump(&done);
10989 :
10990 0 : masm.bind(&undefined);
10991 :
10992 0 : if (mir->needsNegativeIntCheck()) {
10993 0 : if (lir->index()->isConstant()) {
10994 0 : if (ToInt32(lir->index()) < 0)
10995 0 : bailout(lir->snapshot());
10996 : } else {
10997 0 : Label negative;
10998 0 : masm.branch32(Assembler::LessThan, ToRegister(lir->index()), Imm32(0), &negative);
10999 0 : bailoutFrom(&negative, lir->snapshot());
11000 : }
11001 : }
11002 :
11003 0 : masm.moveValue(UndefinedValue(), out);
11004 0 : masm.bind(&done);
11005 0 : }
11006 :
11007 : void
11008 0 : CodeGenerator::visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir)
11009 : {
11010 0 : Register elements = ToRegister(lir->elements());
11011 0 : const ValueOperand out = ToOutValue(lir);
11012 :
11013 0 : if (lir->index()->isConstant()) {
11014 0 : int32_t offset = ToInt32(lir->index()) * sizeof(uintptr_t) + lir->mir()->offsetAdjustment();
11015 0 : masm.loadPtr(Address(elements, offset), out.scratchReg());
11016 : } else {
11017 0 : masm.loadPtr(BaseIndex(elements, ToRegister(lir->index()), ScalePointer,
11018 0 : lir->mir()->offsetAdjustment()), out.scratchReg());
11019 : }
11020 :
11021 0 : Label notNull, done;
11022 0 : masm.branchPtr(Assembler::NotEqual, out.scratchReg(), ImmWord(0), ¬Null);
11023 :
11024 0 : masm.moveValue(NullValue(), out);
11025 0 : masm.jump(&done);
11026 :
11027 0 : masm.bind(¬Null);
11028 0 : masm.tagValue(JSVAL_TYPE_OBJECT, out.scratchReg(), out);
11029 :
11030 0 : masm.bind(&done);
11031 0 : }
11032 :
11033 : void
11034 0 : CodeGenerator::visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir)
11035 : {
11036 0 : Register elements = ToRegister(lir->elements());
11037 0 : const LAllocation* index = lir->index();
11038 0 : Register out = ToRegister(lir->output());
11039 :
11040 : bool bailOnNull;
11041 : int32_t offsetAdjustment;
11042 0 : if (lir->mir()->isLoadUnboxedObjectOrNull()) {
11043 0 : bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() ==
11044 : MLoadUnboxedObjectOrNull::BailOnNull;
11045 0 : offsetAdjustment = lir->mir()->toLoadUnboxedObjectOrNull()->offsetAdjustment();
11046 0 : } else if (lir->mir()->isLoadUnboxedString()) {
11047 0 : bailOnNull = false;
11048 0 : offsetAdjustment = lir->mir()->toLoadUnboxedString()->offsetAdjustment();
11049 : } else {
11050 0 : MOZ_CRASH();
11051 : }
11052 :
11053 0 : if (index->isConstant()) {
11054 0 : Address source(elements, ToInt32(index) * sizeof(uintptr_t) + offsetAdjustment);
11055 0 : masm.loadPtr(source, out);
11056 : } else {
11057 0 : BaseIndex source(elements, ToRegister(index), ScalePointer, offsetAdjustment);
11058 0 : masm.loadPtr(source, out);
11059 : }
11060 :
11061 0 : if (bailOnNull) {
11062 0 : Label bail;
11063 0 : masm.branchTestPtr(Assembler::Zero, out, out, &bail);
11064 0 : bailoutFrom(&bail, lir->snapshot());
11065 : }
11066 0 : }
11067 :
11068 : void
11069 0 : CodeGenerator::visitUnboxObjectOrNull(LUnboxObjectOrNull* lir)
11070 : {
11071 0 : Register obj = ToRegister(lir->input());
11072 :
11073 0 : if (lir->mir()->fallible()) {
11074 0 : Label bail;
11075 0 : masm.branchTestPtr(Assembler::Zero, obj, obj, &bail);
11076 0 : bailoutFrom(&bail, lir->snapshot());
11077 : }
11078 0 : }
11079 :
11080 : void
11081 0 : CodeGenerator::visitLoadUnboxedScalar(LLoadUnboxedScalar* lir)
11082 : {
11083 0 : Register elements = ToRegister(lir->elements());
11084 0 : Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
11085 0 : AnyRegister out = ToAnyRegister(lir->output());
11086 :
11087 0 : const MLoadUnboxedScalar* mir = lir->mir();
11088 :
11089 0 : Scalar::Type readType = mir->readType();
11090 0 : unsigned numElems = mir->numElems();
11091 :
11092 0 : int width = Scalar::byteSize(mir->storageType());
11093 0 : bool canonicalizeDouble = mir->canonicalizeDoubles();
11094 :
11095 0 : Label fail;
11096 0 : if (lir->index()->isConstant()) {
11097 0 : Address source(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment());
11098 0 : masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems);
11099 : } else {
11100 : BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
11101 0 : mir->offsetAdjustment());
11102 0 : masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems);
11103 : }
11104 :
11105 0 : if (fail.used())
11106 0 : bailoutFrom(&fail, lir->snapshot());
11107 0 : }
11108 :
11109 : void
11110 0 : CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir)
11111 : {
11112 0 : Register object = ToRegister(lir->object());
11113 0 : const ValueOperand out = ToOutValue(lir);
11114 :
11115 : // Load the length.
11116 0 : Register scratch = out.scratchReg();
11117 0 : RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->index());
11118 0 : masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch);
11119 :
11120 : // Load undefined unless length > key.
11121 0 : Label inbounds, done;
11122 0 : masm.branch32(Assembler::Above, scratch, key, &inbounds);
11123 0 : masm.moveValue(UndefinedValue(), out);
11124 0 : masm.jump(&done);
11125 :
11126 : // Load the elements vector.
11127 0 : masm.bind(&inbounds);
11128 0 : masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
11129 :
11130 0 : Scalar::Type arrayType = lir->mir()->arrayType();
11131 0 : int width = Scalar::byteSize(arrayType);
11132 :
11133 0 : Label fail;
11134 0 : if (key.isConstant()) {
11135 0 : Address source(scratch, key.constant() * width);
11136 0 : masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
11137 0 : out.scratchReg(), &fail);
11138 : } else {
11139 0 : BaseIndex source(scratch, key.reg(), ScaleFromElemWidth(width));
11140 0 : masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
11141 0 : out.scratchReg(), &fail);
11142 : }
11143 :
11144 0 : if (fail.used())
11145 0 : bailoutFrom(&fail, lir->snapshot());
11146 :
11147 0 : masm.bind(&done);
11148 0 : }
11149 :
11150 : template <typename T>
11151 : static inline void
11152 0 : StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, const LAllocation* value,
11153 : const T& dest, unsigned numElems = 0)
11154 : {
11155 0 : if (Scalar::isSimdType(writeType) ||
11156 0 : writeType == Scalar::Float32 ||
11157 : writeType == Scalar::Float64)
11158 : {
11159 0 : masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest, numElems);
11160 : } else {
11161 0 : if (value->isConstant())
11162 0 : masm.storeToTypedIntArray(writeType, Imm32(ToInt32(value)), dest);
11163 : else
11164 0 : masm.storeToTypedIntArray(writeType, ToRegister(value), dest);
11165 : }
11166 0 : }
11167 :
11168 : void
11169 0 : CodeGenerator::visitStoreUnboxedScalar(LStoreUnboxedScalar* lir)
11170 : {
11171 0 : Register elements = ToRegister(lir->elements());
11172 0 : const LAllocation* value = lir->value();
11173 :
11174 0 : const MStoreUnboxedScalar* mir = lir->mir();
11175 :
11176 0 : Scalar::Type writeType = mir->writeType();
11177 0 : unsigned numElems = mir->numElems();
11178 :
11179 0 : int width = Scalar::byteSize(mir->storageType());
11180 :
11181 0 : if (lir->index()->isConstant()) {
11182 0 : Address dest(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment());
11183 0 : StoreToTypedArray(masm, writeType, value, dest, numElems);
11184 : } else {
11185 : BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
11186 0 : mir->offsetAdjustment());
11187 0 : StoreToTypedArray(masm, writeType, value, dest, numElems);
11188 : }
11189 0 : }
11190 :
11191 : void
11192 0 : CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir)
11193 : {
11194 0 : Register elements = ToRegister(lir->elements());
11195 0 : const LAllocation* value = lir->value();
11196 :
11197 0 : Scalar::Type arrayType = lir->mir()->arrayType();
11198 0 : int width = Scalar::byteSize(arrayType);
11199 :
11200 0 : const LAllocation* index = lir->index();
11201 0 : const LAllocation* length = lir->length();
11202 :
11203 0 : bool guardLength = true;
11204 0 : if (index->isConstant() && length->isConstant()) {
11205 0 : uint32_t idx = ToInt32(index);
11206 0 : uint32_t len = ToInt32(length);
11207 0 : if (idx >= len)
11208 0 : return;
11209 0 : guardLength = false;
11210 : }
11211 0 : Label skip;
11212 0 : if (index->isConstant()) {
11213 0 : uint32_t idx = ToInt32(index);
11214 0 : if (guardLength) {
11215 0 : if (length->isRegister())
11216 0 : masm.branch32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), &skip);
11217 : else
11218 0 : masm.branch32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), &skip);
11219 : }
11220 0 : Address dest(elements, idx * width);
11221 0 : StoreToTypedArray(masm, arrayType, value, dest);
11222 : } else {
11223 0 : Register idxReg = ToRegister(index);
11224 0 : MOZ_ASSERT(guardLength);
11225 0 : if (length->isConstant())
11226 0 : masm.branch32(Assembler::AboveOrEqual, idxReg, Imm32(ToInt32(length)), &skip);
11227 0 : else if (length->isRegister())
11228 0 : masm.branch32(Assembler::BelowOrEqual, ToRegister(length), idxReg, &skip);
11229 : else
11230 0 : masm.branch32(Assembler::BelowOrEqual, ToAddress(length), idxReg, &skip);
11231 0 : BaseIndex dest(elements, ToRegister(index), ScaleFromElemWidth(width));
11232 0 : StoreToTypedArray(masm, arrayType, value, dest);
11233 : }
11234 0 : if (guardLength)
11235 0 : masm.bind(&skip);
11236 : }
11237 :
11238 : void
11239 0 : CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
11240 : {
11241 0 : Register value = ToRegister(lir->value());
11242 0 : Register output = ToRegister(lir->output());
11243 :
11244 : // Keep this in sync with isLockfree() in jit/AtomicOperations.h.
11245 0 : MOZ_ASSERT(AtomicOperations::isLockfree(1)); // Implementation artifact
11246 0 : MOZ_ASSERT(AtomicOperations::isLockfree(2)); // Implementation artifact
11247 0 : MOZ_ASSERT(AtomicOperations::isLockfree(4)); // Spec requirement
11248 0 : MOZ_ASSERT(!AtomicOperations::isLockfree(8)); // Implementation invariant, for now
11249 :
11250 0 : Label Ldone, Lfailed;
11251 0 : masm.move32(Imm32(1), output);
11252 0 : masm.branch32(Assembler::Equal, value, Imm32(4), &Ldone);
11253 0 : masm.branch32(Assembler::Equal, value, Imm32(2), &Ldone);
11254 0 : masm.branch32(Assembler::Equal, value, Imm32(1), &Ldone);
11255 0 : masm.move32(Imm32(0), output);
11256 0 : masm.bind(&Ldone);
11257 0 : }
11258 :
11259 : void
11260 0 : CodeGenerator::visitGuardSharedTypedArray(LGuardSharedTypedArray* guard)
11261 : {
11262 0 : Register obj = ToRegister(guard->input());
11263 0 : Register tmp = ToRegister(guard->tempInt());
11264 :
11265 : // The shared-memory flag is a bit in the ObjectElements header
11266 : // that is set if the TypedArray is mapping a SharedArrayBuffer.
11267 : // The flag is set at construction and does not change subsequently.
11268 0 : masm.loadPtr(Address(obj, TypedArrayObject::offsetOfElements()), tmp);
11269 0 : masm.load32(Address(tmp, ObjectElements::offsetOfFlags()), tmp);
11270 0 : bailoutTest32(Assembler::Zero, tmp, Imm32(ObjectElements::SHARED_MEMORY), guard->snapshot());
11271 0 : }
11272 :
11273 : void
11274 0 : CodeGenerator::visitClampIToUint8(LClampIToUint8* lir)
11275 : {
11276 0 : Register output = ToRegister(lir->output());
11277 0 : MOZ_ASSERT(output == ToRegister(lir->input()));
11278 0 : masm.clampIntToUint8(output);
11279 0 : }
11280 :
11281 : void
11282 0 : CodeGenerator::visitClampDToUint8(LClampDToUint8* lir)
11283 : {
11284 0 : FloatRegister input = ToFloatRegister(lir->input());
11285 0 : Register output = ToRegister(lir->output());
11286 0 : masm.clampDoubleToUint8(input, output);
11287 0 : }
11288 :
11289 : void
11290 0 : CodeGenerator::visitClampVToUint8(LClampVToUint8* lir)
11291 : {
11292 0 : ValueOperand operand = ToValue(lir, LClampVToUint8::Input);
11293 0 : FloatRegister tempFloat = ToFloatRegister(lir->tempFloat());
11294 0 : Register output = ToRegister(lir->output());
11295 0 : MDefinition* input = lir->mir()->input();
11296 :
11297 : Label* stringEntry;
11298 : Label* stringRejoin;
11299 0 : if (input->mightBeType(MIRType::String)) {
11300 0 : OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(output),
11301 0 : StoreFloatRegisterTo(tempFloat));
11302 0 : stringEntry = oolString->entry();
11303 0 : stringRejoin = oolString->rejoin();
11304 : } else {
11305 0 : stringEntry = nullptr;
11306 0 : stringRejoin = nullptr;
11307 : }
11308 :
11309 0 : Label fails;
11310 0 : masm.clampValueToUint8(operand, input,
11311 : stringEntry, stringRejoin,
11312 0 : output, tempFloat, output, &fails);
11313 :
11314 0 : bailoutFrom(&fails, lir->snapshot());
11315 0 : }
11316 :
11317 : void
11318 2 : CodeGenerator::visitInCache(LInCache* ins)
11319 : {
11320 2 : LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
11321 :
11322 2 : ConstantOrRegister key = toConstantOrRegister(ins, LInCache::LHS, ins->mir()->key()->type());
11323 2 : Register object = ToRegister(ins->rhs());
11324 2 : Register output = ToRegister(ins->output());
11325 2 : Register temp = ToRegister(ins->temp());
11326 :
11327 2 : IonInIC cache(liveRegs, key, object, output, temp);
11328 2 : addIC(ins, allocateIC(cache));
11329 2 : }
11330 :
11331 : typedef bool (*OperatorInIFn)(JSContext*, uint32_t, HandleObject, bool*);
11332 3 : static const VMFunction OperatorInIInfo = FunctionInfo<OperatorInIFn>(OperatorInI, "OperatorInI");
11333 :
11334 : void
11335 0 : CodeGenerator::visitInArray(LInArray* lir)
11336 : {
11337 0 : const MInArray* mir = lir->mir();
11338 0 : Register elements = ToRegister(lir->elements());
11339 0 : Register initLength = ToRegister(lir->initLength());
11340 0 : Register output = ToRegister(lir->output());
11341 :
11342 : // When the array is not packed we need to do a hole check in addition to the bounds check.
11343 0 : Label falseBranch, done, trueBranch;
11344 :
11345 0 : OutOfLineCode* ool = nullptr;
11346 0 : Label* failedInitLength = &falseBranch;
11347 :
11348 0 : if (lir->index()->isConstant()) {
11349 0 : int32_t index = ToInt32(lir->index());
11350 :
11351 0 : MOZ_ASSERT_IF(index < 0, mir->needsNegativeIntCheck());
11352 0 : if (mir->needsNegativeIntCheck()) {
11353 0 : ool = oolCallVM(OperatorInIInfo, lir,
11354 0 : ArgList(Imm32(index), ToRegister(lir->object())),
11355 0 : StoreRegisterTo(output));
11356 0 : failedInitLength = ool->entry();
11357 : }
11358 :
11359 0 : masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
11360 0 : if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
11361 0 : NativeObject::elementsSizeMustNotOverflow();
11362 0 : Address address = Address(elements, index * sizeof(Value));
11363 0 : masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
11364 : }
11365 : } else {
11366 0 : Label negativeIntCheck;
11367 0 : Register index = ToRegister(lir->index());
11368 :
11369 0 : if (mir->needsNegativeIntCheck())
11370 0 : failedInitLength = &negativeIntCheck;
11371 :
11372 0 : masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
11373 0 : if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
11374 0 : BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
11375 0 : masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
11376 : }
11377 0 : masm.jump(&trueBranch);
11378 :
11379 0 : if (mir->needsNegativeIntCheck()) {
11380 0 : masm.bind(&negativeIntCheck);
11381 0 : ool = oolCallVM(OperatorInIInfo, lir,
11382 0 : ArgList(index, ToRegister(lir->object())),
11383 0 : StoreRegisterTo(output));
11384 :
11385 0 : masm.branch32(Assembler::LessThan, index, Imm32(0), ool->entry());
11386 0 : masm.jump(&falseBranch);
11387 : }
11388 : }
11389 :
11390 0 : masm.bind(&trueBranch);
11391 0 : masm.move32(Imm32(1), output);
11392 0 : masm.jump(&done);
11393 :
11394 0 : masm.bind(&falseBranch);
11395 0 : masm.move32(Imm32(0), output);
11396 0 : masm.bind(&done);
11397 :
11398 0 : if (ool)
11399 0 : masm.bind(ool->rejoin());
11400 0 : }
11401 :
11402 : void
11403 0 : CodeGenerator::visitInstanceOfO(LInstanceOfO* ins)
11404 : {
11405 0 : emitInstanceOf(ins, ins->mir()->prototypeObject());
11406 0 : }
11407 :
11408 : void
11409 0 : CodeGenerator::visitInstanceOfV(LInstanceOfV* ins)
11410 : {
11411 0 : emitInstanceOf(ins, ins->mir()->prototypeObject());
11412 0 : }
11413 :
11414 : // Wrap IsDelegateOfObject, which takes a JSObject*, not a HandleObject
11415 : static bool
11416 0 : IsDelegateObject(JSContext* cx, HandleObject protoObj, HandleObject obj, bool* res)
11417 : {
11418 0 : return IsDelegateOfObject(cx, protoObj, obj, res);
11419 : }
11420 :
11421 : typedef bool (*IsDelegateObjectFn)(JSContext*, HandleObject, HandleObject, bool*);
11422 3 : static const VMFunction IsDelegateObjectInfo =
11423 6 : FunctionInfo<IsDelegateObjectFn>(IsDelegateObject, "IsDelegateObject");
11424 :
11425 : void
11426 0 : CodeGenerator::emitInstanceOf(LInstruction* ins, JSObject* prototypeObject)
11427 : {
11428 : // This path implements fun_hasInstance when the function's prototype is
11429 : // known to be prototypeObject.
11430 :
11431 0 : Label done;
11432 0 : Register output = ToRegister(ins->getDef(0));
11433 :
11434 : // If the lhs is a primitive, the result is false.
11435 0 : Register objReg;
11436 0 : if (ins->isInstanceOfV()) {
11437 0 : Label isObject;
11438 0 : ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
11439 0 : masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
11440 0 : masm.mov(ImmWord(0), output);
11441 0 : masm.jump(&done);
11442 0 : masm.bind(&isObject);
11443 0 : objReg = masm.extractObject(lhsValue, output);
11444 : } else {
11445 0 : objReg = ToRegister(ins->toInstanceOfO()->lhs());
11446 : }
11447 :
11448 : // Crawl the lhs's prototype chain in a loop to search for prototypeObject.
11449 : // This follows the main loop of js::IsDelegate, though additionally breaks
11450 : // out of the loop on Proxy::LazyProto.
11451 :
11452 : // Load the lhs's prototype.
11453 0 : masm.loadObjProto(objReg, output);
11454 :
11455 0 : Label testLazy;
11456 : {
11457 0 : Label loopPrototypeChain;
11458 0 : masm.bind(&loopPrototypeChain);
11459 :
11460 : // Test for the target prototype object.
11461 0 : Label notPrototypeObject;
11462 0 : masm.branchPtr(Assembler::NotEqual, output, ImmGCPtr(prototypeObject), ¬PrototypeObject);
11463 0 : masm.mov(ImmWord(1), output);
11464 0 : masm.jump(&done);
11465 0 : masm.bind(¬PrototypeObject);
11466 :
11467 0 : MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
11468 :
11469 : // Test for nullptr or Proxy::LazyProto
11470 0 : masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy);
11471 :
11472 : // Load the current object's prototype.
11473 0 : masm.loadObjProto(output, output);
11474 :
11475 0 : masm.jump(&loopPrototypeChain);
11476 : }
11477 :
11478 : // Make a VM call if an object with a lazy proto was found on the prototype
11479 : // chain. This currently occurs only for cross compartment wrappers, which
11480 : // we do not expect to be compared with non-wrapper functions from this
11481 : // compartment. Otherwise, we stopped on a nullptr prototype and the output
11482 : // register is already correct.
11483 :
11484 0 : OutOfLineCode* ool = oolCallVM(IsDelegateObjectInfo, ins,
11485 0 : ArgList(ImmGCPtr(prototypeObject), objReg),
11486 0 : StoreRegisterTo(output));
11487 :
11488 : // Regenerate the original lhs object for the VM call.
11489 0 : Label regenerate, *lazyEntry;
11490 0 : if (objReg != output) {
11491 0 : lazyEntry = ool->entry();
11492 : } else {
11493 0 : masm.bind(®enerate);
11494 0 : lazyEntry = ®enerate;
11495 0 : if (ins->isInstanceOfV()) {
11496 0 : ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
11497 0 : objReg = masm.extractObject(lhsValue, output);
11498 : } else {
11499 0 : objReg = ToRegister(ins->toInstanceOfO()->lhs());
11500 : }
11501 0 : MOZ_ASSERT(objReg == output);
11502 0 : masm.jump(ool->entry());
11503 : }
11504 :
11505 0 : masm.bind(&testLazy);
11506 0 : masm.branchPtr(Assembler::Equal, output, ImmWord(1), lazyEntry);
11507 :
11508 0 : masm.bind(&done);
11509 0 : masm.bind(ool->rejoin());
11510 0 : }
11511 :
11512 : typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
11513 3 : static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
11514 :
11515 : void
11516 0 : CodeGenerator::visitCallInstanceOf(LCallInstanceOf* ins)
11517 : {
11518 0 : ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
11519 0 : Register rhs = ToRegister(ins->rhs());
11520 0 : MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
11521 :
11522 0 : pushArg(lhs);
11523 0 : pushArg(rhs);
11524 0 : callVM(HasInstanceInfo, ins);
11525 0 : }
11526 :
11527 : void
11528 0 : CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
11529 : {
11530 0 : const Register JSContextReg = ToRegister(ins->getJSContextReg());
11531 0 : const Register ObjectReg = ToRegister(ins->getObjectReg());
11532 0 : const Register PrivateReg = ToRegister(ins->getPrivReg());
11533 0 : const Register ValueReg = ToRegister(ins->getValueReg());
11534 :
11535 0 : Label haveValue;
11536 0 : if (ins->mir()->valueMayBeInSlot()) {
11537 0 : size_t slot = ins->mir()->domMemberSlotIndex();
11538 : // It's a bit annoying to redo these slot calculations, which duplcate
11539 : // LSlots and a few other things like that, but I'm not sure there's a
11540 : // way to reuse those here.
11541 : //
11542 : // If this ever gets fixed to work with proxies (by not assuming that
11543 : // reserved slot indices, which is what domMemberSlotIndex() returns,
11544 : // match fixed slot indices), we can reenable MGetDOMProperty for
11545 : // proxies in IonBuilder.
11546 0 : if (slot < NativeObject::MAX_FIXED_SLOTS) {
11547 0 : masm.loadValue(Address(ObjectReg, NativeObject::getFixedSlotOffset(slot)),
11548 0 : JSReturnOperand);
11549 : } else {
11550 : // It's a dynamic slot.
11551 0 : slot -= NativeObject::MAX_FIXED_SLOTS;
11552 : // Use PrivateReg as a scratch register for the slots pointer.
11553 0 : masm.loadPtr(Address(ObjectReg, NativeObject::offsetOfSlots()),
11554 0 : PrivateReg);
11555 0 : masm.loadValue(Address(PrivateReg, slot*sizeof(js::Value)),
11556 0 : JSReturnOperand);
11557 : }
11558 0 : masm.branchTestUndefined(Assembler::NotEqual, JSReturnOperand, &haveValue);
11559 : }
11560 :
11561 0 : DebugOnly<uint32_t> initialStack = masm.framePushed();
11562 :
11563 0 : masm.checkStackAlignment();
11564 :
11565 : // Make space for the outparam. Pre-initialize it to UndefinedValue so we
11566 : // can trace it at GC time.
11567 0 : masm.Push(UndefinedValue());
11568 : // We pass the pointer to our out param as an instance of
11569 : // JSJitGetterCallArgs, since on the binary level it's the same thing.
11570 : JS_STATIC_ASSERT(sizeof(JSJitGetterCallArgs) == sizeof(Value*));
11571 0 : masm.moveStackPtrTo(ValueReg);
11572 :
11573 0 : masm.Push(ObjectReg);
11574 :
11575 0 : LoadDOMPrivate(masm, ObjectReg, PrivateReg);
11576 :
11577 : // Rooting will happen at GC time.
11578 0 : masm.moveStackPtrTo(ObjectReg);
11579 :
11580 0 : uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
11581 0 : masm.loadJSContext(JSContextReg);
11582 0 : masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutGetterToken);
11583 :
11584 0 : markSafepointAt(safepointOffset, ins);
11585 :
11586 0 : masm.setupUnalignedABICall(JSContextReg);
11587 0 : masm.loadJSContext(JSContextReg);
11588 0 : masm.passABIArg(JSContextReg);
11589 0 : masm.passABIArg(ObjectReg);
11590 0 : masm.passABIArg(PrivateReg);
11591 0 : masm.passABIArg(ValueReg);
11592 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
11593 :
11594 0 : if (ins->mir()->isInfallible()) {
11595 0 : masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
11596 0 : JSReturnOperand);
11597 : } else {
11598 0 : masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
11599 :
11600 0 : masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
11601 0 : JSReturnOperand);
11602 : }
11603 0 : masm.adjustStack(IonDOMExitFrameLayout::Size());
11604 :
11605 0 : masm.bind(&haveValue);
11606 :
11607 0 : MOZ_ASSERT(masm.framePushed() == initialStack);
11608 0 : }
11609 :
11610 : void
11611 0 : CodeGenerator::visitGetDOMMemberV(LGetDOMMemberV* ins)
11612 : {
11613 : // It's simpler to duplicate visitLoadFixedSlotV here than it is to try to
11614 : // use an LLoadFixedSlotV or some subclass of it for this case: that would
11615 : // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
11616 : // we'd have to duplicate a bunch of stuff we now get for free from
11617 : // MGetDOMProperty.
11618 : //
11619 : // If this ever gets fixed to work with proxies (by not assuming that
11620 : // reserved slot indices, which is what domMemberSlotIndex() returns,
11621 : // match fixed slot indices), we can reenable MGetDOMMember for
11622 : // proxies in IonBuilder.
11623 0 : Register object = ToRegister(ins->object());
11624 0 : size_t slot = ins->mir()->domMemberSlotIndex();
11625 0 : ValueOperand result = GetValueOutput(ins);
11626 :
11627 0 : masm.loadValue(Address(object, NativeObject::getFixedSlotOffset(slot)), result);
11628 0 : }
11629 :
11630 : void
11631 0 : CodeGenerator::visitGetDOMMemberT(LGetDOMMemberT* ins)
11632 : {
11633 : // It's simpler to duplicate visitLoadFixedSlotT here than it is to try to
11634 : // use an LLoadFixedSlotT or some subclass of it for this case: that would
11635 : // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
11636 : // we'd have to duplicate a bunch of stuff we now get for free from
11637 : // MGetDOMProperty.
11638 : //
11639 : // If this ever gets fixed to work with proxies (by not assuming that
11640 : // reserved slot indices, which is what domMemberSlotIndex() returns,
11641 : // match fixed slot indices), we can reenable MGetDOMMember for
11642 : // proxies in IonBuilder.
11643 0 : Register object = ToRegister(ins->object());
11644 0 : size_t slot = ins->mir()->domMemberSlotIndex();
11645 0 : AnyRegister result = ToAnyRegister(ins->getDef(0));
11646 0 : MIRType type = ins->mir()->type();
11647 :
11648 0 : masm.loadUnboxedValue(Address(object, NativeObject::getFixedSlotOffset(slot)), type, result);
11649 0 : }
11650 :
11651 : void
11652 0 : CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
11653 : {
11654 0 : const Register JSContextReg = ToRegister(ins->getJSContextReg());
11655 0 : const Register ObjectReg = ToRegister(ins->getObjectReg());
11656 0 : const Register PrivateReg = ToRegister(ins->getPrivReg());
11657 0 : const Register ValueReg = ToRegister(ins->getValueReg());
11658 :
11659 0 : DebugOnly<uint32_t> initialStack = masm.framePushed();
11660 :
11661 0 : masm.checkStackAlignment();
11662 :
11663 : // Push the argument. Rooting will happen at GC time.
11664 0 : ValueOperand argVal = ToValue(ins, LSetDOMProperty::Value);
11665 0 : masm.Push(argVal);
11666 : // We pass the pointer to our out param as an instance of
11667 : // JSJitGetterCallArgs, since on the binary level it's the same thing.
11668 : JS_STATIC_ASSERT(sizeof(JSJitSetterCallArgs) == sizeof(Value*));
11669 0 : masm.moveStackPtrTo(ValueReg);
11670 :
11671 0 : masm.Push(ObjectReg);
11672 :
11673 0 : LoadDOMPrivate(masm, ObjectReg, PrivateReg);
11674 :
11675 : // Rooting will happen at GC time.
11676 0 : masm.moveStackPtrTo(ObjectReg);
11677 :
11678 0 : uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
11679 0 : masm.loadJSContext(JSContextReg);
11680 0 : masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutSetterToken);
11681 :
11682 0 : markSafepointAt(safepointOffset, ins);
11683 :
11684 0 : masm.setupUnalignedABICall(JSContextReg);
11685 0 : masm.loadJSContext(JSContextReg);
11686 0 : masm.passABIArg(JSContextReg);
11687 0 : masm.passABIArg(ObjectReg);
11688 0 : masm.passABIArg(PrivateReg);
11689 0 : masm.passABIArg(ValueReg);
11690 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
11691 :
11692 0 : masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
11693 :
11694 0 : masm.adjustStack(IonDOMExitFrameLayout::Size());
11695 :
11696 0 : MOZ_ASSERT(masm.framePushed() == initialStack);
11697 0 : }
11698 :
11699 : class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
11700 : {
11701 : LIsCallable* ins_;
11702 :
11703 : public:
11704 0 : explicit OutOfLineIsCallable(LIsCallable* ins)
11705 0 : : ins_(ins)
11706 0 : { }
11707 :
11708 0 : void accept(CodeGenerator* codegen) {
11709 0 : codegen->visitOutOfLineIsCallable(this);
11710 0 : }
11711 0 : LIsCallable* ins() const {
11712 0 : return ins_;
11713 : }
11714 : };
11715 :
11716 : template <CodeGenerator::CallableOrConstructor mode>
11717 : void
11718 0 : CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
11719 : {
11720 0 : Label notFunction, hasCOps, done;
11721 0 : masm.loadObjClass(object, output);
11722 :
11723 : // Just skim proxies off. Their notion of isCallable()/isConstructor() is
11724 : // more complicated.
11725 0 : masm.branchTestClassIsProxy(true, output, failure);
11726 :
11727 : // An object is callable iff:
11728 : // is<JSFunction>() || (getClass()->cOps && getClass()->cOps->call).
11729 : // An object is constructor iff:
11730 : // ((is<JSFunction>() && as<JSFunction>().isConstructor) ||
11731 : // (getClass()->cOps && getClass()->cOps->construct)).
11732 0 : masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function);
11733 : if (mode == Callable) {
11734 0 : masm.move32(Imm32(1), output);
11735 : } else {
11736 0 : Label notConstructor;
11737 0 : masm.load16ZeroExtend(Address(object, JSFunction::offsetOfFlags()), output);
11738 0 : masm.and32(Imm32(JSFunction::CONSTRUCTOR), output);
11739 0 : masm.branchTest32(Assembler::Zero, output, output, ¬Constructor);
11740 0 : masm.move32(Imm32(1), output);
11741 0 : masm.jump(&done);
11742 0 : masm.bind(¬Constructor);
11743 0 : masm.move32(Imm32(0), output);
11744 : }
11745 0 : masm.jump(&done);
11746 :
11747 0 : masm.bind(¬Function);
11748 0 : masm.branchPtr(Assembler::NonZero, Address(output, offsetof(js::Class, cOps)),
11749 : ImmPtr(nullptr), &hasCOps);
11750 0 : masm.move32(Imm32(0), output);
11751 0 : masm.jump(&done);
11752 :
11753 0 : masm.bind(&hasCOps);
11754 0 : masm.loadPtr(Address(output, offsetof(js::Class, cOps)), output);
11755 : size_t opsOffset = mode == Callable
11756 : ? offsetof(js::ClassOps, call)
11757 0 : : offsetof(js::ClassOps, construct);
11758 0 : masm.cmpPtrSet(Assembler::NonZero, Address(output, opsOffset),
11759 : ImmPtr(nullptr), output);
11760 :
11761 0 : masm.bind(&done);
11762 0 : }
11763 :
11764 : void
11765 0 : CodeGenerator::visitIsCallable(LIsCallable* ins)
11766 : {
11767 0 : Register object = ToRegister(ins->object());
11768 0 : Register output = ToRegister(ins->output());
11769 :
11770 0 : OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins);
11771 0 : addOutOfLineCode(ool, ins->mir());
11772 :
11773 0 : emitIsCallableOrConstructor<Callable>(object, output, ool->entry());
11774 :
11775 0 : masm.bind(ool->rejoin());
11776 0 : }
11777 :
11778 : void
11779 0 : CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable* ool)
11780 : {
11781 0 : LIsCallable* ins = ool->ins();
11782 0 : Register object = ToRegister(ins->object());
11783 0 : Register output = ToRegister(ins->output());
11784 :
11785 0 : saveVolatile(output);
11786 0 : masm.setupUnalignedABICall(output);
11787 0 : masm.passABIArg(object);
11788 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsCallable));
11789 0 : masm.storeCallBoolResult(output);
11790 0 : restoreVolatile(output);
11791 0 : masm.jump(ool->rejoin());
11792 0 : }
11793 :
11794 : typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
11795 3 : static const VMFunction CheckIsCallableInfo =
11796 6 : FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
11797 :
11798 : void
11799 0 : CodeGenerator::visitCheckIsCallable(LCheckIsCallable* ins)
11800 : {
11801 0 : ValueOperand checkValue = ToValue(ins, LCheckIsCallable::CheckValue);
11802 0 : Register temp = ToRegister(ins->temp());
11803 :
11804 : // OOL code is used in the following 2 cases:
11805 : // * checkValue is not callable
11806 : // * checkValue is proxy and it's unknown whether it's callable or not
11807 : // CheckIsCallable checks if passed value is callable, regardless of the
11808 : // cases above. IsCallable operation is not observable and checking it
11809 : // again doesn't matter.
11810 0 : OutOfLineCode* ool = oolCallVM(CheckIsCallableInfo, ins,
11811 0 : ArgList(checkValue, Imm32(ins->mir()->checkKind())),
11812 0 : StoreNothing());
11813 :
11814 0 : masm.branchTestObject(Assembler::NotEqual, checkValue, ool->entry());
11815 :
11816 0 : Register object = masm.extractObject(checkValue, temp);
11817 0 : emitIsCallableOrConstructor<Callable>(object, temp, ool->entry());
11818 :
11819 0 : masm.branchTest32(Assembler::Zero, temp, temp, ool->entry());
11820 :
11821 0 : masm.bind(ool->rejoin());
11822 0 : }
11823 :
11824 : class OutOfLineIsConstructor : public OutOfLineCodeBase<CodeGenerator>
11825 : {
11826 : LIsConstructor* ins_;
11827 :
11828 : public:
11829 0 : explicit OutOfLineIsConstructor(LIsConstructor* ins)
11830 0 : : ins_(ins)
11831 0 : { }
11832 :
11833 0 : void accept(CodeGenerator* codegen) {
11834 0 : codegen->visitOutOfLineIsConstructor(this);
11835 0 : }
11836 0 : LIsConstructor* ins() const {
11837 0 : return ins_;
11838 : }
11839 : };
11840 :
11841 : void
11842 0 : CodeGenerator::visitIsConstructor(LIsConstructor* ins)
11843 : {
11844 0 : Register object = ToRegister(ins->object());
11845 0 : Register output = ToRegister(ins->output());
11846 :
11847 0 : OutOfLineIsConstructor* ool = new(alloc()) OutOfLineIsConstructor(ins);
11848 0 : addOutOfLineCode(ool, ins->mir());
11849 :
11850 0 : emitIsCallableOrConstructor<Constructor>(object, output, ool->entry());
11851 :
11852 0 : masm.bind(ool->rejoin());
11853 0 : }
11854 :
11855 : void
11856 0 : CodeGenerator::visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool)
11857 : {
11858 0 : LIsConstructor* ins = ool->ins();
11859 0 : Register object = ToRegister(ins->object());
11860 0 : Register output = ToRegister(ins->output());
11861 :
11862 0 : saveVolatile(output);
11863 0 : masm.setupUnalignedABICall(output);
11864 0 : masm.passABIArg(object);
11865 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsConstructor));
11866 0 : masm.storeCallBoolResult(output);
11867 0 : restoreVolatile(output);
11868 0 : masm.jump(ool->rejoin());
11869 0 : }
11870 :
11871 : typedef bool (*IsArrayFn)(JSContext*, HandleObject, bool*);
11872 3 : static const VMFunction IsArrayInfo = FunctionInfo<IsArrayFn>(JS::IsArray, "IsArray");
11873 :
11874 : static void
11875 0 : EmitObjectIsArray(MacroAssembler& masm, OutOfLineCode* ool, Register obj, Register output,
11876 : Label* notArray = nullptr)
11877 : {
11878 0 : masm.loadObjClass(obj, output);
11879 :
11880 0 : Label isArray;
11881 0 : masm.branchPtr(Assembler::Equal, output, ImmPtr(&ArrayObject::class_), &isArray);
11882 0 : masm.branchPtr(Assembler::Equal, output, ImmPtr(&UnboxedArrayObject::class_), &isArray);
11883 :
11884 : // Branch to OOL path if it's a proxy.
11885 0 : masm.branchTestClassIsProxy(true, output, ool->entry());
11886 :
11887 0 : if (notArray)
11888 0 : masm.bind(notArray);
11889 0 : masm.move32(Imm32(0), output);
11890 0 : masm.jump(ool->rejoin());
11891 :
11892 0 : masm.bind(&isArray);
11893 0 : masm.move32(Imm32(1), output);
11894 :
11895 0 : masm.bind(ool->rejoin());
11896 0 : }
11897 :
11898 : void
11899 0 : CodeGenerator::visitIsArrayO(LIsArrayO* lir)
11900 : {
11901 0 : Register object = ToRegister(lir->object());
11902 0 : Register output = ToRegister(lir->output());
11903 :
11904 0 : OutOfLineCode* ool = oolCallVM(IsArrayInfo, lir, ArgList(object),
11905 0 : StoreRegisterTo(output));
11906 0 : EmitObjectIsArray(masm, ool, object, output);
11907 0 : }
11908 :
11909 : void
11910 0 : CodeGenerator::visitIsArrayV(LIsArrayV* lir)
11911 : {
11912 0 : ValueOperand val = ToValue(lir, LIsArrayV::Value);
11913 0 : Register output = ToRegister(lir->output());
11914 0 : Register temp = ToRegister(lir->temp());
11915 :
11916 0 : Label notArray;
11917 0 : masm.branchTestObject(Assembler::NotEqual, val, ¬Array);
11918 0 : masm.unboxObject(val, temp);
11919 :
11920 0 : OutOfLineCode* ool = oolCallVM(IsArrayInfo, lir, ArgList(temp),
11921 0 : StoreRegisterTo(output));
11922 0 : EmitObjectIsArray(masm, ool, temp, output, ¬Array);
11923 0 : }
11924 :
11925 : void
11926 0 : CodeGenerator::visitIsObject(LIsObject* ins)
11927 : {
11928 0 : Register output = ToRegister(ins->output());
11929 0 : ValueOperand value = ToValue(ins, LIsObject::Input);
11930 0 : masm.testObjectSet(Assembler::Equal, value, output);
11931 0 : }
11932 :
11933 : void
11934 0 : CodeGenerator::visitIsObjectAndBranch(LIsObjectAndBranch* ins)
11935 : {
11936 0 : ValueOperand value = ToValue(ins, LIsObjectAndBranch::Input);
11937 0 : testObjectEmitBranch(Assembler::Equal, value, ins->ifTrue(), ins->ifFalse());
11938 0 : }
11939 :
11940 : void
11941 0 : CodeGenerator::loadOutermostJSScript(Register reg)
11942 : {
11943 : // The "outermost" JSScript means the script that we are compiling
11944 : // basically; this is not always the script associated with the
11945 : // current basic block, which might be an inlined script.
11946 :
11947 0 : MIRGraph& graph = current->mir()->graph();
11948 0 : MBasicBlock* entryBlock = graph.entryBlock();
11949 0 : masm.movePtr(ImmGCPtr(entryBlock->info().script()), reg);
11950 0 : }
11951 :
11952 : void
11953 0 : CodeGenerator::loadJSScriptForBlock(MBasicBlock* block, Register reg)
11954 : {
11955 : // The current JSScript means the script for the current
11956 : // basic block. This may be an inlined script.
11957 :
11958 0 : JSScript* script = block->info().script();
11959 0 : masm.movePtr(ImmGCPtr(script), reg);
11960 0 : }
11961 :
11962 : void
11963 0 : CodeGenerator::visitHasClass(LHasClass* ins)
11964 : {
11965 0 : Register lhs = ToRegister(ins->lhs());
11966 0 : Register output = ToRegister(ins->output());
11967 :
11968 0 : masm.loadObjClass(lhs, output);
11969 0 : masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
11970 0 : }
11971 :
11972 : void
11973 0 : CodeGenerator::visitWasmParameter(LWasmParameter* lir)
11974 : {
11975 0 : }
11976 :
11977 : void
11978 0 : CodeGenerator::visitWasmParameterI64(LWasmParameterI64* lir)
11979 : {
11980 0 : }
11981 :
11982 : void
11983 0 : CodeGenerator::visitWasmReturn(LWasmReturn* lir)
11984 : {
11985 : // Don't emit a jump to the return label if this is the last block.
11986 0 : if (current->mir() != *gen->graph().poBegin())
11987 0 : masm.jump(&returnLabel_);
11988 0 : }
11989 :
11990 : void
11991 0 : CodeGenerator::visitWasmReturnI64(LWasmReturnI64* lir)
11992 : {
11993 : // Don't emit a jump to the return label if this is the last block.
11994 0 : if (current->mir() != *gen->graph().poBegin())
11995 0 : masm.jump(&returnLabel_);
11996 0 : }
11997 :
11998 : void
11999 0 : CodeGenerator::visitWasmReturnVoid(LWasmReturnVoid* lir)
12000 : {
12001 : // Don't emit a jump to the return label if this is the last block.
12002 0 : if (current->mir() != *gen->graph().poBegin())
12003 0 : masm.jump(&returnLabel_);
12004 0 : }
12005 :
12006 : void
12007 0 : CodeGenerator::emitAssertRangeI(const Range* r, Register input)
12008 : {
12009 : // Check the lower bound.
12010 0 : if (r->hasInt32LowerBound() && r->lower() > INT32_MIN) {
12011 0 : Label success;
12012 0 : masm.branch32(Assembler::GreaterThanOrEqual, input, Imm32(r->lower()), &success);
12013 0 : masm.assumeUnreachable("Integer input should be equal or higher than Lowerbound.");
12014 0 : masm.bind(&success);
12015 : }
12016 :
12017 : // Check the upper bound.
12018 0 : if (r->hasInt32UpperBound() && r->upper() < INT32_MAX) {
12019 0 : Label success;
12020 0 : masm.branch32(Assembler::LessThanOrEqual, input, Imm32(r->upper()), &success);
12021 0 : masm.assumeUnreachable("Integer input should be lower or equal than Upperbound.");
12022 0 : masm.bind(&success);
12023 : }
12024 :
12025 : // For r->canHaveFractionalPart(), r->canBeNegativeZero(), and
12026 : // r->exponent(), there's nothing to check, because if we ended up in the
12027 : // integer range checking code, the value is already in an integer register
12028 : // in the integer range.
12029 0 : }
12030 :
12031 : void
12032 0 : CodeGenerator::emitAssertRangeD(const Range* r, FloatRegister input, FloatRegister temp)
12033 : {
12034 : // Check the lower bound.
12035 0 : if (r->hasInt32LowerBound()) {
12036 0 : Label success;
12037 0 : masm.loadConstantDouble(r->lower(), temp);
12038 0 : if (r->canBeNaN())
12039 0 : masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
12040 0 : masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &success);
12041 0 : masm.assumeUnreachable("Double input should be equal or higher than Lowerbound.");
12042 0 : masm.bind(&success);
12043 : }
12044 : // Check the upper bound.
12045 0 : if (r->hasInt32UpperBound()) {
12046 0 : Label success;
12047 0 : masm.loadConstantDouble(r->upper(), temp);
12048 0 : if (r->canBeNaN())
12049 0 : masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
12050 0 : masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &success);
12051 0 : masm.assumeUnreachable("Double input should be lower or equal than Upperbound.");
12052 0 : masm.bind(&success);
12053 : }
12054 :
12055 : // This code does not yet check r->canHaveFractionalPart(). This would require new
12056 : // assembler interfaces to make rounding instructions available.
12057 :
12058 0 : if (!r->canBeNegativeZero()) {
12059 0 : Label success;
12060 :
12061 : // First, test for being equal to 0.0, which also includes -0.0.
12062 0 : masm.loadConstantDouble(0.0, temp);
12063 0 : masm.branchDouble(Assembler::DoubleNotEqualOrUnordered, input, temp, &success);
12064 :
12065 : // The easiest way to distinguish -0.0 from 0.0 is that 1.0/-0.0 is
12066 : // -Infinity instead of Infinity.
12067 0 : masm.loadConstantDouble(1.0, temp);
12068 0 : masm.divDouble(input, temp);
12069 0 : masm.branchDouble(Assembler::DoubleGreaterThan, temp, input, &success);
12070 :
12071 0 : masm.assumeUnreachable("Input shouldn't be negative zero.");
12072 :
12073 0 : masm.bind(&success);
12074 : }
12075 :
12076 0 : if (!r->hasInt32Bounds() && !r->canBeInfiniteOrNaN() &&
12077 0 : r->exponent() < FloatingPoint<double>::kExponentBias)
12078 : {
12079 : // Check the bounds implied by the maximum exponent.
12080 0 : Label exponentLoOk;
12081 0 : masm.loadConstantDouble(pow(2.0, r->exponent() + 1), temp);
12082 0 : masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentLoOk);
12083 0 : masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &exponentLoOk);
12084 0 : masm.assumeUnreachable("Check for exponent failed.");
12085 0 : masm.bind(&exponentLoOk);
12086 :
12087 0 : Label exponentHiOk;
12088 0 : masm.loadConstantDouble(-pow(2.0, r->exponent() + 1), temp);
12089 0 : masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentHiOk);
12090 0 : masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &exponentHiOk);
12091 0 : masm.assumeUnreachable("Check for exponent failed.");
12092 0 : masm.bind(&exponentHiOk);
12093 0 : } else if (!r->hasInt32Bounds() && !r->canBeNaN()) {
12094 : // If we think the value can't be NaN, check that it isn't.
12095 0 : Label notnan;
12096 0 : masm.branchDouble(Assembler::DoubleOrdered, input, input, ¬nan);
12097 0 : masm.assumeUnreachable("Input shouldn't be NaN.");
12098 0 : masm.bind(¬nan);
12099 :
12100 : // If we think the value also can't be an infinity, check that it isn't.
12101 0 : if (!r->canBeInfiniteOrNaN()) {
12102 0 : Label notposinf;
12103 0 : masm.loadConstantDouble(PositiveInfinity<double>(), temp);
12104 0 : masm.branchDouble(Assembler::DoubleLessThan, input, temp, ¬posinf);
12105 0 : masm.assumeUnreachable("Input shouldn't be +Inf.");
12106 0 : masm.bind(¬posinf);
12107 :
12108 0 : Label notneginf;
12109 0 : masm.loadConstantDouble(NegativeInfinity<double>(), temp);
12110 0 : masm.branchDouble(Assembler::DoubleGreaterThan, input, temp, ¬neginf);
12111 0 : masm.assumeUnreachable("Input shouldn't be -Inf.");
12112 0 : masm.bind(¬neginf);
12113 : }
12114 : }
12115 0 : }
12116 :
12117 : void
12118 0 : CodeGenerator::visitAssertResultV(LAssertResultV* ins)
12119 : {
12120 0 : const ValueOperand value = ToValue(ins, LAssertResultV::Input);
12121 0 : emitAssertResultV(value, ins->mirRaw()->resultTypeSet());
12122 0 : }
12123 :
12124 : void
12125 0 : CodeGenerator::visitAssertResultT(LAssertResultT* ins)
12126 : {
12127 0 : Register input = ToRegister(ins->input());
12128 0 : MDefinition* mir = ins->mirRaw();
12129 :
12130 0 : emitAssertObjectOrStringResult(input, mir->type(), mir->resultTypeSet());
12131 0 : }
12132 :
12133 : void
12134 0 : CodeGenerator::visitAssertRangeI(LAssertRangeI* ins)
12135 : {
12136 0 : Register input = ToRegister(ins->input());
12137 0 : const Range* r = ins->range();
12138 :
12139 0 : emitAssertRangeI(r, input);
12140 0 : }
12141 :
12142 : void
12143 0 : CodeGenerator::visitAssertRangeD(LAssertRangeD* ins)
12144 : {
12145 0 : FloatRegister input = ToFloatRegister(ins->input());
12146 0 : FloatRegister temp = ToFloatRegister(ins->temp());
12147 0 : const Range* r = ins->range();
12148 :
12149 0 : emitAssertRangeD(r, input, temp);
12150 0 : }
12151 :
12152 : void
12153 0 : CodeGenerator::visitAssertRangeF(LAssertRangeF* ins)
12154 : {
12155 0 : FloatRegister input = ToFloatRegister(ins->input());
12156 0 : FloatRegister temp = ToFloatRegister(ins->temp());
12157 0 : FloatRegister temp2 = ToFloatRegister(ins->temp2());
12158 :
12159 0 : const Range* r = ins->range();
12160 :
12161 0 : masm.convertFloat32ToDouble(input, temp);
12162 0 : emitAssertRangeD(r, temp, temp2);
12163 0 : }
12164 :
12165 : void
12166 0 : CodeGenerator::visitAssertRangeV(LAssertRangeV* ins)
12167 : {
12168 0 : const Range* r = ins->range();
12169 0 : const ValueOperand value = ToValue(ins, LAssertRangeV::Input);
12170 0 : Register tag = masm.splitTagForTest(value);
12171 0 : Label done;
12172 :
12173 : {
12174 0 : Label isNotInt32;
12175 0 : masm.branchTestInt32(Assembler::NotEqual, tag, &isNotInt32);
12176 0 : Register unboxInt32 = ToTempUnboxRegister(ins->temp());
12177 0 : Register input = masm.extractInt32(value, unboxInt32);
12178 0 : emitAssertRangeI(r, input);
12179 0 : masm.jump(&done);
12180 0 : masm.bind(&isNotInt32);
12181 : }
12182 :
12183 : {
12184 0 : Label isNotDouble;
12185 0 : masm.branchTestDouble(Assembler::NotEqual, tag, &isNotDouble);
12186 0 : FloatRegister input = ToFloatRegister(ins->floatTemp1());
12187 0 : FloatRegister temp = ToFloatRegister(ins->floatTemp2());
12188 0 : masm.unboxDouble(value, input);
12189 0 : emitAssertRangeD(r, input, temp);
12190 0 : masm.jump(&done);
12191 0 : masm.bind(&isNotDouble);
12192 : }
12193 :
12194 0 : masm.assumeUnreachable("Incorrect range for Value.");
12195 0 : masm.bind(&done);
12196 0 : }
12197 :
12198 : void
12199 5 : CodeGenerator::visitInterruptCheck(LInterruptCheck* lir)
12200 : {
12201 5 : if (lir->implicit()) {
12202 0 : OutOfLineInterruptCheckImplicit* ool = new(alloc()) OutOfLineInterruptCheckImplicit(current, lir);
12203 0 : addOutOfLineCode(ool, lir->mir());
12204 :
12205 0 : lir->setOolEntry(ool->entry());
12206 0 : masm.bind(ool->rejoin());
12207 0 : return;
12208 : }
12209 :
12210 5 : OutOfLineCode* ool = oolCallVM(InterruptCheckInfo, lir, ArgList(), StoreNothing());
12211 :
12212 5 : Register temp = ToRegister(lir->temp());
12213 :
12214 5 : const void* contextAddr = GetJitContext()->compartment->zone()->addressOfJSContext();
12215 5 : masm.loadPtr(AbsoluteAddress(contextAddr), temp);
12216 10 : masm.branch32(Assembler::NotEqual, Address(temp, offsetof(JSContext, interrupt_)),
12217 5 : Imm32(0), ool->entry());
12218 5 : masm.bind(ool->rejoin());
12219 : }
12220 :
12221 : void
12222 0 : CodeGenerator::visitWasmTrap(LWasmTrap* lir)
12223 : {
12224 0 : MOZ_ASSERT(gen->compilingWasm());
12225 0 : const MWasmTrap* mir = lir->mir();
12226 :
12227 0 : masm.jump(trap(mir, mir->trap()));
12228 0 : }
12229 :
12230 : void
12231 0 : CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
12232 : {
12233 : #ifdef WASM_HUGE_MEMORY
12234 0 : MOZ_CRASH("No wasm bounds check for huge memory");
12235 : #else
12236 : const MWasmBoundsCheck* mir = ins->mir();
12237 : Register ptr = ToRegister(ins->ptr());
12238 : Register boundsCheckLimit = ToRegister(ins->boundsCheckLimit());
12239 : masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr, boundsCheckLimit,
12240 : trap(mir, wasm::Trap::OutOfBounds));
12241 : #endif
12242 : }
12243 :
12244 : void
12245 0 : CodeGenerator::visitWasmLoadTls(LWasmLoadTls* ins)
12246 : {
12247 0 : switch (ins->mir()->type()) {
12248 : case MIRType::Pointer:
12249 0 : masm.loadPtr(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
12250 0 : ToRegister(ins->output()));
12251 0 : break;
12252 : case MIRType::Int32:
12253 0 : masm.load32(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
12254 0 : ToRegister(ins->output()));
12255 0 : break;
12256 : default:
12257 0 : MOZ_CRASH("MIRType not supported in WasmLoadTls");
12258 : }
12259 0 : }
12260 :
12261 : typedef bool (*RecompileFn)(JSContext*);
12262 3 : static const VMFunction RecompileFnInfo = FunctionInfo<RecompileFn>(Recompile, "Recompile");
12263 :
12264 : typedef bool (*ForcedRecompileFn)(JSContext*);
12265 3 : static const VMFunction ForcedRecompileFnInfo =
12266 6 : FunctionInfo<ForcedRecompileFn>(ForcedRecompile, "ForcedRecompile");
12267 :
12268 : void
12269 6 : CodeGenerator::visitRecompileCheck(LRecompileCheck* ins)
12270 : {
12271 12 : Label done;
12272 6 : Register tmp = ToRegister(ins->scratch());
12273 : OutOfLineCode* ool;
12274 6 : if (ins->mir()->forceRecompilation())
12275 6 : ool = oolCallVM(ForcedRecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
12276 : else
12277 0 : ool = oolCallVM(RecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
12278 :
12279 : // Check if warm-up counter is high enough.
12280 6 : AbsoluteAddress warmUpCount = AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
12281 6 : if (ins->mir()->increaseWarmUpCounter()) {
12282 0 : masm.load32(warmUpCount, tmp);
12283 0 : masm.add32(Imm32(1), tmp);
12284 0 : masm.store32(tmp, warmUpCount);
12285 0 : masm.branch32(Assembler::BelowOrEqual, tmp, Imm32(ins->mir()->recompileThreshold()), &done);
12286 : } else {
12287 12 : masm.branch32(Assembler::BelowOrEqual, warmUpCount, Imm32(ins->mir()->recompileThreshold()),
12288 6 : &done);
12289 : }
12290 :
12291 : // Check if not yet recompiling.
12292 6 : CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
12293 6 : masm.propagateOOM(ionScriptLabels_.append(label));
12294 18 : masm.branch32(Assembler::Equal,
12295 12 : Address(tmp, IonScript::offsetOfRecompiling()),
12296 : Imm32(0),
12297 6 : ool->entry());
12298 6 : masm.bind(ool->rejoin());
12299 6 : masm.bind(&done);
12300 6 : }
12301 :
12302 : void
12303 0 : CodeGenerator::visitLexicalCheck(LLexicalCheck* ins)
12304 : {
12305 0 : ValueOperand inputValue = ToValue(ins, LLexicalCheck::Input);
12306 0 : Label bail;
12307 0 : masm.branchTestMagicValue(Assembler::Equal, inputValue, JS_UNINITIALIZED_LEXICAL, &bail);
12308 0 : bailoutFrom(&bail, ins->snapshot());
12309 0 : }
12310 :
12311 : typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext*, unsigned);
12312 3 : static const VMFunction ThrowRuntimeLexicalErrorInfo =
12313 6 : FunctionInfo<ThrowRuntimeLexicalErrorFn>(ThrowRuntimeLexicalError, "ThrowRuntimeLexicalError");
12314 :
12315 : void
12316 0 : CodeGenerator::visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins)
12317 : {
12318 0 : pushArg(Imm32(ins->mir()->errorNumber()));
12319 0 : callVM(ThrowRuntimeLexicalErrorInfo, ins);
12320 0 : }
12321 :
12322 : typedef bool (*GlobalNameConflictsCheckFromIonFn)(JSContext*, HandleScript);
12323 3 : static const VMFunction GlobalNameConflictsCheckFromIonInfo =
12324 6 : FunctionInfo<GlobalNameConflictsCheckFromIonFn>(GlobalNameConflictsCheckFromIon,
12325 : "GlobalNameConflictsCheckFromIon");
12326 :
12327 : void
12328 0 : CodeGenerator::visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins)
12329 : {
12330 0 : pushArg(ImmGCPtr(ins->mirRaw()->block()->info().script()));
12331 0 : callVM(GlobalNameConflictsCheckFromIonInfo, ins);
12332 0 : }
12333 :
12334 : void
12335 0 : CodeGenerator::visitDebugger(LDebugger* ins)
12336 : {
12337 0 : Register cx = ToRegister(ins->getTemp(0));
12338 0 : Register temp = ToRegister(ins->getTemp(1));
12339 :
12340 0 : masm.loadJSContext(cx);
12341 0 : masm.setupUnalignedABICall(temp);
12342 0 : masm.passABIArg(cx);
12343 0 : masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GlobalHasLiveOnDebuggerStatement));
12344 :
12345 0 : Label bail;
12346 0 : masm.branchIfTrueBool(ReturnReg, &bail);
12347 0 : bailoutFrom(&bail, ins->snapshot());
12348 0 : }
12349 :
12350 : void
12351 0 : CodeGenerator::visitNewTarget(LNewTarget *ins)
12352 : {
12353 0 : ValueOperand output = GetValueOutput(ins);
12354 :
12355 : // if (isConstructing) output = argv[Max(numActualArgs, numFormalArgs)]
12356 0 : Label notConstructing, done;
12357 0 : Address calleeToken(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
12358 0 : masm.branchTestPtr(Assembler::Zero, calleeToken,
12359 0 : Imm32(CalleeToken_FunctionConstructing), ¬Constructing);
12360 :
12361 0 : Register argvLen = output.scratchReg();
12362 :
12363 0 : Address actualArgsPtr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfNumActualArgs());
12364 0 : masm.loadPtr(actualArgsPtr, argvLen);
12365 :
12366 0 : Label useNFormals;
12367 :
12368 0 : size_t numFormalArgs = ins->mirRaw()->block()->info().funMaybeLazy()->nargs();
12369 0 : masm.branchPtr(Assembler::Below, argvLen, Imm32(numFormalArgs),
12370 0 : &useNFormals);
12371 :
12372 0 : size_t argsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
12373 : {
12374 0 : BaseValueIndex newTarget(masm.getStackPointer(), argvLen, argsOffset);
12375 0 : masm.loadValue(newTarget, output);
12376 0 : masm.jump(&done);
12377 : }
12378 :
12379 0 : masm.bind(&useNFormals);
12380 :
12381 : {
12382 0 : Address newTarget(masm.getStackPointer(), argsOffset + (numFormalArgs * sizeof(Value)));
12383 0 : masm.loadValue(newTarget, output);
12384 0 : masm.jump(&done);
12385 : }
12386 :
12387 : // else output = undefined
12388 0 : masm.bind(¬Constructing);
12389 0 : masm.moveValue(UndefinedValue(), output);
12390 0 : masm.bind(&done);
12391 0 : }
12392 :
12393 : void
12394 0 : CodeGenerator::visitCheckReturn(LCheckReturn* ins)
12395 : {
12396 0 : ValueOperand returnValue = ToValue(ins, LCheckReturn::ReturnValue);
12397 0 : ValueOperand thisValue = ToValue(ins, LCheckReturn::ThisValue);
12398 0 : Label bail, noChecks;
12399 0 : masm.branchTestObject(Assembler::Equal, returnValue, &noChecks);
12400 0 : masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail);
12401 0 : masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail);
12402 0 : bailoutFrom(&bail, ins->snapshot());
12403 0 : masm.bind(&noChecks);
12404 0 : }
12405 :
12406 : typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind);
12407 3 : static const VMFunction ThrowCheckIsObjectInfo =
12408 6 : FunctionInfo<ThrowCheckIsObjectFn>(ThrowCheckIsObject, "ThrowCheckIsObject");
12409 :
12410 : void
12411 0 : CodeGenerator::visitCheckIsObj(LCheckIsObj* ins)
12412 : {
12413 0 : ValueOperand checkValue = ToValue(ins, LCheckIsObj::CheckValue);
12414 :
12415 0 : OutOfLineCode* ool = oolCallVM(ThrowCheckIsObjectInfo, ins,
12416 0 : ArgList(Imm32(ins->mir()->checkKind())),
12417 0 : StoreNothing());
12418 0 : masm.branchTestObject(Assembler::NotEqual, checkValue, ool->entry());
12419 0 : masm.bind(ool->rejoin());
12420 0 : }
12421 :
12422 : typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue);
12423 3 : static const VMFunction ThrowObjectCoercibleInfo =
12424 6 : FunctionInfo<ThrowObjCoercibleFn>(ThrowObjectCoercible, "ThrowObjectCoercible");
12425 :
12426 : void
12427 0 : CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins)
12428 : {
12429 0 : ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue);
12430 0 : Label fail, done;
12431 0 : masm.branchTestNull(Assembler::Equal, checkValue, &fail);
12432 0 : masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done);
12433 0 : masm.bind(&fail);
12434 0 : pushArg(checkValue);
12435 0 : callVM(ThrowObjectCoercibleInfo, ins);
12436 0 : masm.bind(&done);
12437 0 : }
12438 :
12439 : typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
12440 3 : static const VMFunction CheckSelfHostedInfo =
12441 6 : FunctionInfo<CheckSelfHostedFn>(js::Debug_CheckSelfHosted, "Debug_CheckSelfHosted");
12442 :
12443 : void
12444 0 : CodeGenerator::visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins)
12445 : {
12446 0 : ValueOperand checkValue = ToValue(ins, LDebugCheckSelfHosted::CheckValue);
12447 0 : pushArg(checkValue);
12448 0 : callVM(CheckSelfHostedInfo, ins);
12449 0 : }
12450 :
12451 : void
12452 0 : CodeGenerator::visitRandom(LRandom* ins)
12453 : {
12454 : using mozilla::non_crypto::XorShift128PlusRNG;
12455 :
12456 0 : FloatRegister output = ToFloatRegister(ins->output());
12457 0 : Register tempReg = ToRegister(ins->temp0());
12458 :
12459 : #ifdef JS_PUNBOX64
12460 0 : Register64 s0Reg(ToRegister(ins->temp1()));
12461 0 : Register64 s1Reg(ToRegister(ins->temp2()));
12462 : #else
12463 : Register64 s0Reg(ToRegister(ins->temp1()), ToRegister(ins->temp2()));
12464 : Register64 s1Reg(ToRegister(ins->temp3()), ToRegister(ins->temp4()));
12465 : #endif
12466 :
12467 0 : const void* rng = gen->compartment->addressOfRandomNumberGenerator();
12468 0 : masm.movePtr(ImmPtr(rng), tempReg);
12469 :
12470 : static_assert(sizeof(XorShift128PlusRNG) == 2 * sizeof(uint64_t),
12471 : "Code below assumes XorShift128PlusRNG contains two uint64_t values");
12472 :
12473 0 : Address state0Addr(tempReg, XorShift128PlusRNG::offsetOfState0());
12474 0 : Address state1Addr(tempReg, XorShift128PlusRNG::offsetOfState1());
12475 :
12476 : // uint64_t s1 = mState[0];
12477 0 : masm.load64(state0Addr, s1Reg);
12478 :
12479 : // s1 ^= s1 << 23;
12480 0 : masm.move64(s1Reg, s0Reg);
12481 0 : masm.lshift64(Imm32(23), s1Reg);
12482 0 : masm.xor64(s0Reg, s1Reg);
12483 :
12484 : // s1 ^= s1 >> 17
12485 0 : masm.move64(s1Reg, s0Reg);
12486 0 : masm.rshift64(Imm32(17), s1Reg);
12487 0 : masm.xor64(s0Reg, s1Reg);
12488 :
12489 : // const uint64_t s0 = mState[1];
12490 0 : masm.load64(state1Addr, s0Reg);
12491 :
12492 : // mState[0] = s0;
12493 0 : masm.store64(s0Reg, state0Addr);
12494 :
12495 : // s1 ^= s0
12496 0 : masm.xor64(s0Reg, s1Reg);
12497 :
12498 : // s1 ^= s0 >> 26
12499 0 : masm.rshift64(Imm32(26), s0Reg);
12500 0 : masm.xor64(s0Reg, s1Reg);
12501 :
12502 : // mState[1] = s1
12503 0 : masm.store64(s1Reg, state1Addr);
12504 :
12505 : // s1 += mState[0]
12506 0 : masm.load64(state0Addr, s0Reg);
12507 0 : masm.add64(s0Reg, s1Reg);
12508 :
12509 : // See comment in XorShift128PlusRNG::nextDouble().
12510 : static const int MantissaBits = FloatingPoint<double>::kExponentShift + 1;
12511 : static const double ScaleInv = double(1) / (1ULL << MantissaBits);
12512 :
12513 0 : masm.and64(Imm64((1ULL << MantissaBits) - 1), s1Reg);
12514 :
12515 0 : if (masm.convertUInt64ToDoubleNeedsTemp())
12516 0 : masm.convertUInt64ToDouble(s1Reg, output, tempReg);
12517 : else
12518 0 : masm.convertUInt64ToDouble(s1Reg, output, Register::Invalid());
12519 :
12520 : // output *= ScaleInv
12521 0 : masm.mulDoublePtr(ImmPtr(&ScaleInv), tempReg, output);
12522 0 : }
12523 :
12524 : void
12525 0 : CodeGenerator::visitSignExtend(LSignExtend* ins)
12526 : {
12527 0 : Register input = ToRegister(ins->input());
12528 0 : Register output = ToRegister(ins->output());
12529 :
12530 0 : switch (ins->mode()) {
12531 : case MSignExtend::Byte:
12532 0 : masm.move8SignExtend(input, output);
12533 0 : break;
12534 : case MSignExtend::Half:
12535 0 : masm.move16SignExtend(input, output);
12536 0 : break;
12537 : }
12538 0 : }
12539 :
12540 : void
12541 0 : CodeGenerator::visitRotate(LRotate* ins)
12542 : {
12543 0 : MRotate* mir = ins->mir();
12544 0 : Register input = ToRegister(ins->input());
12545 0 : Register dest = ToRegister(ins->output());
12546 :
12547 0 : const LAllocation* count = ins->count();
12548 0 : if (count->isConstant()) {
12549 0 : int32_t c = ToInt32(count) & 0x1F;
12550 0 : if (mir->isLeftRotate())
12551 0 : masm.rotateLeft(Imm32(c), input, dest);
12552 : else
12553 0 : masm.rotateRight(Imm32(c), input, dest);
12554 : } else {
12555 0 : Register creg = ToRegister(count);
12556 0 : if (mir->isLeftRotate())
12557 0 : masm.rotateLeft(creg, input, dest);
12558 : else
12559 0 : masm.rotateRight(creg, input, dest);
12560 : }
12561 0 : }
12562 :
12563 : class OutOfLineNaNToZero : public OutOfLineCodeBase<CodeGenerator>
12564 : {
12565 : LNaNToZero* lir_;
12566 :
12567 : public:
12568 0 : explicit OutOfLineNaNToZero(LNaNToZero* lir)
12569 0 : : lir_(lir)
12570 0 : {}
12571 :
12572 0 : void accept(CodeGenerator* codegen) {
12573 0 : codegen->visitOutOfLineNaNToZero(this);
12574 0 : }
12575 0 : LNaNToZero* lir() const {
12576 0 : return lir_;
12577 : }
12578 : };
12579 :
12580 : void
12581 0 : CodeGenerator::visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool)
12582 : {
12583 0 : FloatRegister output = ToFloatRegister(ool->lir()->output());
12584 0 : masm.loadConstantDouble(0.0, output);
12585 0 : masm.jump(ool->rejoin());
12586 0 : }
12587 :
12588 : void
12589 0 : CodeGenerator::visitNaNToZero(LNaNToZero* lir)
12590 : {
12591 0 : FloatRegister input = ToFloatRegister(lir->input());
12592 :
12593 0 : OutOfLineNaNToZero* ool = new(alloc()) OutOfLineNaNToZero(lir);
12594 0 : addOutOfLineCode(ool, lir->mir());
12595 :
12596 0 : if (lir->mir()->operandIsNeverNegativeZero()){
12597 0 : masm.branchDouble(Assembler::DoubleUnordered, input, input, ool->entry());
12598 : } else {
12599 0 : FloatRegister scratch = ToFloatRegister(lir->tempDouble());
12600 0 : masm.loadConstantDouble(0.0, scratch);
12601 0 : masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, ool->entry());
12602 : }
12603 0 : masm.bind(ool->rejoin());
12604 0 : }
12605 :
12606 : typedef bool (*FinishBoundFunctionInitFn)(JSContext* cx, HandleFunction bound,
12607 : HandleObject target, int32_t argCount);
12608 3 : static const VMFunction FinishBoundFunctionInitInfo =
12609 6 : FunctionInfo<FinishBoundFunctionInitFn>(JSFunction::finishBoundFunctionInit,
12610 : "JSFunction::finishBoundFunctionInit");
12611 :
12612 : void
12613 0 : CodeGenerator::visitFinishBoundFunctionInit(LFinishBoundFunctionInit* lir)
12614 : {
12615 0 : Register bound = ToRegister(lir->bound());
12616 0 : Register target = ToRegister(lir->target());
12617 0 : Register argCount = ToRegister(lir->argCount());
12618 0 : Register temp1 = ToRegister(lir->temp1());
12619 0 : Register temp2 = ToRegister(lir->temp2());
12620 :
12621 0 : OutOfLineCode* ool = oolCallVM(FinishBoundFunctionInitInfo, lir,
12622 0 : ArgList(bound, target, argCount), StoreNothing());
12623 0 : Label* slowPath = ool->entry();
12624 :
12625 0 : const size_t boundLengthOffset = FunctionExtended::offsetOfExtendedSlot(BOUND_FUN_LENGTH_SLOT);
12626 :
12627 : // Take the slow path if the target is not a JSFunction.
12628 0 : masm.branchTestObjClass(Assembler::NotEqual, target, temp1, &JSFunction::class_, slowPath);
12629 :
12630 : // Take the slow path if we'd need to adjust the [[Prototype]].
12631 0 : masm.loadObjProto(bound, temp1);
12632 0 : masm.loadObjProto(target, temp2);
12633 0 : masm.branchPtr(Assembler::NotEqual, temp1, temp2, slowPath);
12634 :
12635 : // Get the function flags.
12636 0 : masm.load16ZeroExtend(Address(target, JSFunction::offsetOfFlags()), temp1);
12637 :
12638 : // Functions with lazy scripts don't store their length.
12639 : // If the length or name property is resolved, it might be shadowed.
12640 0 : masm.branchTest32(Assembler::NonZero,
12641 : temp1,
12642 : Imm32(JSFunction::INTERPRETED_LAZY |
12643 : JSFunction::RESOLVED_NAME |
12644 : JSFunction::RESOLVED_LENGTH),
12645 0 : slowPath);
12646 :
12647 0 : Label notBoundTarget, loadName;
12648 0 : masm.branchTest32(Assembler::Zero, temp1, Imm32(JSFunction::BOUND_FUN), ¬BoundTarget);
12649 : {
12650 : // Target's name atom doesn't contain the bound function prefix, so we
12651 : // need to call into the VM.
12652 0 : masm.branchTest32(Assembler::Zero, temp1,
12653 0 : Imm32(JSFunction::HAS_BOUND_FUNCTION_NAME_PREFIX), slowPath);
12654 :
12655 : // We also take the slow path when target's length isn't an int32.
12656 0 : masm.branchTestInt32(Assembler::NotEqual, Address(target, boundLengthOffset), slowPath);
12657 :
12658 : // Bound functions reuse HAS_GUESSED_ATOM for HAS_BOUND_FUNCTION_NAME_PREFIX,
12659 : // so skip the guessed atom check below.
12660 : static_assert(JSFunction::HAS_BOUND_FUNCTION_NAME_PREFIX == JSFunction::HAS_GUESSED_ATOM,
12661 : "HAS_BOUND_FUNCTION_NAME_PREFIX is shared with HAS_GUESSED_ATOM");
12662 0 : masm.jump(&loadName);
12663 : }
12664 0 : masm.bind(¬BoundTarget);
12665 :
12666 0 : Label guessed, hasName;
12667 0 : masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::HAS_GUESSED_ATOM), &guessed);
12668 0 : masm.bind(&loadName);
12669 0 : masm.loadPtr(Address(target, JSFunction::offsetOfAtom()), temp2);
12670 0 : masm.branchTestPtr(Assembler::NonZero, temp2, temp2, &hasName);
12671 : {
12672 0 : masm.bind(&guessed);
12673 :
12674 : // Unnamed class expression don't have a name property. To avoid
12675 : // looking it up from the prototype chain, we take the slow path here.
12676 0 : masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, target, temp2,
12677 0 : slowPath);
12678 :
12679 : // An absent name property defaults to the empty string.
12680 0 : const JSAtomState& names = GetJitContext()->runtime->names();
12681 0 : masm.movePtr(ImmGCPtr(names.empty), temp2);
12682 : }
12683 0 : masm.bind(&hasName);
12684 :
12685 : // Store the target's name atom in the bound function as is.
12686 0 : masm.storePtr(temp2, Address(bound, JSFunction::offsetOfAtom()));
12687 :
12688 : // Set the BOUND_FN flag and, if the target is a constructor, the
12689 : // CONSTRUCTOR flag.
12690 0 : Label isConstructor, boundFlagsComputed;
12691 0 : masm.load16ZeroExtend(Address(bound, JSFunction::offsetOfFlags()), temp2);
12692 0 : masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::CONSTRUCTOR), &isConstructor);
12693 : {
12694 0 : masm.or32(Imm32(JSFunction::BOUND_FUN), temp2);
12695 0 : masm.jump(&boundFlagsComputed);
12696 : }
12697 0 : masm.bind(&isConstructor);
12698 : {
12699 0 : masm.or32(Imm32(JSFunction::BOUND_FUN | JSFunction::CONSTRUCTOR), temp2);
12700 : }
12701 0 : masm.bind(&boundFlagsComputed);
12702 0 : masm.store16(temp2, Address(bound, JSFunction::offsetOfFlags()));
12703 :
12704 : // Load the target function's length.
12705 0 : Label isInterpreted, isBound, lengthLoaded;
12706 0 : masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::BOUND_FUN), &isBound);
12707 0 : masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::INTERPRETED), &isInterpreted);
12708 : {
12709 : // Load the length property of a native function.
12710 0 : masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), temp1);
12711 0 : masm.jump(&lengthLoaded);
12712 : }
12713 0 : masm.bind(&isBound);
12714 : {
12715 : // Load the length property of a bound function.
12716 0 : masm.unboxInt32(Address(target, boundLengthOffset), temp1);
12717 0 : masm.jump(&lengthLoaded);
12718 : }
12719 0 : masm.bind(&isInterpreted);
12720 : {
12721 : // Load the length property of an interpreted function.
12722 0 : masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp1);
12723 0 : masm.load16ZeroExtend(Address(temp1, JSScript::offsetOfFunLength()), temp1);
12724 : }
12725 0 : masm.bind(&lengthLoaded);
12726 :
12727 : // Compute the bound function length: Max(0, target.length - argCount).
12728 0 : Label nonNegative;
12729 0 : masm.sub32(argCount, temp1);
12730 0 : masm.branch32(Assembler::GreaterThanOrEqual, temp1, Imm32(0), &nonNegative);
12731 0 : masm.move32(Imm32(0), temp1);
12732 0 : masm.bind(&nonNegative);
12733 :
12734 : // Store the bound function's length into the extended slot.
12735 0 : masm.storeValue(JSVAL_TYPE_INT32, temp1, Address(bound, boundLengthOffset));
12736 :
12737 0 : masm.bind(ool->rejoin());
12738 0 : }
12739 :
12740 : } // namespace jit
12741 : } // namespace js
|