1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 : * May 28, 2008.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Brendan Eich <brendan@mozilla.org>
22 : *
23 : * Contributor(s):
24 : * Jan de Mooij <jandemooij@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 : #include "jsbool.h"
40 : #include "jslibmath.h"
41 : #include "jsmath.h"
42 : #include "jsnum.h"
43 : #include "methodjit/MethodJIT.h"
44 : #include "methodjit/Compiler.h"
45 : #include "methodjit/StubCalls.h"
46 : #include "methodjit/FrameState-inl.h"
47 :
48 : using namespace js;
49 : using namespace js::mjit;
50 : using namespace JSC;
51 :
52 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
53 :
54 : CompileStatus
55 36 : mjit::Compiler::compileMathAbsInt(FrameEntry *arg)
56 : {
57 : RegisterID reg;
58 36 : if (arg->isConstant()) {
59 0 : reg = frame.allocReg();
60 0 : masm.move(Imm32(arg->getValue().toInt32()), reg);
61 : } else {
62 36 : reg = frame.copyDataIntoReg(arg);
63 : }
64 :
65 36 : Jump isPositive = masm.branch32(Assembler::GreaterThanOrEqual, reg, Imm32(0));
66 :
67 : /* Math.abs(INT32_MIN) results in a double */
68 36 : Jump isMinInt = masm.branch32(Assembler::Equal, reg, Imm32(INT32_MIN));
69 36 : stubcc.linkExit(isMinInt, Uses(3));
70 :
71 36 : masm.neg32(reg);
72 :
73 36 : isPositive.linkTo(masm.label(), &masm);
74 :
75 36 : stubcc.leave();
76 36 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
77 36 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
78 :
79 36 : frame.popn(3);
80 36 : frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
81 :
82 36 : stubcc.rejoin(Changes(1));
83 36 : return Compile_Okay;
84 : }
85 :
86 : CompileStatus
87 85 : mjit::Compiler::compileMathAbsDouble(FrameEntry *arg)
88 : {
89 85 : FPRegisterID fpResultReg = frame.allocFPReg();
90 :
91 : FPRegisterID fpReg;
92 : bool allocate;
93 :
94 170 : DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
95 85 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
96 :
97 85 : masm.absDouble(fpReg, fpResultReg);
98 :
99 85 : if (allocate)
100 0 : frame.freeReg(fpReg);
101 :
102 85 : frame.popn(3);
103 85 : frame.pushDouble(fpResultReg);
104 :
105 85 : return Compile_Okay;
106 : }
107 :
108 : CompileStatus
109 184 : mjit::Compiler::compileRound(FrameEntry *arg, RoundingMode mode)
110 : {
111 184 : FPRegisterID fpScratchReg = frame.allocFPReg();
112 :
113 : FPRegisterID fpReg;
114 : bool allocate;
115 :
116 368 : DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
117 184 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
118 :
119 184 : masm.zeroDouble(fpScratchReg);
120 :
121 : /* Slow path for NaN and numbers <= 0. */
122 184 : Jump negOrNan = masm.branchDouble(Assembler::DoubleLessThanOrEqualOrUnordered, fpReg, fpScratchReg);
123 184 : stubcc.linkExit(negOrNan, Uses(3));
124 :
125 : /* For round add 0.5 and floor. */
126 : FPRegisterID fpSourceReg;
127 184 : if (mode == Round) {
128 51 : masm.slowLoadConstantDouble(0.5, fpScratchReg);
129 51 : masm.addDouble(fpReg, fpScratchReg);
130 51 : fpSourceReg = fpScratchReg;
131 : } else {
132 133 : fpSourceReg = fpReg;
133 : }
134 :
135 : /* Truncate to integer, slow path if this overflows. */
136 184 : RegisterID reg = frame.allocReg();
137 184 : Jump overflow = masm.branchTruncateDoubleToInt32(fpSourceReg, reg);
138 184 : stubcc.linkExit(overflow, Uses(3));
139 :
140 184 : if (allocate)
141 6 : frame.freeReg(fpReg);
142 184 : frame.freeReg(fpScratchReg);
143 :
144 184 : stubcc.leave();
145 184 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
146 184 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
147 :
148 184 : frame.popn(3);
149 184 : frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
150 :
151 184 : stubcc.rejoin(Changes(1));
152 184 : return Compile_Okay;
153 : }
154 :
155 : CompileStatus
156 178 : mjit::Compiler::compileMathSqrt(FrameEntry *arg)
157 : {
158 178 : FPRegisterID fpResultReg = frame.allocFPReg();
159 :
160 : FPRegisterID fpReg;
161 : bool allocate;
162 :
163 356 : DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
164 178 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
165 :
166 178 : masm.sqrtDouble(fpReg, fpResultReg);
167 :
168 178 : if (allocate)
169 56 : frame.freeReg(fpReg);
170 :
171 178 : frame.popn(3);
172 178 : frame.pushDouble(fpResultReg);
173 :
174 178 : return Compile_Okay;
175 : }
176 :
177 : CompileStatus
178 174 : mjit::Compiler::compileMathMinMaxDouble(FrameEntry *arg1, FrameEntry *arg2,
179 : Assembler::DoubleCondition cond)
180 : {
181 : FPRegisterID fpReg1;
182 : FPRegisterID fpReg2;
183 : bool allocate;
184 :
185 348 : DebugOnly<MaybeJump> notNumber = loadDouble(arg1, &fpReg1, &allocate);
186 174 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
187 :
188 174 : if (!allocate) {
189 136 : FPRegisterID fpResultReg = frame.allocFPReg();
190 136 : masm.moveDouble(fpReg1, fpResultReg);
191 136 : fpReg1 = fpResultReg;
192 : }
193 :
194 348 : DebugOnly<MaybeJump> notNumber2 = loadDouble(arg2, &fpReg2, &allocate);
195 174 : JS_ASSERT(!((MaybeJump)notNumber2).isSet());
196 :
197 :
198 : /* Slow path for 0 and NaN, because they have special requriments. */
199 174 : masm.zeroDouble(Registers::FPConversionTemp);
200 : Jump zeroOrNan = masm.branchDouble(Assembler::DoubleEqualOrUnordered, fpReg1,
201 174 : Registers::FPConversionTemp);
202 174 : stubcc.linkExit(zeroOrNan, Uses(4));
203 : Jump zeroOrNan2 = masm.branchDouble(Assembler::DoubleEqualOrUnordered, fpReg2,
204 174 : Registers::FPConversionTemp);
205 174 : stubcc.linkExit(zeroOrNan2, Uses(4));
206 :
207 :
208 174 : Jump ifTrue = masm.branchDouble(cond, fpReg1, fpReg2);
209 174 : masm.moveDouble(fpReg2, fpReg1);
210 :
211 174 : ifTrue.linkTo(masm.label(), &masm);
212 :
213 174 : if (allocate)
214 66 : frame.freeReg(fpReg2);
215 :
216 174 : stubcc.leave();
217 174 : stubcc.masm.move(Imm32(2), Registers::ArgReg1);
218 174 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
219 :
220 174 : frame.popn(4);
221 174 : frame.pushDouble(fpReg1);
222 :
223 174 : stubcc.rejoin(Changes(1));
224 174 : return Compile_Okay;
225 : }
226 :
227 : CompileStatus
228 87 : mjit::Compiler::compileMathMinMaxInt(FrameEntry *arg1, FrameEntry *arg2, Assembler::Condition cond)
229 : {
230 : /* Get this case out of the way */
231 87 : if (arg1->isConstant() && arg2->isConstant()) {
232 16 : int32_t a = arg1->getValue().toInt32();
233 16 : int32_t b = arg2->getValue().toInt32();
234 :
235 16 : frame.popn(4);
236 16 : if (cond == Assembler::LessThan)
237 8 : frame.push(Int32Value(a < b ? a : b));
238 : else
239 8 : frame.push(Int32Value(a > b ? a : b));
240 16 : return Compile_Okay;
241 : }
242 :
243 71 : Jump ifTrue;
244 : RegisterID reg;
245 71 : if (arg1->isConstant()) {
246 8 : reg = frame.copyDataIntoReg(arg2);
247 8 : int32_t v = arg1->getValue().toInt32();
248 :
249 8 : ifTrue = masm.branch32(cond, reg, Imm32(v));
250 8 : masm.move(Imm32(v), reg);
251 63 : } else if (arg2->isConstant()) {
252 14 : reg = frame.copyDataIntoReg(arg1);
253 14 : int32_t v = arg2->getValue().toInt32();
254 :
255 14 : ifTrue = masm.branch32(cond, reg, Imm32(v));
256 14 : masm.move(Imm32(v), reg);
257 : } else {
258 49 : reg = frame.copyDataIntoReg(arg1);
259 49 : RegisterID regB = frame.tempRegForData(arg2);
260 :
261 49 : ifTrue = masm.branch32(cond, reg, regB);
262 49 : masm.move(regB, reg);
263 : }
264 :
265 71 : ifTrue.linkTo(masm.label(), &masm);
266 71 : frame.popn(4);
267 71 : frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
268 71 : return Compile_Okay;
269 : }
270 :
271 : CompileStatus
272 10 : mjit::Compiler::compileMathPowSimple(FrameEntry *arg1, FrameEntry *arg2)
273 : {
274 10 : FPRegisterID fpScratchReg = frame.allocFPReg();
275 10 : FPRegisterID fpResultReg = frame.allocFPReg();
276 :
277 : FPRegisterID fpReg;
278 : bool allocate;
279 :
280 20 : DebugOnly<MaybeJump> notNumber = loadDouble(arg1, &fpReg, &allocate);
281 10 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
282 :
283 : /* Slow path for -Infinity (must return Infinity, not NaN). */
284 10 : masm.slowLoadConstantDouble(js_NegativeInfinity, fpResultReg);
285 10 : Jump isNegInfinity = masm.branchDouble(Assembler::DoubleEqual, fpReg, fpResultReg);
286 10 : stubcc.linkExit(isNegInfinity, Uses(4));
287 :
288 : /* Convert -0 to +0. */
289 10 : masm.zeroDouble(fpResultReg);
290 10 : masm.moveDouble(fpReg, fpScratchReg);
291 10 : masm.addDouble(fpResultReg, fpScratchReg);
292 :
293 10 : double y = arg2->getValue().toDouble();
294 10 : if (y == 0.5) {
295 : /* pow(x, 0.5) => sqrt(x) */
296 1 : masm.sqrtDouble(fpScratchReg, fpResultReg);
297 :
298 9 : } else if (y == -0.5) {
299 : /* pow(x, -0.5) => 1/sqrt(x) */
300 9 : masm.sqrtDouble(fpScratchReg, fpScratchReg);
301 9 : masm.slowLoadConstantDouble(1, fpResultReg);
302 9 : masm.divDouble(fpScratchReg, fpResultReg);
303 : }
304 :
305 10 : frame.freeReg(fpScratchReg);
306 :
307 10 : if (allocate)
308 9 : frame.freeReg(fpReg);
309 :
310 10 : stubcc.leave();
311 10 : stubcc.masm.move(Imm32(2), Registers::ArgReg1);
312 10 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
313 :
314 10 : frame.popn(4);
315 10 : frame.pushDouble(fpResultReg);
316 :
317 10 : stubcc.rejoin(Changes(1));
318 10 : return Compile_Okay;
319 : }
320 :
321 : CompileStatus
322 105 : mjit::Compiler::compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode)
323 : {
324 105 : RegisterID reg1 = frame.allocReg();
325 105 : RegisterID reg2 = frame.allocReg();
326 :
327 : /* Load string in strReg. */
328 : RegisterID strReg;
329 105 : if (thisValue->isConstant()) {
330 2 : strReg = frame.allocReg();
331 2 : masm.move(ImmPtr(thisValue->getValue().toString()), strReg);
332 : } else {
333 103 : strReg = frame.tempRegForData(thisValue);
334 103 : frame.pinReg(strReg);
335 : }
336 :
337 : /* Load index in argReg. */
338 : RegisterID argReg;
339 105 : if (arg->isConstant()) {
340 11 : argReg = frame.allocReg();
341 11 : masm.move(Imm32(arg->getValue().toInt32()), argReg);
342 : } else {
343 94 : argReg = frame.tempRegForData(arg);
344 : }
345 105 : if (!thisValue->isConstant())
346 103 : frame.unpinReg(strReg);
347 :
348 105 : Address lengthAndFlagsAddr(strReg, JSString::offsetOfLengthAndFlags());
349 :
350 : /* Load lengthAndFlags in reg1 and reg2 */
351 105 : masm.loadPtr(lengthAndFlagsAddr, reg1);
352 105 : masm.move(reg1, reg2);
353 :
354 : /* Slow path if string is a rope */
355 105 : masm.andPtr(ImmPtr((void *)JSString::ROPE_BIT), reg1);
356 105 : Jump isRope = masm.branchTestPtr(Assembler::NonZero, reg1);
357 105 : stubcc.linkExit(isRope, Uses(3));
358 :
359 : /* Slow path if out-of-range. */
360 105 : masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), reg2);
361 105 : Jump outOfRange = masm.branchPtr(Assembler::AboveOrEqual, argReg, reg2);
362 105 : stubcc.linkExit(outOfRange, Uses(3));
363 :
364 : /* Load char code in reg2. */
365 105 : masm.move(argReg, reg1);
366 105 : masm.loadPtr(Address(strReg, JSString::offsetOfChars()), reg2);
367 105 : masm.lshiftPtr(Imm32(1), reg1);
368 105 : masm.addPtr(reg1, reg2);
369 105 : masm.load16(Address(reg2), reg2);
370 :
371 : /* Convert char code to string. */
372 105 : if (mode == GetChar) {
373 : /* Slow path if there's no unit string for this character. */
374 : Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, reg2,
375 22 : Imm32(StaticStrings::UNIT_STATIC_LIMIT));
376 22 : stubcc.linkExit(notUnitString, Uses(3));
377 :
378 : /* Load unit string in reg2. */
379 22 : masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), reg2);
380 22 : masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), reg2);
381 22 : masm.loadPtr(Address(reg2), reg2);
382 : }
383 :
384 105 : if (thisValue->isConstant())
385 2 : frame.freeReg(strReg);
386 105 : if (arg->isConstant())
387 11 : frame.freeReg(argReg);
388 105 : frame.freeReg(reg1);
389 :
390 105 : stubcc.leave();
391 105 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
392 105 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
393 :
394 105 : frame.popn(3);
395 105 : switch(mode) {
396 : case GetCharCode:
397 83 : frame.pushTypedPayload(JSVAL_TYPE_INT32, reg2);
398 83 : break;
399 : case GetChar:
400 22 : frame.pushTypedPayload(JSVAL_TYPE_STRING, reg2);
401 22 : break;
402 : default:
403 0 : JS_NOT_REACHED("unknown getchar mode");
404 : }
405 :
406 105 : stubcc.rejoin(Changes(1));
407 105 : return Compile_Okay;
408 : }
409 :
410 : CompileStatus
411 72 : mjit::Compiler::compileStringFromCode(FrameEntry *arg)
412 : {
413 : /* Load Char-Code into argReg */
414 : RegisterID argReg;
415 72 : if (arg->isConstant()) {
416 0 : argReg = frame.allocReg();
417 0 : masm.move(Imm32(arg->getValue().toInt32()), argReg);
418 : } else {
419 72 : argReg = frame.copyDataIntoReg(arg);
420 : }
421 :
422 : /* Slow path if there's no unit string for this character. */
423 : Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, argReg,
424 72 : Imm32(StaticStrings::UNIT_STATIC_LIMIT));
425 72 : stubcc.linkExit(notUnitString, Uses(3));
426 :
427 : /* Load unit string in reg. */
428 72 : masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), argReg);
429 72 : masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), argReg);
430 72 : masm.loadPtr(Address(argReg), argReg);
431 :
432 72 : stubcc.leave();
433 72 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
434 72 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
435 :
436 72 : frame.popn(3);
437 72 : frame.pushTypedPayload(JSVAL_TYPE_STRING, argReg);
438 :
439 72 : stubcc.rejoin(Changes(1));
440 72 : return Compile_Okay;
441 : }
442 :
443 : CompileStatus
444 1226 : mjit::Compiler::compileArrayPush(FrameEntry *thisValue, FrameEntry *arg)
445 : {
446 : /* This behaves like an assignment this[this.length] = arg; */
447 :
448 : /* Filter out silly cases. */
449 1226 : if (frame.haveSameBacking(thisValue, arg) || thisValue->isConstant())
450 0 : return Compile_InlineAbort;
451 :
452 : /* Allocate registers. */
453 : ValueRemat vr;
454 1226 : frame.pinEntry(arg, vr, /* breakDouble = */ false);
455 :
456 1226 : RegisterID objReg = frame.tempRegForData(thisValue);
457 1226 : frame.pinReg(objReg);
458 :
459 1226 : RegisterID slotsReg = frame.allocReg();
460 1226 : masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
461 :
462 1226 : RegisterID lengthReg = frame.allocReg();
463 1226 : masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg);
464 :
465 1226 : frame.unpinReg(objReg);
466 :
467 1226 : Int32Key key = Int32Key::FromRegister(lengthReg);
468 :
469 : /* Test for 'length == initializedLength' */
470 : Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
471 1226 : slotsReg, key, Assembler::NotEqual);
472 1226 : stubcc.linkExit(initlenGuard, Uses(3));
473 :
474 : /* Test for 'length < capacity' */
475 : Jump capacityGuard = masm.guardArrayExtent(ObjectElements::offsetOfCapacity(),
476 1226 : slotsReg, key, Assembler::BelowOrEqual);
477 1226 : stubcc.linkExit(capacityGuard, Uses(3));
478 :
479 1226 : masm.storeValue(vr, BaseIndex(slotsReg, lengthReg, masm.JSVAL_SCALE));
480 :
481 1226 : masm.bumpKey(key, 1);
482 1226 : masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength()));
483 1226 : masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
484 :
485 1226 : stubcc.leave();
486 1226 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
487 1226 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
488 :
489 1226 : frame.unpinEntry(vr);
490 1226 : frame.freeReg(slotsReg);
491 1226 : frame.popn(3);
492 :
493 1226 : frame.pushTypedPayload(JSVAL_TYPE_INT32, lengthReg);
494 :
495 1226 : stubcc.rejoin(Changes(1));
496 1226 : return Compile_Okay;
497 : }
498 :
499 : CompileStatus
500 76 : mjit::Compiler::compileArrayPopShift(FrameEntry *thisValue, bool isPacked, bool isArrayPop)
501 : {
502 : /* Filter out silly cases. */
503 76 : if (thisValue->isConstant())
504 0 : return Compile_InlineAbort;
505 :
506 : #ifdef JSGC_INCREMENTAL_MJ
507 : /* Write barrier. */
508 76 : if (cx->compartment->needsBarrier())
509 6 : return Compile_InlineAbort;
510 : #endif
511 :
512 70 : RegisterID objReg = frame.tempRegForData(thisValue);
513 70 : frame.pinReg(objReg);
514 :
515 70 : RegisterID lengthReg = frame.allocReg();
516 70 : RegisterID slotsReg = frame.allocReg();
517 :
518 70 : JSValueType type = knownPushedType(0);
519 :
520 70 : MaybeRegisterID dataReg, typeReg;
521 70 : if (!analysis->popGuaranteed(PC)) {
522 64 : dataReg = frame.allocReg();
523 64 : if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE)
524 9 : typeReg = frame.allocReg();
525 : }
526 :
527 70 : if (isArrayPop) {
528 49 : frame.unpinReg(objReg);
529 : } else {
530 : /*
531 : * Sync up front for shift() so we can jump over the inline stub.
532 : * The result will be stored in memory rather than registers.
533 : */
534 21 : frame.syncAndKillEverything();
535 21 : frame.unpinKilledReg(objReg);
536 : }
537 :
538 70 : masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
539 70 : masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg);
540 :
541 : /* Test for 'length == initializedLength' */
542 70 : Int32Key key = Int32Key::FromRegister(lengthReg);
543 : Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
544 70 : slotsReg, key, Assembler::NotEqual);
545 70 : stubcc.linkExit(initlenGuard, Uses(3));
546 :
547 : /*
548 : * Test for length != 0. On zero length either take a slow call or generate
549 : * an undefined value, depending on whether the call is known to produce
550 : * undefined.
551 : */
552 70 : bool maybeUndefined = pushedTypeSet(0)->hasType(types::Type::UndefinedType());
553 70 : Jump emptyGuard = masm.branch32(Assembler::Equal, lengthReg, Imm32(0));
554 70 : if (!maybeUndefined)
555 56 : stubcc.linkExit(emptyGuard, Uses(3));
556 :
557 70 : masm.bumpKey(key, -1);
558 :
559 70 : if (dataReg.isSet()) {
560 64 : Jump holeCheck;
561 64 : if (isArrayPop) {
562 45 : BaseIndex slot(slotsReg, lengthReg, masm.JSVAL_SCALE);
563 45 : holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg.reg());
564 : } else {
565 19 : holeCheck = masm.fastArrayLoadSlot(Address(slotsReg), !isPacked, typeReg, dataReg.reg());
566 19 : Address addr = frame.addressOf(frame.peek(-2));
567 19 : if (typeReg.isSet())
568 2 : masm.storeValueFromComponents(typeReg.reg(), dataReg.reg(), addr);
569 : else
570 17 : masm.storeValueFromComponents(ImmType(type), dataReg.reg(), addr);
571 : }
572 64 : if (!isPacked)
573 47 : stubcc.linkExit(holeCheck, Uses(3));
574 : }
575 :
576 70 : masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength()));
577 70 : masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
578 :
579 70 : if (!isArrayPop)
580 21 : INLINE_STUBCALL(stubs::ArrayShift, REJOIN_NONE);
581 :
582 70 : stubcc.leave();
583 70 : stubcc.masm.move(Imm32(0), Registers::ArgReg1);
584 70 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
585 :
586 70 : frame.freeReg(slotsReg);
587 70 : frame.freeReg(lengthReg);
588 70 : frame.popn(2);
589 :
590 70 : if (dataReg.isSet()) {
591 64 : if (isArrayPop) {
592 45 : if (typeReg.isSet())
593 7 : frame.pushRegs(typeReg.reg(), dataReg.reg(), type);
594 : else
595 38 : frame.pushTypedPayload(type, dataReg.reg());
596 : } else {
597 19 : frame.pushSynced(type);
598 19 : if (typeReg.isSet())
599 2 : frame.freeReg(typeReg.reg());
600 19 : frame.freeReg(dataReg.reg());
601 : }
602 : } else {
603 6 : frame.push(UndefinedValue());
604 : }
605 :
606 70 : stubcc.rejoin(Changes(1));
607 :
608 70 : if (maybeUndefined) {
609 : /* Generate an OOL path to push an undefined value, and rejoin. */
610 14 : if (dataReg.isSet()) {
611 12 : stubcc.linkExitDirect(emptyGuard, stubcc.masm.label());
612 12 : if (isArrayPop) {
613 6 : if (typeReg.isSet()) {
614 6 : stubcc.masm.loadValueAsComponents(UndefinedValue(), typeReg.reg(), dataReg.reg());
615 : } else {
616 0 : JS_ASSERT(type == JSVAL_TYPE_UNDEFINED);
617 0 : stubcc.masm.loadValuePayload(UndefinedValue(), dataReg.reg());
618 : }
619 : } else {
620 6 : stubcc.masm.storeValue(UndefinedValue(), frame.addressOf(frame.peek(-1)));
621 : }
622 12 : stubcc.crossJump(stubcc.masm.jump(), masm.label());
623 : } else {
624 2 : emptyGuard.linkTo(masm.label(), &masm);
625 : }
626 : }
627 :
628 70 : return Compile_Okay;
629 : }
630 :
631 : CompileStatus
632 24 : mjit::Compiler::compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *argTypes,
633 : FrameEntry *thisValue, FrameEntry *argValue)
634 : {
635 : /*
636 : * Require the 'this' types to have a specific type matching the current
637 : * global, so we can create the result object inline.
638 : */
639 24 : if (thisTypes->getObjectCount() != 1)
640 0 : return Compile_InlineAbort;
641 24 : types::TypeObject *thisType = thisTypes->getTypeObject(0);
642 24 : if (!thisType || &thisType->proto->global() != globalObj)
643 0 : return Compile_InlineAbort;
644 :
645 : /*
646 : * Constraints modeling this concat have not been generated by inference,
647 : * so check that type information already reflects possible side effects of
648 : * this call.
649 : */
650 24 : thisTypes->addFreeze(cx);
651 24 : argTypes->addFreeze(cx);
652 24 : types::TypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID, false);
653 24 : if (!thisElemTypes)
654 0 : return Compile_Error;
655 24 : if (!pushedTypeSet(0)->hasType(types::Type::ObjectType(thisType)))
656 0 : return Compile_InlineAbort;
657 46 : for (unsigned i = 0; i < argTypes->getObjectCount(); i++) {
658 24 : if (argTypes->getSingleObject(i))
659 0 : return Compile_InlineAbort;
660 24 : types::TypeObject *argType = argTypes->getTypeObject(i);
661 24 : if (!argType)
662 0 : continue;
663 24 : types::TypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
664 24 : if (!elemTypes)
665 0 : return Compile_Error;
666 24 : if (!elemTypes->knownSubset(cx, thisElemTypes))
667 2 : return Compile_InlineAbort;
668 : }
669 :
670 : /* Test for 'length == initializedLength' on both arrays. */
671 :
672 22 : RegisterID slotsReg = frame.allocReg();
673 22 : RegisterID reg = frame.allocReg();
674 :
675 22 : Int32Key key = Int32Key::FromRegister(reg);
676 :
677 22 : RegisterID objReg = frame.tempRegForData(thisValue);
678 22 : masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
679 22 : masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), reg);
680 : Jump initlenOneGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
681 22 : slotsReg, key, Assembler::NotEqual);
682 22 : stubcc.linkExit(initlenOneGuard, Uses(3));
683 :
684 22 : objReg = frame.tempRegForData(argValue);
685 22 : masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
686 22 : masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), reg);
687 : Jump initlenTwoGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
688 22 : slotsReg, key, Assembler::NotEqual);
689 22 : stubcc.linkExit(initlenTwoGuard, Uses(3));
690 :
691 22 : frame.freeReg(reg);
692 22 : frame.freeReg(slotsReg);
693 22 : frame.syncAndForgetEverything();
694 :
695 : /*
696 : * The current stack layout is 'CALLEE THIS ARG'. Allocate the result and
697 : * scribble it over the callee, which will be its final position after the
698 : * call.
699 : */
700 :
701 22 : JSObject *templateObject = NewDenseEmptyArray(cx, thisType->proto);
702 22 : if (!templateObject)
703 0 : return Compile_Error;
704 22 : templateObject->setType(thisType);
705 :
706 22 : RegisterID result = Registers::ReturnReg;
707 22 : Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
708 22 : stubcc.linkExit(emptyFreeList, Uses(3));
709 :
710 22 : masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), result, frame.addressOf(frame.peek(-3)));
711 22 : INLINE_STUBCALL(stubs::ArrayConcatTwoArrays, REJOIN_FALLTHROUGH);
712 :
713 22 : stubcc.leave();
714 22 : stubcc.masm.move(Imm32(1), Registers::ArgReg1);
715 22 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
716 :
717 22 : frame.popn(3);
718 22 : frame.pushSynced(JSVAL_TYPE_OBJECT);
719 :
720 22 : stubcc.rejoin(Changes(1));
721 22 : return Compile_Okay;
722 : }
723 :
724 : CompileStatus
725 965 : mjit::Compiler::compileArrayWithLength(uint32_t argc)
726 : {
727 : /* Match Array() or Array(n) for constant n. */
728 965 : JS_ASSERT(argc == 0 || argc == 1);
729 :
730 965 : int32_t length = 0;
731 965 : if (argc == 1) {
732 620 : FrameEntry *arg = frame.peek(-1);
733 620 : if (!arg->isConstant() || !arg->getValue().isInt32())
734 301 : return Compile_InlineAbort;
735 319 : length = arg->getValue().toInt32();
736 319 : if (length < 0)
737 0 : return Compile_InlineAbort;
738 : }
739 :
740 664 : types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
741 664 : if (!type)
742 0 : return Compile_Error;
743 :
744 664 : JSObject *templateObject = NewDenseUnallocatedArray(cx, length, type->proto);
745 664 : if (!templateObject)
746 0 : return Compile_Error;
747 664 : templateObject->setType(type);
748 :
749 664 : RegisterID result = frame.allocReg();
750 664 : Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
751 :
752 664 : stubcc.linkExit(emptyFreeList, Uses(0));
753 664 : stubcc.leave();
754 :
755 664 : stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
756 664 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
757 :
758 664 : frame.popn(argc + 2);
759 664 : frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
760 :
761 664 : stubcc.rejoin(Changes(1));
762 664 : return Compile_Okay;
763 : }
764 :
765 : CompileStatus
766 124 : mjit::Compiler::compileArrayWithArgs(uint32_t argc)
767 : {
768 : /*
769 : * Match Array(x, y, z) with at least two arguments. Don't inline the case
770 : * where a non-number argument is passed, so we don't need to care about
771 : * the types of the arguments.
772 : */
773 124 : JS_ASSERT(argc >= 2);
774 :
775 : size_t maxArraySlots =
776 124 : gc::GetGCKindSlots(gc::FINALIZE_OBJECT_LAST) - ObjectElements::VALUES_PER_HEADER;
777 :
778 124 : if (argc > maxArraySlots)
779 0 : return Compile_InlineAbort;
780 :
781 124 : types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
782 124 : if (!type)
783 0 : return Compile_Error;
784 :
785 124 : JSObject *templateObject = NewDenseUnallocatedArray(cx, argc, type->proto);
786 124 : if (!templateObject)
787 0 : return Compile_Error;
788 124 : templateObject->setType(type);
789 :
790 124 : JS_ASSERT(templateObject->getDenseArrayCapacity() >= argc);
791 :
792 124 : RegisterID result = frame.allocReg();
793 124 : Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
794 124 : stubcc.linkExit(emptyFreeList, Uses(0));
795 :
796 124 : int offset = JSObject::offsetOfFixedElements();
797 : masm.store32(Imm32(argc),
798 124 : Address(result, offset + ObjectElements::offsetOfInitializedLength()));
799 :
800 511 : for (unsigned i = 0; i < argc; i++) {
801 387 : FrameEntry *arg = frame.peek(-(int32_t)argc + i);
802 387 : frame.storeTo(arg, Address(result, offset), /* popped = */ true);
803 387 : offset += sizeof(Value);
804 : }
805 :
806 124 : stubcc.leave();
807 :
808 124 : stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
809 124 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
810 :
811 124 : frame.popn(argc + 2);
812 124 : frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
813 :
814 124 : stubcc.rejoin(Changes(1));
815 124 : return Compile_Okay;
816 : }
817 :
818 : CompileStatus
819 199 : mjit::Compiler::compileParseInt(JSValueType argType, uint32_t argc)
820 : {
821 199 : bool needStubCall = false;
822 :
823 199 : if (argc > 1) {
824 30 : FrameEntry *arg = frame.peek(-(int32_t)argc + 1);
825 :
826 30 : if (!arg->isTypeKnown() || arg->getKnownType() != JSVAL_TYPE_INT32)
827 2 : return Compile_InlineAbort;
828 :
829 28 : if (arg->isConstant()) {
830 20 : int32_t base = arg->getValue().toInt32();
831 20 : if (base != 0 && base != 10)
832 0 : return Compile_InlineAbort;
833 : } else {
834 8 : RegisterID baseReg = frame.tempRegForData(arg);
835 8 : needStubCall = true;
836 :
837 8 : Jump isTen = masm.branch32(Assembler::Equal, baseReg, Imm32(10));
838 8 : Jump isNotZero = masm.branch32(Assembler::NotEqual, baseReg, Imm32(0));
839 8 : stubcc.linkExit(isNotZero, Uses(2 + argc));
840 :
841 8 : isTen.linkTo(masm.label(), &masm);
842 : }
843 : }
844 :
845 197 : if (argType == JSVAL_TYPE_INT32) {
846 24 : if (needStubCall) {
847 3 : stubcc.leave();
848 3 : stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
849 3 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
850 : }
851 :
852 : /*
853 : * Stack looks like callee, this, arg1, arg2, argN.
854 : * First pop all args other than arg1.
855 : */
856 24 : frame.popn(argc - 1);
857 : /* "Shimmy" arg1 to the callee slot and pop this + arg1. */
858 24 : frame.shimmy(2);
859 :
860 24 : if (needStubCall) {
861 3 : stubcc.rejoin(Changes(1));
862 : }
863 : } else {
864 173 : FrameEntry *arg = frame.peek(-(int32_t)argc);
865 173 : FPRegisterID fpScratchReg = frame.allocFPReg();
866 : FPRegisterID fpReg;
867 : bool allocate;
868 :
869 346 : DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
870 173 : JS_ASSERT(!((MaybeJump)notNumber).isSet());
871 :
872 173 : masm.slowLoadConstantDouble(1, fpScratchReg);
873 :
874 : /* Slow path for NaN and numbers < 1. */
875 : Jump lessThanOneOrNan = masm.branchDouble(Assembler::DoubleLessThanOrUnordered,
876 173 : fpReg, fpScratchReg);
877 173 : stubcc.linkExit(lessThanOneOrNan, Uses(2 + argc));
878 :
879 173 : frame.freeReg(fpScratchReg);
880 :
881 : /* Truncate to integer, slow path if this overflows. */
882 173 : RegisterID reg = frame.allocReg();
883 173 : Jump overflow = masm.branchTruncateDoubleToInt32(fpReg, reg);
884 173 : stubcc.linkExit(overflow, Uses(2 + argc));
885 :
886 173 : if (allocate)
887 112 : frame.freeReg(fpReg);
888 :
889 173 : stubcc.leave();
890 173 : stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
891 173 : OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
892 :
893 173 : frame.popn(2 + argc);
894 173 : frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
895 :
896 173 : stubcc.rejoin(Changes(1));
897 : }
898 :
899 197 : return Compile_Okay;
900 : }
901 :
902 : CompileStatus
903 287828 : mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
904 : {
905 287828 : if (!cx->typeInferenceEnabled())
906 168723 : return Compile_InlineAbort;
907 :
908 119105 : if (applyTricks == LazyArgsObj)
909 0 : return Compile_InlineAbort;
910 :
911 119105 : FrameEntry *origCallee = frame.peek(-((int)argc + 2));
912 119105 : FrameEntry *thisValue = frame.peek(-((int)argc + 1));
913 119105 : types::TypeSet *thisTypes = analysis->poppedTypes(PC, argc);
914 :
915 119105 : if (!origCallee->isConstant() || !origCallee->isType(JSVAL_TYPE_OBJECT))
916 67400 : return Compile_InlineAbort;
917 :
918 51705 : JSObject *callee = &origCallee->getValue().toObject();
919 51705 : if (!callee->isFunction())
920 0 : return Compile_InlineAbort;
921 :
922 : /*
923 : * The callee must have the same parent as the script's global, otherwise
924 : * inference may not have accounted for any side effects correctly.
925 : */
926 51705 : if (!globalObj || globalObj != &callee->global())
927 284 : return Compile_InlineAbort;
928 :
929 51421 : Native native = callee->toFunction()->maybeNative();
930 :
931 51421 : if (!native)
932 12250 : return Compile_InlineAbort;
933 :
934 39171 : JSValueType type = knownPushedType(0);
935 39171 : JSValueType thisType = thisValue->isTypeKnown()
936 : ? thisValue->getKnownType()
937 39171 : : JSVAL_TYPE_UNKNOWN;
938 :
939 : /*
940 : * Note: when adding new natives which operate on properties, add relevant
941 : * constraint generation to the behavior of TypeConstraintCall.
942 : */
943 :
944 : /* Handle natives that can be called either with or without 'new'. */
945 :
946 39171 : if (native == js_Array && type == JSVAL_TYPE_OBJECT && globalObj) {
947 1089 : if (argc == 0 || argc == 1)
948 965 : return compileArrayWithLength(argc);
949 124 : return compileArrayWithArgs(argc);
950 : }
951 :
952 : /* Remaining natives must not be called with 'new'. */
953 38082 : if (callingNew)
954 1766 : return Compile_InlineAbort;
955 :
956 36316 : if (native == js::num_parseInt && argc >= 1) {
957 323 : FrameEntry *arg = frame.peek(-(int32_t)argc);
958 323 : JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
959 :
960 323 : if ((argType == JSVAL_TYPE_DOUBLE || argType == JSVAL_TYPE_INT32) &&
961 : type == JSVAL_TYPE_INT32) {
962 199 : return compileParseInt(argType, argc);
963 : }
964 : }
965 :
966 36117 : if (argc == 0) {
967 2267 : if ((native == js::array_pop || native == js::array_shift) && thisType == JSVAL_TYPE_OBJECT) {
968 : /*
969 : * Only handle pop/shift on dense arrays which have never been used
970 : * in an iterator --- when popping elements we don't account for
971 : * suppressing deleted properties in active iterators.
972 : *
973 : * Constraints propagating properties directly into the result
974 : * type set are generated by TypeConstraintCall during inference.
975 : */
976 160 : if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY |
977 84 : types::OBJECT_FLAG_ITERATED) &&
978 76 : !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
979 76 : bool packed = !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
980 76 : return compileArrayPopShift(thisValue, packed, native == js::array_pop);
981 : }
982 : }
983 33850 : } else if (argc == 1) {
984 16706 : FrameEntry *arg = frame.peek(-1);
985 16706 : types::TypeSet *argTypes = frame.extra(arg).types;
986 16706 : if (!argTypes)
987 0 : return Compile_InlineAbort;
988 16706 : JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
989 :
990 16706 : if (native == js_math_abs) {
991 270 : if (argType == JSVAL_TYPE_INT32 && type == JSVAL_TYPE_INT32)
992 36 : return compileMathAbsInt(arg);
993 :
994 234 : if (argType == JSVAL_TYPE_DOUBLE && type == JSVAL_TYPE_DOUBLE)
995 85 : return compileMathAbsDouble(arg);
996 : }
997 16585 : if (native == js_math_floor && argType == JSVAL_TYPE_DOUBLE &&
998 : type == JSVAL_TYPE_INT32) {
999 133 : return compileRound(arg, Floor);
1000 : }
1001 16452 : if (native == js_math_round && argType == JSVAL_TYPE_DOUBLE &&
1002 : type == JSVAL_TYPE_INT32) {
1003 51 : return compileRound(arg, Round);
1004 : }
1005 16582 : if (native == js_math_sqrt && type == JSVAL_TYPE_DOUBLE &&
1006 181 : masm.supportsFloatingPointSqrt() &&
1007 : (argType == JSVAL_TYPE_INT32 || argType == JSVAL_TYPE_DOUBLE)) {
1008 178 : return compileMathSqrt(arg);
1009 : }
1010 16223 : if (native == js_str_charCodeAt && argType == JSVAL_TYPE_INT32 &&
1011 : thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_INT32) {
1012 83 : return compileGetChar(thisValue, arg, GetCharCode);
1013 : }
1014 16140 : if (native == js_str_charAt && argType == JSVAL_TYPE_INT32 &&
1015 : thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_STRING) {
1016 22 : return compileGetChar(thisValue, arg, GetChar);
1017 : }
1018 16118 : if (native == js::str_fromCharCode && argType == JSVAL_TYPE_INT32 &&
1019 : type == JSVAL_TYPE_STRING) {
1020 72 : return compileStringFromCode(arg);
1021 : }
1022 16046 : if (native == js::array_push &&
1023 : thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_INT32) {
1024 : /*
1025 : * Constraints propagating properties into the 'this' object are
1026 : * generated by TypeConstraintCall during inference.
1027 : */
1028 2479 : if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
1029 1238 : !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
1030 1226 : return compileArrayPush(thisValue, arg);
1031 : }
1032 : }
1033 14974 : if (native == js::array_concat && argType == JSVAL_TYPE_OBJECT &&
1034 : thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_OBJECT &&
1035 77 : !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
1036 77 : !argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
1037 24 : return compileArrayConcat(thisTypes, argTypes, thisValue, arg);
1038 : }
1039 17144 : } else if (argc == 2) {
1040 16460 : FrameEntry *arg1 = frame.peek(-2);
1041 16460 : FrameEntry *arg2 = frame.peek(-1);
1042 :
1043 16460 : JSValueType arg1Type = arg1->isTypeKnown() ? arg1->getKnownType() : JSVAL_TYPE_UNKNOWN;
1044 16460 : JSValueType arg2Type = arg2->isTypeKnown() ? arg2->getKnownType() : JSVAL_TYPE_UNKNOWN;
1045 :
1046 16819 : if (native == js_math_pow && type == JSVAL_TYPE_DOUBLE &&
1047 211 : masm.supportsFloatingPointSqrt() &&
1048 : (arg1Type == JSVAL_TYPE_DOUBLE || arg1Type == JSVAL_TYPE_INT32) &&
1049 148 : arg2Type == JSVAL_TYPE_DOUBLE && arg2->isConstant())
1050 : {
1051 10 : Value arg2Value = arg2->getValue();
1052 10 : if (arg2Value.toDouble() == -0.5 || arg2Value.toDouble() == 0.5)
1053 10 : return compileMathPowSimple(arg1, arg2);
1054 : }
1055 16450 : if ((native == js_math_min || native == js_math_max)) {
1056 337 : if (arg1Type == JSVAL_TYPE_INT32 && arg2Type == JSVAL_TYPE_INT32 &&
1057 : type == JSVAL_TYPE_INT32) {
1058 : return compileMathMinMaxInt(arg1, arg2,
1059 87 : native == js_math_min ? Assembler::LessThan : Assembler::GreaterThan);
1060 : }
1061 250 : if ((arg1Type == JSVAL_TYPE_INT32 || arg1Type == JSVAL_TYPE_DOUBLE) &&
1062 : (arg2Type == JSVAL_TYPE_INT32 || arg2Type == JSVAL_TYPE_DOUBLE) &&
1063 : type == JSVAL_TYPE_DOUBLE) {
1064 : return compileMathMinMaxDouble(arg1, arg2,
1065 : (native == js_math_min)
1066 : ? Assembler::DoubleLessThan
1067 174 : : Assembler::DoubleGreaterThan);
1068 : }
1069 : }
1070 : }
1071 33860 : return Compile_InlineAbort;
1072 : }
1073 :
|