OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 } | 195 } |
196 | 196 |
197 static MemOperand ContextOperand(Register context, int index) { | 197 static MemOperand ContextOperand(Register context, int index) { |
198 return MemOperand(context, Context::SlotOffset(index)); | 198 return MemOperand(context, Context::SlotOffset(index)); |
199 } | 199 } |
200 | 200 |
201 static MemOperand ParameterOperand(Scope* scope, int index) { | 201 static MemOperand ParameterOperand(Scope* scope, int index) { |
202 // index -2 corresponds to the activated closure, -1 corresponds | 202 // index -2 corresponds to the activated closure, -1 corresponds |
203 // to the receiver | 203 // to the receiver |
204 ASSERT(-2 <= index && index < scope->num_parameters()); | 204 ASSERT(-2 <= index && index < scope->num_parameters()); |
205 int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize; | 205 int offset = (1 + scope->num_parameters() - index) * kPointerSize; |
206 return MemOperand(pp, offset); | 206 return MemOperand(fp, offset); |
207 } | 207 } |
208 | 208 |
209 MemOperand ParameterOperand(int index) const { | 209 MemOperand ParameterOperand(int index) const { |
210 return ParameterOperand(scope_, index); | 210 return ParameterOperand(scope_, index); |
211 } | 211 } |
212 | 212 |
213 MemOperand FunctionOperand() const { return ParameterOperand(-2); } | 213 MemOperand FunctionOperand() const { |
| 214 return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset); |
| 215 } |
214 | 216 |
215 static MemOperand SlotOperand(MacroAssembler* masm, | 217 static MemOperand SlotOperand(MacroAssembler* masm, |
216 Scope* scope, | 218 Scope* scope, |
217 Slot* slot, | 219 Slot* slot, |
218 Register tmp); | 220 Register tmp); |
219 | 221 |
220 MemOperand SlotOperand(Slot* slot, Register tmp) { | 222 MemOperand SlotOperand(Slot* slot, Register tmp) { |
221 return SlotOperand(masm_, scope_, slot, tmp); | 223 return SlotOperand(masm_, scope_, slot, tmp); |
222 } | 224 } |
223 | 225 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 | 300 |
299 // Node visitors | 301 // Node visitors |
300 #define DEF_VISIT(type) \ | 302 #define DEF_VISIT(type) \ |
301 virtual void Visit##type(type* node); | 303 virtual void Visit##type(type* node); |
302 NODE_LIST(DEF_VISIT) | 304 NODE_LIST(DEF_VISIT) |
303 #undef DEF_VISIT | 305 #undef DEF_VISIT |
304 | 306 |
305 void RecordStatementPosition(Node* node); | 307 void RecordStatementPosition(Node* node); |
306 | 308 |
307 // Activation frames | 309 // Activation frames |
308 void EnterJSFrame(int argc); // preserves r1 | 310 void EnterJSFrame(); |
309 void ExitJSFrame(ExitJSFlag flag = RETURN); // preserves r0-r2 | 311 void ExitJSFrame(); |
310 | 312 |
311 virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args); | 313 virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args); |
312 virtual void GenerateSetThisFunction(ZoneList<Expression*>* args); | 314 virtual void GenerateSetThisFunction(ZoneList<Expression*>* args); |
313 virtual void GenerateGetThisFunction(ZoneList<Expression*>* args); | 315 virtual void GenerateGetThisFunction(ZoneList<Expression*>* args); |
314 virtual void GenerateSetThis(ZoneList<Expression*>* args); | 316 virtual void GenerateSetThis(ZoneList<Expression*>* args); |
315 virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args); | 317 virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args); |
316 virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args); | 318 virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args); |
317 virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args); | 319 virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args); |
318 virtual void GenerateSetArgument(ZoneList<Expression*>* args); | 320 virtual void GenerateSetArgument(ZoneList<Expression*>* args); |
319 virtual void GenerateSquashFrame(ZoneList<Expression*>* args); | 321 virtual void GenerateSquashFrame(ZoneList<Expression*>* args); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 | 463 |
462 // Entry | 464 // Entry |
463 // stack: function, receiver, arguments, return address | 465 // stack: function, receiver, arguments, return address |
464 // r0: number of arguments | 466 // r0: number of arguments |
465 // sp: stack pointer | 467 // sp: stack pointer |
466 // fp: frame pointer | 468 // fp: frame pointer |
467 // pp: caller's parameter pointer | 469 // pp: caller's parameter pointer |
468 // cp: callee's context | 470 // cp: callee's context |
469 | 471 |
470 { Comment cmnt(masm_, "[ enter JS frame"); | 472 { Comment cmnt(masm_, "[ enter JS frame"); |
471 EnterJSFrame(scope->num_parameters()); | 473 EnterJSFrame(); |
472 } | 474 } |
473 // tos: code slot | 475 // tos: code slot |
474 #ifdef DEBUG | 476 #ifdef DEBUG |
475 if (strlen(FLAG_stop_at) > 0 && | 477 if (strlen(FLAG_stop_at) > 0 && |
476 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 478 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
477 __ stop("stop-at"); | 479 __ stop("stop-at"); |
478 } | 480 } |
479 #endif | 481 #endif |
480 | 482 |
481 // Allocate space for locals and initialize them. | 483 // Allocate space for locals and initialize them. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 // passed to the parameter that needs to be copied. This is a rare | 521 // passed to the parameter that needs to be copied. This is a rare |
520 // case so we don't check for it, instead we rely on the copying | 522 // case so we don't check for it, instead we rely on the copying |
521 // order: such a parameter is copied repeatedly into the same | 523 // order: such a parameter is copied repeatedly into the same |
522 // context location and thus the last value is what is seen inside | 524 // context location and thus the last value is what is seen inside |
523 // the function. | 525 // the function. |
524 for (int i = 0; i < scope->num_parameters(); i++) { | 526 for (int i = 0; i < scope->num_parameters(); i++) { |
525 Variable* par = scope->parameter(i); | 527 Variable* par = scope->parameter(i); |
526 Slot* slot = par->slot(); | 528 Slot* slot = par->slot(); |
527 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 529 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
528 ASSERT(!scope->is_global_scope()); // no parameters in global scope | 530 ASSERT(!scope->is_global_scope()); // no parameters in global scope |
529 int parameter_offset = | 531 __ ldr(r1, ParameterOperand(i)); |
530 JavaScriptFrameConstants::kParam0Offset - i * kPointerSize; | |
531 __ ldr(r1, MemOperand(pp, parameter_offset)); | |
532 // Loads r2 with context; used below in RecordWrite. | 532 // Loads r2 with context; used below in RecordWrite. |
533 __ str(r1, SlotOperand(slot, r2)); | 533 __ str(r1, SlotOperand(slot, r2)); |
534 // Load the offset into r3. | 534 // Load the offset into r3. |
535 int slot_offset = | 535 int slot_offset = |
536 FixedArray::kHeaderSize + slot->index() * kPointerSize; | 536 FixedArray::kHeaderSize + slot->index() * kPointerSize; |
537 __ mov(r3, Operand(slot_offset)); | 537 __ mov(r3, Operand(slot_offset)); |
538 __ RecordWrite(r2, r3, r1); | 538 __ RecordWrite(r2, r3, r1); |
539 } | 539 } |
540 } | 540 } |
541 } | 541 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 __ mov(r0, Operand(Factory::undefined_value())); | 622 __ mov(r0, Operand(Factory::undefined_value())); |
623 | 623 |
624 __ bind(&function_return_); | 624 __ bind(&function_return_); |
625 if (FLAG_trace) { | 625 if (FLAG_trace) { |
626 // Push the return value on the stack as the parameter. | 626 // Push the return value on the stack as the parameter. |
627 // Runtime::TraceExit returns the parameter as it is. | 627 // Runtime::TraceExit returns the parameter as it is. |
628 __ push(r0); | 628 __ push(r0); |
629 __ CallRuntime(Runtime::kTraceExit, 1); | 629 __ CallRuntime(Runtime::kTraceExit, 1); |
630 } | 630 } |
631 | 631 |
| 632 // Tear down the frame which will restore the caller's frame pointer and the |
| 633 // link register. |
632 ExitJSFrame(); | 634 ExitJSFrame(); |
633 | 635 |
| 636 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); |
| 637 __ mov(pc, lr); |
| 638 |
634 // Code generation state must be reset. | 639 // Code generation state must be reset. |
635 scope_ = NULL; | 640 scope_ = NULL; |
636 ASSERT(!has_cc()); | 641 ASSERT(!has_cc()); |
637 ASSERT(state_ == NULL); | 642 ASSERT(state_ == NULL); |
638 } | 643 } |
639 | 644 |
640 | 645 |
641 MemOperand ArmCodeGenerator::SlotOperand(MacroAssembler* masm, | 646 MemOperand ArmCodeGenerator::SlotOperand(MacroAssembler* masm, |
642 Scope* scope, | 647 Scope* scope, |
643 Slot* slot, | 648 Slot* slot, |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 // hole' value and by doing so, end up calling this code. r2 may be | 976 // hole' value and by doing so, end up calling this code. r2 may be |
972 // loaded with context; used below in RecordWrite. | 977 // loaded with context; used below in RecordWrite. |
973 masm->pop(r0); | 978 masm->pop(r0); |
974 masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); | 979 masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
975 masm->push(r0); | 980 masm->push(r0); |
976 | 981 |
977 if (type() == Slot::CONTEXT) { | 982 if (type() == Slot::CONTEXT) { |
978 // Skip write barrier if the written value is a smi. | 983 // Skip write barrier if the written value is a smi. |
979 masm->tst(r0, Operand(kSmiTagMask)); | 984 masm->tst(r0, Operand(kSmiTagMask)); |
980 masm->b(eq, &exit); | 985 masm->b(eq, &exit); |
| 986 may_skip_write = true; |
981 // r2 is loaded with context when calling SlotOperand above. | 987 // r2 is loaded with context when calling SlotOperand above. |
982 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | 988 int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
983 masm->mov(r3, Operand(offset)); | 989 masm->mov(r3, Operand(offset)); |
984 masm->RecordWrite(r2, r3, r1); | 990 masm->RecordWrite(r2, r3, r1); |
985 } | 991 } |
986 // If we definitely did not jump over the assignment, we do not need to | 992 // If we definitely did not jump over the assignment, we do not need to |
987 // bind the exit label. Doing so can defeat peephole optimization. | 993 // bind the exit label. Doing so can defeat peephole optimization. |
988 if (may_skip_write) masm->bind(&exit); | 994 if (may_skip_write) masm->bind(&exit); |
989 } | 995 } |
990 } | 996 } |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1274 // go slow-path in case of non-smi operands | 1280 // go slow-path in case of non-smi operands |
1275 ASSERT(kSmiTag == 0); // adjust code below | 1281 ASSERT(kSmiTag == 0); // adjust code below |
1276 __ tst(r2, Operand(kSmiTagMask)); | 1282 __ tst(r2, Operand(kSmiTagMask)); |
1277 __ b(eq, &exit); | 1283 __ b(eq, &exit); |
1278 // slow path | 1284 // slow path |
1279 __ bind(&slow); | 1285 __ bind(&slow); |
1280 __ sub(r0, r0, Operand(r1)); // revert optimistic add | 1286 __ sub(r0, r0, Operand(r1)); // revert optimistic add |
1281 __ push(r1); | 1287 __ push(r1); |
1282 __ push(r0); | 1288 __ push(r0); |
1283 __ mov(r0, Operand(1)); // set number of arguments | 1289 __ mov(r0, Operand(1)); // set number of arguments |
1284 __ InvokeBuiltin("ADD", 1, JUMP_JS); | 1290 __ InvokeBuiltin(Builtins::ADD, JUMP_JS); |
1285 // done | 1291 // done |
1286 __ bind(&exit); | 1292 __ bind(&exit); |
1287 break; | 1293 break; |
1288 } | 1294 } |
1289 | 1295 |
1290 case Token::SUB: { | 1296 case Token::SUB: { |
1291 Label slow, exit; | 1297 Label slow, exit; |
1292 // fast path | 1298 // fast path |
1293 __ orr(r2, r1, Operand(r0)); // r2 = x | y; | 1299 __ orr(r2, r1, Operand(r0)); // r2 = x | y; |
1294 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically | 1300 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically |
1295 // go slow-path in case of overflow | 1301 // go slow-path in case of overflow |
1296 __ b(vs, &slow); | 1302 __ b(vs, &slow); |
1297 // go slow-path in case of non-smi operands | 1303 // go slow-path in case of non-smi operands |
1298 ASSERT(kSmiTag == 0); // adjust code below | 1304 ASSERT(kSmiTag == 0); // adjust code below |
1299 __ tst(r2, Operand(kSmiTagMask)); | 1305 __ tst(r2, Operand(kSmiTagMask)); |
1300 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result | 1306 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result |
1301 __ b(eq, &exit); | 1307 __ b(eq, &exit); |
1302 // slow path | 1308 // slow path |
1303 __ bind(&slow); | 1309 __ bind(&slow); |
1304 __ push(r1); | 1310 __ push(r1); |
1305 __ push(r0); | 1311 __ push(r0); |
1306 __ mov(r0, Operand(1)); // set number of arguments | 1312 __ mov(r0, Operand(1)); // set number of arguments |
1307 __ InvokeBuiltin("SUB", 1, JUMP_JS); | 1313 __ InvokeBuiltin(Builtins::SUB, JUMP_JS); |
1308 // done | 1314 // done |
1309 __ bind(&exit); | 1315 __ bind(&exit); |
1310 break; | 1316 break; |
1311 } | 1317 } |
1312 | 1318 |
1313 case Token::MUL: { | 1319 case Token::MUL: { |
1314 Label slow, exit; | 1320 Label slow, exit; |
1315 // tag check | 1321 // tag check |
1316 __ orr(r2, r1, Operand(r0)); // r2 = x | y; | 1322 __ orr(r2, r1, Operand(r0)); // r2 = x | y; |
1317 ASSERT(kSmiTag == 0); // adjust code below | 1323 ASSERT(kSmiTag == 0); // adjust code below |
1318 __ tst(r2, Operand(kSmiTagMask)); | 1324 __ tst(r2, Operand(kSmiTagMask)); |
1319 __ b(ne, &slow); | 1325 __ b(ne, &slow); |
1320 // remove tag from one operand (but keep sign), so that result is smi | 1326 // remove tag from one operand (but keep sign), so that result is smi |
1321 __ mov(ip, Operand(r0, ASR, kSmiTagSize)); | 1327 __ mov(ip, Operand(r0, ASR, kSmiTagSize)); |
1322 // do multiplication | 1328 // do multiplication |
1323 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1 | 1329 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1 |
1324 // go slow on overflows (overflow bit is not set) | 1330 // go slow on overflows (overflow bit is not set) |
1325 __ mov(ip, Operand(r3, ASR, 31)); | 1331 __ mov(ip, Operand(r3, ASR, 31)); |
1326 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical | 1332 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical |
1327 __ b(ne, &slow); | 1333 __ b(ne, &slow); |
1328 // go slow on zero result to handle -0 | 1334 // go slow on zero result to handle -0 |
1329 __ tst(r3, Operand(r3)); | 1335 __ tst(r3, Operand(r3)); |
1330 __ mov(r0, Operand(r3), LeaveCC, ne); | 1336 __ mov(r0, Operand(r3), LeaveCC, ne); |
1331 __ b(ne, &exit); | 1337 __ b(ne, &exit); |
1332 // slow case | 1338 // slow case |
1333 __ bind(&slow); | 1339 __ bind(&slow); |
1334 __ push(r1); | 1340 __ push(r1); |
1335 __ push(r0); | 1341 __ push(r0); |
1336 __ mov(r0, Operand(1)); // set number of arguments | 1342 __ mov(r0, Operand(1)); // set number of arguments |
1337 __ InvokeBuiltin("MUL", 1, JUMP_JS); | 1343 __ InvokeBuiltin(Builtins::MUL, JUMP_JS); |
1338 // done | 1344 // done |
1339 __ bind(&exit); | 1345 __ bind(&exit); |
1340 break; | 1346 break; |
1341 } | 1347 } |
1342 | 1348 |
1343 case Token::BIT_OR: | 1349 case Token::BIT_OR: |
1344 case Token::BIT_AND: | 1350 case Token::BIT_AND: |
1345 case Token::BIT_XOR: { | 1351 case Token::BIT_XOR: { |
1346 Label slow, exit; | 1352 Label slow, exit; |
1347 // tag check | 1353 // tag check |
1348 __ orr(r2, r1, Operand(r0)); // r2 = x | y; | 1354 __ orr(r2, r1, Operand(r0)); // r2 = x | y; |
1349 ASSERT(kSmiTag == 0); // adjust code below | 1355 ASSERT(kSmiTag == 0); // adjust code below |
1350 __ tst(r2, Operand(kSmiTagMask)); | 1356 __ tst(r2, Operand(kSmiTagMask)); |
1351 __ b(ne, &slow); | 1357 __ b(ne, &slow); |
1352 switch (op_) { | 1358 switch (op_) { |
1353 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; | 1359 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; |
1354 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; | 1360 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; |
1355 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; | 1361 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; |
1356 default: UNREACHABLE(); | 1362 default: UNREACHABLE(); |
1357 } | 1363 } |
1358 __ b(&exit); | 1364 __ b(&exit); |
1359 __ bind(&slow); | 1365 __ bind(&slow); |
1360 __ push(r1); // restore stack | 1366 __ push(r1); // restore stack |
1361 __ push(r0); | 1367 __ push(r0); |
1362 __ mov(r0, Operand(1)); // 1 argument (not counting receiver). | 1368 __ mov(r0, Operand(1)); // 1 argument (not counting receiver). |
1363 switch (op_) { | 1369 switch (op_) { |
1364 case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, JUMP_JS); break; | 1370 case Token::BIT_OR: |
1365 case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, JUMP_JS); break; | 1371 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS); |
1366 case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, JUMP_JS); break; | 1372 break; |
1367 default: UNREACHABLE(); | 1373 case Token::BIT_AND: |
| 1374 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS); |
| 1375 break; |
| 1376 case Token::BIT_XOR: |
| 1377 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS); |
| 1378 break; |
| 1379 default: |
| 1380 UNREACHABLE(); |
1368 } | 1381 } |
1369 __ bind(&exit); | 1382 __ bind(&exit); |
1370 break; | 1383 break; |
1371 } | 1384 } |
1372 | 1385 |
1373 case Token::SHL: | 1386 case Token::SHL: |
1374 case Token::SHR: | 1387 case Token::SHR: |
1375 case Token::SAR: { | 1388 case Token::SAR: { |
1376 Label slow, exit; | 1389 Label slow, exit; |
1377 // tag check | 1390 // tag check |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1415 // tag result and store it in r0 | 1428 // tag result and store it in r0 |
1416 ASSERT(kSmiTag == 0); // adjust code below | 1429 ASSERT(kSmiTag == 0); // adjust code below |
1417 __ mov(r0, Operand(r3, LSL, kSmiTagSize)); | 1430 __ mov(r0, Operand(r3, LSL, kSmiTagSize)); |
1418 __ b(&exit); | 1431 __ b(&exit); |
1419 // slow case | 1432 // slow case |
1420 __ bind(&slow); | 1433 __ bind(&slow); |
1421 __ push(r1); // restore stack | 1434 __ push(r1); // restore stack |
1422 __ push(r0); | 1435 __ push(r0); |
1423 __ mov(r0, Operand(1)); // 1 argument (not counting receiver). | 1436 __ mov(r0, Operand(1)); // 1 argument (not counting receiver). |
1424 switch (op_) { | 1437 switch (op_) { |
1425 case Token::SAR: __ InvokeBuiltin("SAR", 1, JUMP_JS); break; | 1438 case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break; |
1426 case Token::SHR: __ InvokeBuiltin("SHR", 1, JUMP_JS); break; | 1439 case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break; |
1427 case Token::SHL: __ InvokeBuiltin("SHL", 1, JUMP_JS); break; | 1440 case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break; |
1428 default: UNREACHABLE(); | 1441 default: UNREACHABLE(); |
1429 } | 1442 } |
1430 __ bind(&exit); | 1443 __ bind(&exit); |
1431 break; | 1444 break; |
1432 } | 1445 } |
1433 | 1446 |
1434 default: UNREACHABLE(); | 1447 default: UNREACHABLE(); |
1435 } | 1448 } |
1436 __ Ret(); | 1449 __ Ret(); |
1437 } | 1450 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1473 | 1486 |
1474 // If result is a smi we are done. | 1487 // If result is a smi we are done. |
1475 __ tst(r1, Operand(kSmiTagMask)); | 1488 __ tst(r1, Operand(kSmiTagMask)); |
1476 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result | 1489 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result |
1477 __ b(eq, &done); | 1490 __ b(eq, &done); |
1478 | 1491 |
1479 // Enter runtime system. | 1492 // Enter runtime system. |
1480 __ bind(&slow); | 1493 __ bind(&slow); |
1481 __ push(r0); | 1494 __ push(r0); |
1482 __ mov(r0, Operand(0)); // set number of arguments | 1495 __ mov(r0, Operand(0)); // set number of arguments |
1483 __ InvokeBuiltin("UNARY_MINUS", 0, JUMP_JS); | 1496 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); |
1484 | 1497 |
1485 __ bind(&done); | 1498 __ bind(&done); |
1486 masm->StubReturn(1); | 1499 masm->StubReturn(1); |
1487 } | 1500 } |
1488 | 1501 |
1489 | 1502 |
1490 class InvokeBuiltinStub : public CodeStub { | 1503 class InvokeBuiltinStub : public CodeStub { |
1491 public: | 1504 public: |
1492 enum Kind { Inc, Dec, ToNumber }; | 1505 enum Kind { Inc, Dec, ToNumber }; |
1493 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { } | 1506 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { } |
(...skipping 15 matching lines...) Expand all Loading... |
1509 argc_); | 1522 argc_); |
1510 } | 1523 } |
1511 #endif | 1524 #endif |
1512 }; | 1525 }; |
1513 | 1526 |
1514 | 1527 |
1515 void InvokeBuiltinStub::Generate(MacroAssembler* masm) { | 1528 void InvokeBuiltinStub::Generate(MacroAssembler* masm) { |
1516 __ push(r0); | 1529 __ push(r0); |
1517 __ mov(r0, Operand(0)); // set number of arguments | 1530 __ mov(r0, Operand(0)); // set number of arguments |
1518 switch (kind_) { | 1531 switch (kind_) { |
1519 case ToNumber: __ InvokeBuiltin("TO_NUMBER", 0, JUMP_JS); break; | 1532 case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break; |
1520 case Inc: __ InvokeBuiltin("INC", 0, JUMP_JS); break; | 1533 case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break; |
1521 case Dec: __ InvokeBuiltin("DEC", 0, JUMP_JS); break; | 1534 case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break; |
1522 default: UNREACHABLE(); | 1535 default: UNREACHABLE(); |
1523 } | 1536 } |
1524 masm->StubReturn(argc_); | 1537 masm->StubReturn(argc_); |
1525 } | 1538 } |
1526 | 1539 |
1527 | 1540 |
1528 class JSExitStub : public CodeStub { | |
1529 public: | |
1530 enum Kind { Inc, Dec, ToNumber }; | |
1531 | |
1532 explicit JSExitStub(ExitJSFlag flag) : flag_(flag) { } | |
1533 | |
1534 private: | |
1535 ExitJSFlag flag_; | |
1536 | |
1537 Major MajorKey() { return JSExit; } | |
1538 int MinorKey() { return static_cast<int>(flag_); } | |
1539 void Generate(MacroAssembler* masm); | |
1540 | |
1541 const char* GetName() { return "JSExitStub"; } | |
1542 | |
1543 #ifdef DEBUG | |
1544 void Print() { | |
1545 PrintF("JSExitStub flag %d)\n", static_cast<int>(flag_)); | |
1546 } | |
1547 #endif | |
1548 }; | |
1549 | |
1550 | |
1551 void JSExitStub::Generate(MacroAssembler* masm) { | |
1552 __ ExitJSFrame(flag_); | |
1553 masm->StubReturn(1); | |
1554 } | |
1555 | |
1556 | |
1557 | |
1558 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 1541 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
1559 // r0 holds exception | 1542 // r0 holds exception |
1560 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code | 1543 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code |
1561 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 1544 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
1562 __ ldr(sp, MemOperand(r3)); | 1545 __ ldr(sp, MemOperand(r3)); |
1563 __ pop(r2); // pop next in chain | 1546 __ pop(r2); // pop next in chain |
1564 __ str(r2, MemOperand(r3)); | 1547 __ str(r2, MemOperand(r3)); |
1565 // restore parameter- and frame-pointer and pop state. | 1548 // restore parameter- and frame-pointer and pop state. |
1566 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit()); | 1549 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit()); |
1567 // Before returning we restore the context from the frame pointer if not NULL. | 1550 // Before returning we restore the context from the frame pointer if not NULL. |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1694 // Exit C frame and return | 1677 // Exit C frame and return |
1695 // r0:r1: result | 1678 // r0:r1: result |
1696 // sp: stack pointer | 1679 // sp: stack pointer |
1697 // fp: frame pointer | 1680 // fp: frame pointer |
1698 // pp: caller's parameter pointer pp (restored as C callee-saved) | 1681 // pp: caller's parameter pointer pp (restored as C callee-saved) |
1699 | 1682 |
1700 // Restore current context from top and clear it in debug mode. | 1683 // Restore current context from top and clear it in debug mode. |
1701 __ mov(r3, Operand(Top::context_address())); | 1684 __ mov(r3, Operand(Top::context_address())); |
1702 __ ldr(cp, MemOperand(r3)); | 1685 __ ldr(cp, MemOperand(r3)); |
1703 __ mov(sp, Operand(fp)); // respect ABI stack constraint | 1686 __ mov(sp, Operand(fp)); // respect ABI stack constraint |
1704 __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | pc.bit()); | 1687 __ ldm(ia, sp, fp.bit() | sp.bit() | pc.bit()); |
1705 | 1688 |
1706 // check if we should retry or throw exception | 1689 // check if we should retry or throw exception |
1707 Label retry; | 1690 Label retry; |
1708 __ bind(&failure_returned); | 1691 __ bind(&failure_returned); |
1709 ASSERT(Failure::RETRY_AFTER_GC == 0); | 1692 ASSERT(Failure::RETRY_AFTER_GC == 0); |
1710 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 1693 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
1711 __ b(eq, &retry); | 1694 __ b(eq, &retry); |
1712 | 1695 |
1713 Label continue_exception; | 1696 Label continue_exception; |
1714 // If the returned failure is EXCEPTION then promote Top::pending_exception(). | 1697 // If the returned failure is EXCEPTION then promote Top::pending_exception(). |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1748 // instead of a proper result. The builtin entry handles | 1731 // instead of a proper result. The builtin entry handles |
1749 // this by performing a garbage collection and retrying the | 1732 // this by performing a garbage collection and retrying the |
1750 // builtin once. | 1733 // builtin once. |
1751 | 1734 |
1752 // Enter C frame | 1735 // Enter C frame |
1753 // Compute parameter pointer before making changes and save it as ip register | 1736 // Compute parameter pointer before making changes and save it as ip register |
1754 // so that it is restored as sp register on exit, thereby popping the args. | 1737 // so that it is restored as sp register on exit, thereby popping the args. |
1755 // ip = sp + kPointerSize*args_len; | 1738 // ip = sp + kPointerSize*args_len; |
1756 __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); | 1739 __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); |
1757 | 1740 |
1758 // all JS callee-saved are saved and traversed by GC; push in reverse order: | 1741 // push in reverse order: |
1759 // JS callee-saved, caller_pp, caller_fp, sp_on_exit (ip==pp), caller_pc | 1742 // caller_fp, sp_on_exit, caller_pc |
1760 __ stm(db_w, sp, pp.bit() | fp.bit() | ip.bit() | lr.bit()); | 1743 __ stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); |
1761 __ mov(fp, Operand(sp)); // setup new frame pointer | 1744 __ mov(fp, Operand(sp)); // setup new frame pointer |
1762 | 1745 |
1763 // Store the current context in top. | 1746 // Store the current context in top. |
1764 __ mov(ip, Operand(Top::context_address())); | 1747 __ mov(ip, Operand(ExternalReference(Top::k_context_address))); |
1765 __ str(cp, MemOperand(ip)); | 1748 __ str(cp, MemOperand(ip)); |
1766 | 1749 |
1767 // remember top frame | 1750 // remember top frame |
1768 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); | 1751 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
1769 __ str(fp, MemOperand(ip)); | 1752 __ str(fp, MemOperand(ip)); |
1770 | 1753 |
1771 // Push debug marker. | 1754 // Push debug marker. |
1772 __ mov(ip, Operand(is_debug_break ? 1 : 0)); | 1755 __ mov(ip, Operand(is_debug_break ? 1 : 0)); |
1773 __ push(ip); | 1756 __ push(ip); |
1774 | 1757 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1831 // r1: function | 1814 // r1: function |
1832 // r2: receiver | 1815 // r2: receiver |
1833 // r3: argc | 1816 // r3: argc |
1834 // [sp+0]: argv | 1817 // [sp+0]: argv |
1835 | 1818 |
1836 Label invoke, exit; | 1819 Label invoke, exit; |
1837 | 1820 |
1838 // Called from C, so do not pop argc and args on exit (preserve sp) | 1821 // Called from C, so do not pop argc and args on exit (preserve sp) |
1839 // No need to save register-passed args | 1822 // No need to save register-passed args |
1840 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr | 1823 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr |
1841 __ mov(ip, Operand(sp)); | 1824 __ stm(db_w, sp, kCalleeSaved | lr.bit()); |
1842 __ stm(db_w, sp, kCalleeSaved | ip.bit() | lr.bit()); | |
1843 | |
1844 // Setup frame pointer | |
1845 __ mov(fp, Operand(sp)); | |
1846 | |
1847 // Add constructor mark. | |
1848 __ mov(ip, Operand(is_construct ? 1 : 0)); | |
1849 __ push(ip); | |
1850 | |
1851 // Move arguments into registers expected by Builtins::JSEntryTrampoline | |
1852 // preserve r0-r3, set r4, r5-r7 may be clobbered | |
1853 | 1825 |
1854 // Get address of argv, see stm above. | 1826 // Get address of argv, see stm above. |
1855 __ add(r4, sp, Operand((kNumCalleeSaved + 3)*kPointerSize)); | 1827 // r0: code entry |
| 1828 // r1: function |
| 1829 // r2: receiver |
| 1830 // r3: argc |
| 1831 __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize)); |
1856 __ ldr(r4, MemOperand(r4)); // argv | 1832 __ ldr(r4, MemOperand(r4)); // argv |
1857 | 1833 |
1858 // Save copies of the top frame descriptors on the stack. | 1834 // Push a frame with special values setup to mark it as an entry frame. |
1859 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); | 1835 // r0: code entry |
1860 __ ldr(r6, MemOperand(ip)); | 1836 // r1: function |
1861 __ stm(db_w, sp, r6.bit()); | 1837 // r2: receiver |
| 1838 // r3: argc |
| 1839 // r4: argv |
| 1840 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| 1841 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. |
| 1842 __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL)); |
| 1843 __ mov(r6, Operand(Smi::FromInt(marker))); |
| 1844 __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
| 1845 __ ldr(r5, MemOperand(r5)); |
| 1846 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit()); |
| 1847 |
| 1848 // Setup frame pointer for the frame to be pushed. |
| 1849 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); |
1862 | 1850 |
1863 // Call a faked try-block that does the invoke. | 1851 // Call a faked try-block that does the invoke. |
1864 __ bl(&invoke); | 1852 __ bl(&invoke); |
1865 | 1853 |
1866 // Caught exception: Store result (exception) in the pending | 1854 // Caught exception: Store result (exception) in the pending |
1867 // exception field in the JSEnv and return a failure sentinel. | 1855 // exception field in the JSEnv and return a failure sentinel. |
| 1856 // Coming in here the fp will be invalid because the PushTryHandler below |
| 1857 // sets it to 0 to signal the existence of the JSEntry frame. |
1868 __ mov(ip, Operand(Top::pending_exception_address())); | 1858 __ mov(ip, Operand(Top::pending_exception_address())); |
1869 __ str(r0, MemOperand(ip)); | 1859 __ str(r0, MemOperand(ip)); |
1870 __ mov(r0, Operand(Handle<Failure>(Failure::Exception()))); | 1860 __ mov(r0, Operand(Handle<Failure>(Failure::Exception()))); |
1871 __ b(&exit); | 1861 __ b(&exit); |
1872 | 1862 |
1873 // Invoke: Link this frame into the handler chain. | 1863 // Invoke: Link this frame into the handler chain. |
1874 __ bind(&invoke); | 1864 __ bind(&invoke); |
1875 // Must preserve r0-r3, r5-r7 are available. | 1865 // Must preserve r0-r4, r5-r7 are available. |
1876 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); | 1866 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
1877 // If an exception not caught by another handler occurs, this handler returns | 1867 // If an exception not caught by another handler occurs, this handler returns |
1878 // control to the code after the bl(&invoke) above, which restores all | 1868 // control to the code after the bl(&invoke) above, which restores all |
1879 // kCalleeSaved registers (including cp, pp and fp) to their saved values | 1869 // kCalleeSaved registers (including cp, pp and fp) to their saved values |
1880 // before returning a failure to C. | 1870 // before returning a failure to C. |
1881 | 1871 |
1882 // Clear any pending exceptions. | 1872 // Clear any pending exceptions. |
1883 __ mov(ip, Operand(ExternalReference::the_hole_value_location())); | 1873 __ mov(ip, Operand(ExternalReference::the_hole_value_location())); |
1884 __ ldr(r5, MemOperand(ip)); | 1874 __ ldr(r5, MemOperand(ip)); |
1885 __ mov(ip, Operand(Top::pending_exception_address())); | 1875 __ mov(ip, Operand(Top::pending_exception_address())); |
(...skipping 27 matching lines...) Expand all Loading... |
1913 // displacement since the current stack pointer (sp) points directly | 1903 // displacement since the current stack pointer (sp) points directly |
1914 // to the stack handler. | 1904 // to the stack handler. |
1915 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset)); | 1905 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset)); |
1916 __ mov(ip, Operand(ExternalReference(Top::k_handler_address))); | 1906 __ mov(ip, Operand(ExternalReference(Top::k_handler_address))); |
1917 __ str(r3, MemOperand(ip)); | 1907 __ str(r3, MemOperand(ip)); |
1918 // No need to restore registers | 1908 // No need to restore registers |
1919 __ add(sp, sp, Operand(StackHandlerConstants::kSize)); | 1909 __ add(sp, sp, Operand(StackHandlerConstants::kSize)); |
1920 | 1910 |
1921 __ bind(&exit); // r0 holds result | 1911 __ bind(&exit); // r0 holds result |
1922 // Restore the top frame descriptors from the stack. | 1912 // Restore the top frame descriptors from the stack. |
1923 __ ldm(ia_w, sp, r3.bit()); | 1913 __ pop(r3); |
1924 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); | 1914 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
1925 __ str(r3, MemOperand(ip)); | 1915 __ str(r3, MemOperand(ip)); |
1926 | 1916 |
1927 // Remove constructor mark. | 1917 // Reset the stack to the callee saved registers. |
1928 __ pop(); | 1918 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); |
1929 | 1919 |
1930 // Restore callee-saved registers, sp, and return. | 1920 // Restore callee-saved registers and return. |
1931 #ifdef DEBUG | 1921 #ifdef DEBUG |
1932 if (FLAG_debug_code) __ mov(lr, Operand(pc)); | 1922 if (FLAG_debug_code) __ mov(lr, Operand(pc)); |
1933 #endif | 1923 #endif |
1934 __ ldm(ia, sp, kCalleeSaved | sp.bit() | pc.bit()); | 1924 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); |
1935 } | 1925 } |
1936 | 1926 |
1937 | 1927 |
1938 class ArgumentsAccessStub: public CodeStub { | 1928 class ArgumentsAccessStub: public CodeStub { |
1939 public: | 1929 public: |
1940 explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { } | 1930 explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { } |
1941 | 1931 |
1942 private: | 1932 private: |
1943 bool is_length_; | 1933 bool is_length_; |
1944 | 1934 |
1945 Major MajorKey() { return ArgumentsAccess; } | 1935 Major MajorKey() { return ArgumentsAccess; } |
1946 int MinorKey() { return is_length_ ? 1 : 0; } | 1936 int MinorKey() { return is_length_ ? 1 : 0; } |
1947 void Generate(MacroAssembler* masm); | 1937 void Generate(MacroAssembler* masm); |
1948 | 1938 |
1949 const char* GetName() { return "ArgumentsAccessStub"; } | 1939 const char* GetName() { return "ArgumentsAccessStub"; } |
1950 | 1940 |
1951 #ifdef DEBUG | 1941 #ifdef DEBUG |
1952 void Print() { | 1942 void Print() { |
1953 PrintF("ArgumentsAccessStub (is_length %s)\n", | 1943 PrintF("ArgumentsAccessStub (is_length %s)\n", |
1954 is_length_ ? "true" : "false"); | 1944 is_length_ ? "true" : "false"); |
1955 } | 1945 } |
1956 #endif | 1946 #endif |
1957 }; | 1947 }; |
1958 | 1948 |
1959 | 1949 |
1960 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { | 1950 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { |
| 1951 // ----------- S t a t e ------------- |
| 1952 // -- r0: formal number of parameters for the calling function |
| 1953 // -- r1: key (if value access) |
| 1954 // -- lr: return address |
| 1955 // ----------------------------------- |
| 1956 |
| 1957 // Check that the key is a smi for non-length accesses. |
| 1958 Label slow; |
| 1959 if (!is_length_) { |
| 1960 __ tst(r1, Operand(kSmiTagMask)); |
| 1961 __ b(ne, &slow); |
| 1962 } |
| 1963 |
| 1964 // Check if the calling frame is an arguments adaptor frame. |
| 1965 // r0: formal number of parameters |
| 1966 // r1: key (if access) |
| 1967 Label adaptor; |
| 1968 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 1969 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
| 1970 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL)); |
| 1971 __ b(eq, &adaptor); |
| 1972 |
| 1973 static const int kParamDisplacement = |
| 1974 StandardFrameConstants::kCallerSPOffset - kPointerSize; |
| 1975 |
1961 if (is_length_) { | 1976 if (is_length_) { |
1962 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); | 1977 // Nothing to do: the formal length of parameters has been passed in r0 |
1963 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | 1978 // by the calling function. |
1964 __ Ret(); | |
1965 } else { | 1979 } else { |
1966 // Check that the key is a smi. | 1980 // Check index against formal parameter count. Use unsigned comparison to |
1967 Label slow; | 1981 // get the negative check for free. |
1968 __ tst(r0, Operand(kSmiTagMask)); | 1982 // r0: formal number of parameters |
1969 __ b(ne, &slow); | 1983 // r1: index |
| 1984 __ cmp(r1, r0); |
| 1985 __ b(cs, &slow); |
1970 | 1986 |
1971 // Get the actual number of arguments passed and do bounds | 1987 // Read the argument from the current frame. |
1972 // check. Use unsigned comparison to get negative check for free. | 1988 __ sub(r3, r0, r1); |
1973 __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); | 1989 __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); |
1974 __ cmp(r0, Operand(r1, LSL, kSmiTagSize)); | 1990 __ ldr(r0, MemOperand(r3, kParamDisplacement)); |
1975 __ b(hs, &slow); | 1991 } |
1976 | 1992 |
1977 // Load the argument directly from the stack and return. | 1993 // Return to the calling function. |
1978 __ sub(r1, pp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1994 __ mov(pc, lr); |
1979 __ ldr(r0, MemOperand(r1, JavaScriptFrameConstants::kParam0Offset)); | |
1980 __ Ret(); | |
1981 | 1995 |
1982 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 1996 // An arguments adaptor frame is present. Find the length or the actual |
1983 // by calling the runtime system. | 1997 // argument in the calling frame. |
| 1998 // r0: formal number of parameters |
| 1999 // r1: key |
| 2000 // r2: adaptor frame pointer |
| 2001 __ bind(&adaptor); |
| 2002 // Read the arguments length from the adaptor frame. This is the result if |
| 2003 // only accessing the length, otherwise it is used in accessing the value |
| 2004 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2005 |
| 2006 if (!is_length_) { |
| 2007 // Check index against actual arguments count. Use unsigned comparison to |
| 2008 // get the negative check for free. |
| 2009 // r0: actual number of parameter |
| 2010 // r1: index |
| 2011 // r2: adaptor frame point |
| 2012 __ cmp(r1, r0); |
| 2013 __ b(cs, &slow); |
| 2014 |
| 2015 // Read the argument from the adaptor frame. |
| 2016 __ sub(r3, r0, r1); |
| 2017 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 2018 __ ldr(r0, MemOperand(r3, kParamDisplacement)); |
| 2019 } |
| 2020 |
| 2021 // Return to the calling function. |
| 2022 __ mov(pc, lr); |
| 2023 |
| 2024 if (!is_length_) { |
1984 __ bind(&slow); | 2025 __ bind(&slow); |
1985 __ push(r0); | 2026 __ push(r1); |
1986 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); | 2027 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); |
1987 } | 2028 } |
1988 } | 2029 } |
1989 | 2030 |
1990 | 2031 |
1991 #undef __ | 2032 #undef __ |
1992 #define __ masm_-> | 2033 #define __ masm_-> |
1993 | 2034 |
1994 | 2035 |
1995 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { | 2036 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2078 case Token::SAR: { | 2119 case Token::SAR: { |
2079 __ pop(r0); // r0 : y | 2120 __ pop(r0); // r0 : y |
2080 __ pop(r1); // r1 : x | 2121 __ pop(r1); // r1 : x |
2081 GenericBinaryOpStub stub(op); | 2122 GenericBinaryOpStub stub(op); |
2082 __ CallStub(&stub); | 2123 __ CallStub(&stub); |
2083 break; | 2124 break; |
2084 } | 2125 } |
2085 | 2126 |
2086 case Token::DIV: { | 2127 case Token::DIV: { |
2087 __ mov(r0, Operand(1)); | 2128 __ mov(r0, Operand(1)); |
2088 __ InvokeBuiltin("DIV", 1, CALL_JS); | 2129 __ InvokeBuiltin(Builtins::DIV, CALL_JS); |
2089 break; | 2130 break; |
2090 } | 2131 } |
2091 | 2132 |
2092 case Token::MOD: { | 2133 case Token::MOD: { |
2093 __ mov(r0, Operand(1)); | 2134 __ mov(r0, Operand(1)); |
2094 __ InvokeBuiltin("MOD", 1, CALL_JS); | 2135 __ InvokeBuiltin(Builtins::MOD, CALL_JS); |
2095 break; | 2136 break; |
2096 } | 2137 } |
2097 | 2138 |
2098 case Token::COMMA: | 2139 case Token::COMMA: |
2099 __ pop(r0); | 2140 __ pop(r0); |
2100 // simply discard left value | 2141 // simply discard left value |
2101 __ pop(); | 2142 __ pop(); |
2102 break; | 2143 break; |
2103 | 2144 |
2104 default: | 2145 default: |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2339 __ pop(r1); | 2380 __ pop(r1); |
2340 } | 2381 } |
2341 __ orr(r2, r0, Operand(r1)); | 2382 __ orr(r2, r0, Operand(r1)); |
2342 __ tst(r2, Operand(kSmiTagMask)); | 2383 __ tst(r2, Operand(kSmiTagMask)); |
2343 __ b(eq, &smi); | 2384 __ b(eq, &smi); |
2344 | 2385 |
2345 // Perform non-smi comparison by runtime call. | 2386 // Perform non-smi comparison by runtime call. |
2346 __ push(r1); | 2387 __ push(r1); |
2347 | 2388 |
2348 // Figure out which native to call and setup the arguments. | 2389 // Figure out which native to call and setup the arguments. |
2349 const char* native; | 2390 Builtins::JavaScript native; |
2350 int argc; | 2391 int argc; |
2351 if (cc == eq) { | 2392 if (cc == eq) { |
2352 native = strict ? "STRICT_EQUALS" : "EQUALS"; | 2393 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
2353 argc = 1; | 2394 argc = 1; |
2354 } else { | 2395 } else { |
2355 native = "COMPARE"; | 2396 native = Builtins::COMPARE; |
2356 int ncr; // NaN compare result | 2397 int ncr; // NaN compare result |
2357 if (cc == lt || cc == le) { | 2398 if (cc == lt || cc == le) { |
2358 ncr = GREATER; | 2399 ncr = GREATER; |
2359 } else { | 2400 } else { |
2360 ASSERT(cc == gt || cc == ge); // remaining cases | 2401 ASSERT(cc == gt || cc == ge); // remaining cases |
2361 ncr = LESS; | 2402 ncr = LESS; |
2362 } | 2403 } |
2363 __ push(r0); | 2404 __ push(r0); |
2364 __ mov(r0, Operand(Smi::FromInt(ncr))); | 2405 __ mov(r0, Operand(Smi::FromInt(ncr))); |
2365 argc = 2; | 2406 argc = 2; |
2366 } | 2407 } |
2367 | 2408 |
2368 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 2409 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
2369 // tagged as a small integer. | 2410 // tagged as a small integer. |
2370 __ push(r0); | 2411 __ push(r0); |
2371 __ mov(r0, Operand(argc)); | 2412 __ mov(r0, Operand(argc)); |
2372 __ InvokeBuiltin(native, argc, CALL_JS); | 2413 __ InvokeBuiltin(native, CALL_JS); |
2373 __ cmp(r0, Operand(0)); | 2414 __ cmp(r0, Operand(0)); |
2374 __ b(&exit); | 2415 __ b(&exit); |
2375 | 2416 |
2376 // test smi equality by pointer comparison. | 2417 // test smi equality by pointer comparison. |
2377 __ bind(&smi); | 2418 __ bind(&smi); |
2378 __ cmp(r1, Operand(r0)); | 2419 __ cmp(r1, Operand(r0)); |
2379 | 2420 |
2380 __ bind(&exit); | 2421 __ bind(&exit); |
2381 cc_reg_ = cc; | 2422 cc_reg_ = cc; |
2382 } | 2423 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2419 masm->b(ne, &slow); | 2460 masm->b(ne, &slow); |
2420 | 2461 |
2421 // Fast-case: Invoke the function now. | 2462 // Fast-case: Invoke the function now. |
2422 // r1: pushed function | 2463 // r1: pushed function |
2423 ParameterCount actual(argc_); | 2464 ParameterCount actual(argc_); |
2424 masm->InvokeFunction(r1, actual, JUMP_FUNCTION); | 2465 masm->InvokeFunction(r1, actual, JUMP_FUNCTION); |
2425 | 2466 |
2426 // Slow-case: Non-function called. | 2467 // Slow-case: Non-function called. |
2427 masm->bind(&slow); | 2468 masm->bind(&slow); |
2428 masm->mov(r0, Operand(argc_)); // Setup the number of arguments. | 2469 masm->mov(r0, Operand(argc_)); // Setup the number of arguments. |
2429 masm->InvokeBuiltin("CALL_NON_FUNCTION", argc_, JUMP_JS); | 2470 masm->InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); |
2430 } | 2471 } |
2431 | 2472 |
2432 | 2473 |
2433 // Call the function on the stack with the given arguments. | 2474 // Call the function on the stack with the given arguments. |
2434 void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 2475 void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
2435 int position) { | 2476 int position) { |
2436 // Push the arguments ("left-to-right") on the stack. | 2477 // Push the arguments ("left-to-right") on the stack. |
2437 for (int i = 0; i < args->length(); i++) { | 2478 for (int i = 0; i < args->length(); i++) { |
2438 Load(args->at(i)); | 2479 Load(args->at(i)); |
2439 } | 2480 } |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2859 __ tst(r0, Operand(kSmiTagMask)); | 2900 __ tst(r0, Operand(kSmiTagMask)); |
2860 __ b(eq, &primitive); | 2901 __ b(eq, &primitive); |
2861 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2902 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
2862 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 2903 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
2863 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 2904 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
2864 __ b(hs, &jsobject); | 2905 __ b(hs, &jsobject); |
2865 | 2906 |
2866 __ bind(&primitive); | 2907 __ bind(&primitive); |
2867 __ push(r0); | 2908 __ push(r0); |
2868 __ mov(r0, Operand(0)); | 2909 __ mov(r0, Operand(0)); |
2869 __ InvokeBuiltin("TO_OBJECT", 0, CALL_JS); | 2910 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
2870 | 2911 |
2871 | 2912 |
2872 __ bind(&jsobject); | 2913 __ bind(&jsobject); |
2873 | 2914 |
2874 // Get the set of properties (as a FixedArray or Map). | 2915 // Get the set of properties (as a FixedArray or Map). |
2875 __ push(r0); // duplicate the object being enumerated | 2916 __ push(r0); // duplicate the object being enumerated |
2876 __ push(r0); | 2917 __ push(r0); |
2877 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 2918 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
2878 | 2919 |
2879 // If we got a Map, we can do a fast modification check. | 2920 // If we got a Map, we can do a fast modification check. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2953 __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); | 2994 __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); |
2954 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 2995 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
2955 __ cmp(r1, Operand(r2)); | 2996 __ cmp(r1, Operand(r2)); |
2956 __ b(eq, &end_del_check); | 2997 __ b(eq, &end_del_check); |
2957 | 2998 |
2958 // Convert the entry to a string (or null if it isn't a property anymore). | 2999 // Convert the entry to a string (or null if it isn't a property anymore). |
2959 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable | 3000 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable |
2960 __ push(r0); | 3001 __ push(r0); |
2961 __ push(r3); // push entry | 3002 __ push(r3); // push entry |
2962 __ mov(r0, Operand(1)); | 3003 __ mov(r0, Operand(1)); |
2963 __ InvokeBuiltin("FILTER_KEY", 1, CALL_JS); | 3004 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); |
2964 __ mov(r3, Operand(r0)); | 3005 __ mov(r3, Operand(r0)); |
2965 | 3006 |
2966 // If the property has been removed while iterating, we just skip it. | 3007 // If the property has been removed while iterating, we just skip it. |
2967 __ cmp(r3, Operand(Factory::null_value())); | 3008 __ cmp(r3, Operand(Factory::null_value())); |
2968 __ b(eq, &next); | 3009 __ b(eq, &next); |
2969 | 3010 |
2970 | 3011 |
2971 __ bind(&end_del_check); | 3012 __ bind(&end_del_check); |
2972 | 3013 |
2973 // Store the entry in the 'each' expression and take another spin in the loop. | 3014 // Store the entry in the 'each' expression and take another spin in the loop. |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3351 __ push(r0); | 3392 __ push(r0); |
3352 } | 3393 } |
3353 | 3394 |
3354 | 3395 |
3355 void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 3396 void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
3356 Comment cmnt(masm_, "[ RexExp Literal"); | 3397 Comment cmnt(masm_, "[ RexExp Literal"); |
3357 | 3398 |
3358 // Retrieve the literal array and check the allocated entry. | 3399 // Retrieve the literal array and check the allocated entry. |
3359 | 3400 |
3360 // Load the function of this activation. | 3401 // Load the function of this activation. |
3361 __ ldr(r1, MemOperand(pp, 0)); | 3402 __ ldr(r1, FunctionOperand()); |
3362 | 3403 |
3363 // Load the literals array of the function. | 3404 // Load the literals array of the function. |
3364 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 3405 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
3365 | 3406 |
3366 // Load the literal at the ast saved index. | 3407 // Load the literal at the ast saved index. |
3367 int literal_offset = | 3408 int literal_offset = |
3368 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 3409 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
3369 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 3410 __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
3370 | 3411 |
3371 Label done; | 3412 Label done; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3424 | 3465 |
3425 | 3466 |
3426 void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 3467 void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
3427 Comment cmnt(masm_, "[ ObjectLiteral"); | 3468 Comment cmnt(masm_, "[ ObjectLiteral"); |
3428 | 3469 |
3429 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 3470 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
3430 | 3471 |
3431 // Retrieve the literal array and check the allocated entry. | 3472 // Retrieve the literal array and check the allocated entry. |
3432 | 3473 |
3433 // Load the function of this activation. | 3474 // Load the function of this activation. |
3434 __ ldr(r1, MemOperand(pp, 0)); | 3475 __ ldr(r1, FunctionOperand()); |
3435 | 3476 |
3436 // Load the literals array of the function. | 3477 // Load the literals array of the function. |
3437 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 3478 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
3438 | 3479 |
3439 // Load the literal at the ast saved index. | 3480 // Load the literal at the ast saved index. |
3440 int literal_offset = | 3481 int literal_offset = |
3441 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 3482 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
3442 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 3483 __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
3443 | 3484 |
3444 // Check whether we need to materialize the object literal boilerplate. | 3485 // Check whether we need to materialize the object literal boilerplate. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3495 } | 3536 } |
3496 } | 3537 } |
3497 | 3538 |
3498 | 3539 |
3499 void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 3540 void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
3500 Comment cmnt(masm_, "[ ArrayLiteral"); | 3541 Comment cmnt(masm_, "[ ArrayLiteral"); |
3501 | 3542 |
3502 // Call runtime to create the array literal. | 3543 // Call runtime to create the array literal. |
3503 __ mov(r0, Operand(node->literals())); | 3544 __ mov(r0, Operand(node->literals())); |
3504 __ push(r0); | 3545 __ push(r0); |
3505 // TODO(1332579): The second argument to CreateArrayLiteral is | 3546 // Load the function of this frame. |
3506 // supposed to be the literals array of the function of this frame. | 3547 __ ldr(r0, FunctionOperand()); |
3507 // Until the new ARM calling convention is in place, that function | 3548 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
3508 // is not always available. Therefore, on ARM we pass in the hole | |
3509 // until the new calling convention is in place. | |
3510 __ mov(r0, Operand(Factory::the_hole_value())); | |
3511 __ push(r0); | 3549 __ push(r0); |
3512 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 3550 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
3513 | 3551 |
3514 // Push the resulting array literal on the stack. | 3552 // Push the resulting array literal on the stack. |
3515 __ push(r0); | 3553 __ push(r0); |
3516 | 3554 |
3517 // Generate code to set the elements in the array that are not | 3555 // Generate code to set the elements in the array that are not |
3518 // literals. | 3556 // literals. |
3519 for (int i = 0; i < node->values()->length(); i++) { | 3557 for (int i = 0; i < node->values()->length(); i++) { |
3520 Expression* value = node->values()->at(i); | 3558 Expression* value = node->values()->at(i); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3753 Load(node->expression()); | 3791 Load(node->expression()); |
3754 LoadGlobal(); | 3792 LoadGlobal(); |
3755 | 3793 |
3756 // Push the arguments ("left-to-right") on the stack. | 3794 // Push the arguments ("left-to-right") on the stack. |
3757 ZoneList<Expression*>* args = node->arguments(); | 3795 ZoneList<Expression*>* args = node->arguments(); |
3758 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 3796 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
3759 | 3797 |
3760 // r0: the number of arguments. | 3798 // r0: the number of arguments. |
3761 __ mov(r0, Operand(args->length())); | 3799 __ mov(r0, Operand(args->length())); |
3762 | 3800 |
| 3801 // Load the function into r1 as per calling convention. |
| 3802 __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize)); |
| 3803 |
3763 // Call the construct call builtin that handles allocation and | 3804 // Call the construct call builtin that handles allocation and |
3764 // constructor invocation. | 3805 // constructor invocation. |
3765 __ RecordPosition(position); | 3806 __ RecordPosition(position); |
3766 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 3807 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
3767 js_construct_call); | 3808 js_construct_call); |
3768 | 3809 |
3769 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 3810 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
3770 __ str(r0, MemOperand(sp, 0 * kPointerSize)); | 3811 __ str(r0, MemOperand(sp, 0 * kPointerSize)); |
3771 } | 3812 } |
3772 | 3813 |
3773 | 3814 |
3774 void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) { | 3815 void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) { |
3775 ASSERT(args->length() == 1); | 3816 __ stop("ArmCodeGenerator::GenerateSetThisFunction - unreachable"); |
3776 Load(args->at(0)); | |
3777 __ ldr(r0, MemOperand(sp, 0)); | |
3778 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | |
3779 } | 3817 } |
3780 | 3818 |
3781 | 3819 |
3782 void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) { | 3820 void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) { |
3783 ASSERT(args->length() == 0); | 3821 __ stop("ArmCodeGenerator::GenerateGetThisFunction - unreachable"); |
3784 __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | |
3785 __ push(r0); | |
3786 } | 3822 } |
3787 | 3823 |
3788 | 3824 |
3789 void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) { | 3825 void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) { |
3790 ASSERT(args->length() == 1); | 3826 __ stop("ArmCodeGenerator::GenerateSetThis - unreachable"); |
3791 Load(args->at(0)); | |
3792 __ ldr(r0, MemOperand(sp, 0)); | |
3793 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kReceiverOffset)); | |
3794 } | 3827 } |
3795 | 3828 |
3796 | 3829 |
3797 void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) { | 3830 void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) { |
3798 ASSERT(args->length() == 1); | 3831 __ stop("ArmCodeGenerator::GenerateSetArgumentsLength - unreachable"); |
3799 Load(args->at(0)); | |
3800 __ pop(r0); | |
3801 __ mov(r0, Operand(r0, LSR, kSmiTagSize)); | |
3802 __ str(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); | |
3803 __ mov(r0, Operand(Smi::FromInt(0))); // return a meaningful value | |
3804 __ push(r0); | |
3805 } | 3832 } |
3806 | 3833 |
3807 | 3834 |
3808 void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) { | 3835 void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) { |
3809 ASSERT(args->length() == 1); | 3836 __ stop("ArmCodeGenerator::GenerateGetArgumentsLength - unreachable"); |
3810 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); | |
3811 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
3812 __ push(r0); | |
3813 } | 3837 } |
3814 | 3838 |
3815 | 3839 |
3816 void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3840 void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
3817 ASSERT(args->length() == 1); | 3841 ASSERT(args->length() == 1); |
3818 Label leave; | 3842 Label leave; |
3819 Load(args->at(0)); | 3843 Load(args->at(0)); |
3820 __ pop(r0); // r0 contains object. | 3844 __ pop(r0); // r0 contains object. |
3821 // if (object->IsSmi()) return the object. | 3845 // if (object->IsSmi()) return the object. |
3822 __ tst(r0, Operand(kSmiTagMask)); | 3846 __ tst(r0, Operand(kSmiTagMask)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3856 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); | 3880 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); |
3857 __ RecordWrite(r1, r2, r3); | 3881 __ RecordWrite(r1, r2, r3); |
3858 // Leave. | 3882 // Leave. |
3859 __ bind(&leave); | 3883 __ bind(&leave); |
3860 __ push(r0); | 3884 __ push(r0); |
3861 } | 3885 } |
3862 | 3886 |
3863 | 3887 |
3864 void ArmCodeGenerator::GenerateTailCallWithArguments( | 3888 void ArmCodeGenerator::GenerateTailCallWithArguments( |
3865 ZoneList<Expression*>* args) { | 3889 ZoneList<Expression*>* args) { |
3866 // r0 = number of arguments (smi) | 3890 __ stop("ArmCodeGenerator::GenerateTailCallWithArguments - unreachable"); |
3867 ASSERT(args->length() == 1); | |
3868 Load(args->at(0)); | |
3869 __ pop(r0); | |
3870 __ mov(r0, Operand(r0, LSR, kSmiTagSize)); | |
3871 | |
3872 // r1 = new function (previously written to stack) | |
3873 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | |
3874 | |
3875 // Reset parameter pointer and frame pointer to previous frame | |
3876 ExitJSFrame(DO_NOT_RETURN); | |
3877 | |
3878 // Jump (tail-call) to the function in register r1. | |
3879 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
3880 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
3881 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset)); | |
3882 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); | |
3883 } | 3891 } |
3884 | 3892 |
3885 | 3893 |
3886 void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) { | 3894 void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) { |
3887 ASSERT(args->length() == 3); | 3895 __ stop("ArmCodeGenerator::GenerateSetArgument - unreachable"); |
3888 // r0 = args[i]; r1 = i | |
3889 Comment cmnt(masm_, "[ GenerateSetArgument"); | |
3890 Load(args->at(1)); // args[i] (value) | |
3891 Load(args->at(0)); // i | |
3892 __ pop(r1); // i | |
3893 __ pop(r0); // value | |
3894 #if defined(DEBUG) | |
3895 { Label L; | |
3896 __ tst(r1, Operand(kSmiTagMask)); | |
3897 __ b(eq, &L); | |
3898 __ stop("SMI expected"); | |
3899 __ bind(&L); | |
3900 } | |
3901 #endif // defined(DEBUG) | |
3902 __ add(r2, pp, Operand(JavaScriptFrameConstants::kParam0Offset)); | |
3903 __ str(r0, | |
3904 MemOperand(r2, r1, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset)); | |
3905 __ push(r0); | |
3906 } | 3896 } |
3907 | 3897 |
3908 | 3898 |
3909 void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) { | 3899 void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) { |
3910 ASSERT(args->length() == 2); | 3900 __ stop("ArmCodeGenerator::GenerateSquashFrame - unreachable"); |
3911 Load(args->at(0)); // old number of arguments | |
3912 Load(args->at(1)); // new number of arguments, r1 > r0 | |
3913 __ pop(r0); | |
3914 __ mov(r0, Operand(r0, LSR, kSmiTagSize)); | |
3915 __ pop(r1); | |
3916 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); | |
3917 // r1 = number of words to move stack. | |
3918 __ sub(r1, r1, Operand(r0)); | |
3919 // r2 is source. | |
3920 __ add(r2, fp, Operand(StandardFrameConstants::kCallerPCOffset)); | |
3921 // Move down frame pointer fp. | |
3922 __ add(fp, fp, Operand(r1, LSL, kPointerSizeLog2)); | |
3923 // r1 is destination. | |
3924 __ add(r1, fp, Operand(StandardFrameConstants::kCallerPCOffset)); | |
3925 | |
3926 Label move; | |
3927 __ bind(&move); | |
3928 __ ldr(r3, MemOperand(r2, -kPointerSize, PostIndex)); | |
3929 __ str(r3, MemOperand(r1, -kPointerSize, PostIndex)); | |
3930 __ cmp(r2, Operand(sp)); | |
3931 __ b(ne, &move); | |
3932 __ ldr(r3, MemOperand(r2)); | |
3933 __ str(r3, MemOperand(r1)); | |
3934 | |
3935 // Move down stack pointer esp. | |
3936 __ mov(sp, Operand(r1)); | |
3937 // Put something GC-able in r0. | |
3938 __ mov(r0, Operand(Smi::FromInt(0))); | |
3939 __ push(r0); | |
3940 } | 3901 } |
3941 | 3902 |
3942 | 3903 |
3943 void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) { | 3904 void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) { |
3944 ASSERT(args->length() == 2); | 3905 __ stop("ArmCodeGenerator::GenerateExpandFrame - unreachable"); |
3945 Load(args->at(1)); | |
3946 Load(args->at(0)); | |
3947 __ pop(r0); // new number of arguments | |
3948 __ pop(r1); // old number of arguments, r1 > r0 | |
3949 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); | |
3950 | |
3951 // r1 = number of words to move stack. | |
3952 __ sub(r1, r1, Operand(r0, LSR, kSmiTagSize)); | |
3953 Label end_of_expand_frame; | |
3954 if (FLAG_check_stack) { | |
3955 Label not_too_big; | |
3956 __ sub(r2, sp, Operand(r1, LSL, kPointerSizeLog2)); | |
3957 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit())); | |
3958 __ ldr(ip, MemOperand(ip)); | |
3959 __ cmp(r2, Operand(ip)); | |
3960 __ b(gt, ¬_too_big); | |
3961 __ mov(r0, Operand(Factory::false_value())); | |
3962 __ b(&end_of_expand_frame); | |
3963 __ bind(¬_too_big); | |
3964 } | |
3965 // r3 is source. | |
3966 __ mov(r3, Operand(sp)); | |
3967 // r0 is copy limit + 1 word | |
3968 __ add(r0, fp, | |
3969 Operand(StandardFrameConstants::kCallerPCOffset + kPointerSize)); | |
3970 // Move up frame pointer fp. | |
3971 __ sub(fp, fp, Operand(r1, LSL, kPointerSizeLog2)); | |
3972 // Move up stack pointer sp. | |
3973 __ sub(sp, sp, Operand(r1, LSL, kPointerSizeLog2)); | |
3974 // r1 is destination (r1 = source - r1). | |
3975 __ mov(r2, Operand(0)); | |
3976 __ sub(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); | |
3977 __ add(r1, r3, Operand(r2)); | |
3978 | |
3979 Label move; | |
3980 __ bind(&move); | |
3981 __ ldr(r2, MemOperand(r3, kPointerSize, PostIndex)); | |
3982 __ str(r2, MemOperand(r1, kPointerSize, PostIndex)); | |
3983 __ cmp(r3, Operand(r0)); | |
3984 __ b(ne, &move); | |
3985 | |
3986 // Put success value in top of stack | |
3987 __ mov(r0, Operand(Factory::true_value())); | |
3988 __ bind(&end_of_expand_frame); | |
3989 __ push(r0); | |
3990 } | 3906 } |
3991 | 3907 |
3992 | 3908 |
3993 void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3909 void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
3994 ASSERT(args->length() == 1); | 3910 ASSERT(args->length() == 1); |
3995 Load(args->at(0)); | 3911 Load(args->at(0)); |
3996 __ pop(r0); | 3912 __ pop(r0); |
3997 __ tst(r0, Operand(kSmiTagMask)); | 3913 __ tst(r0, Operand(kSmiTagMask)); |
3998 cc_reg_ = eq; | 3914 cc_reg_ = eq; |
3999 } | 3915 } |
4000 | 3916 |
4001 | 3917 |
4002 void ArmCodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3918 void ArmCodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
4003 ASSERT(args->length() == 1); | 3919 ASSERT(args->length() == 1); |
4004 Load(args->at(0)); | 3920 Load(args->at(0)); |
4005 __ pop(r0); | 3921 __ pop(r0); |
4006 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); | 3922 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); |
4007 cc_reg_ = eq; | 3923 cc_reg_ = eq; |
4008 } | 3924 } |
4009 | 3925 |
4010 | 3926 |
4011 | |
4012 // This should generate code that performs a charCodeAt() call or returns | 3927 // This should generate code that performs a charCodeAt() call or returns |
4013 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3928 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
4014 // It is not yet implemented on ARM, so it always goes to the slow case. | 3929 // It is not yet implemented on ARM, so it always goes to the slow case. |
4015 void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3930 void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
4016 ASSERT(args->length() == 2); | 3931 ASSERT(args->length() == 2); |
4017 __ mov(r0, Operand(Factory::undefined_value())); | 3932 __ mov(r0, Operand(Factory::undefined_value())); |
4018 __ push(r0); | 3933 __ push(r0); |
4019 } | 3934 } |
4020 | 3935 |
4021 | 3936 |
4022 | |
4023 // This is used in the implementation of apply on ia32 but it is not | |
4024 // used on ARM yet. | |
4025 void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3937 void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
4026 __ stop("ArmCodeGenerator::GenerateIsArray"); | 3938 ASSERT(args->length() == 1); |
| 3939 Load(args->at(0)); |
| 3940 Label answer; |
| 3941 // We need the CC bits to come out as not_equal in the case where the |
| 3942 // object is a smi. This can't be done with the usual test opcode so |
| 3943 // we use XOR to get the right CC bits. |
| 3944 __ pop(r0); |
| 3945 __ and_(r1, r0, Operand(kSmiTagMask)); |
| 3946 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
| 3947 __ b(ne, &answer); |
| 3948 // It is a heap object - get the map. |
| 3949 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 3950 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3951 // Check if the object is a JS array or not. |
| 3952 __ cmp(r1, Operand(JS_ARRAY_TYPE)); |
| 3953 __ bind(&answer); |
4027 cc_reg_ = eq; | 3954 cc_reg_ = eq; |
4028 } | 3955 } |
4029 | 3956 |
4030 | 3957 |
4031 void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 3958 void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
4032 ASSERT(args->length() == 0); | 3959 ASSERT(args->length() == 0); |
4033 | 3960 |
4034 // Seed the result with the formal parameters count, which will be used | 3961 // Seed the result with the formal parameters count, which will be used |
4035 // in case no arguments adaptor frame is found below the current frame. | 3962 // in case no arguments adaptor frame is found below the current frame. |
4036 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | 3963 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
4037 | 3964 |
4038 // Call the shared stub to get to the arguments.length. | 3965 // Call the shared stub to get to the arguments.length. |
4039 ArgumentsAccessStub stub(true); | 3966 ArgumentsAccessStub stub(true); |
4040 __ CallStub(&stub); | 3967 __ CallStub(&stub); |
4041 __ push(r0); | 3968 __ push(r0); |
4042 } | 3969 } |
4043 | 3970 |
4044 | 3971 |
4045 void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3972 void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
4046 ASSERT(args->length() == 1); | 3973 ASSERT(args->length() == 1); |
4047 | 3974 |
4048 // Load the key onto the stack and set register r1 to the formal | 3975 // Satisfy contract with ArgumentsAccessStub: |
4049 // parameters count for the currently executing function. | 3976 // Load the key into r1 and the formal parameters count into r0. |
4050 Load(args->at(0)); | 3977 Load(args->at(0)); |
4051 __ pop(r0); | 3978 __ pop(r1); |
4052 __ mov(r1, Operand(Smi::FromInt(scope_->num_parameters()))); | 3979 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
4053 | 3980 |
4054 // Call the shared stub to get to arguments[key]. | 3981 // Call the shared stub to get to arguments[key]. |
4055 ArgumentsAccessStub stub(false); | 3982 ArgumentsAccessStub stub(false); |
4056 __ CallStub(&stub); | 3983 __ CallStub(&stub); |
4057 __ push(r0); | 3984 __ push(r0); |
4058 } | 3985 } |
4059 | 3986 |
4060 | 3987 |
4061 void ArmCodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3988 void ArmCodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
4062 ASSERT(args->length() == 2); | 3989 ASSERT(args->length() == 2); |
4063 | 3990 |
4064 // Load the two objects into registers and perform the comparison. | 3991 // Load the two objects into registers and perform the comparison. |
4065 Load(args->at(0)); | 3992 Load(args->at(0)); |
4066 Load(args->at(1)); | 3993 Load(args->at(1)); |
4067 __ pop(r0); | 3994 __ pop(r0); |
4068 __ pop(r1); | 3995 __ pop(r1); |
4069 __ cmp(r0, Operand(r1)); | 3996 __ cmp(r0, Operand(r1)); |
4070 cc_reg_ = eq; | 3997 cc_reg_ = eq; |
4071 } | 3998 } |
4072 | 3999 |
4073 | 4000 |
4074 void ArmCodeGenerator::GenerateShiftDownAndTailCall( | 4001 void ArmCodeGenerator::GenerateShiftDownAndTailCall( |
4075 ZoneList<Expression*>* args) { | 4002 ZoneList<Expression*>* args) { |
4076 // r0 = number of arguments | 4003 __ stop("ArmCodeGenerator::GenerateShiftDownAndTailCall - unreachable"); |
4077 ASSERT(args->length() == 1); | |
4078 Load(args->at(0)); | |
4079 __ pop(r0); | |
4080 __ mov(r0, Operand(r0, LSR, kSmiTagSize)); | |
4081 | |
4082 // Get the 'this' function and exit the frame without returning. | |
4083 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | |
4084 ExitJSFrame(DO_NOT_RETURN); | |
4085 // return address in lr | |
4086 | |
4087 // Move arguments one element down the stack. | |
4088 Label move; | |
4089 Label moved; | |
4090 __ sub(r2, r0, Operand(0), SetCC); | |
4091 __ b(eq, &moved); | |
4092 __ bind(&move); | |
4093 __ sub(ip, r2, Operand(1)); | |
4094 __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2)); | |
4095 __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2)); | |
4096 __ sub(r2, r2, Operand(1), SetCC); | |
4097 __ b(ne, &move); | |
4098 __ bind(&moved); | |
4099 | |
4100 // Remove the TOS (copy of last argument) | |
4101 __ pop(); | |
4102 | |
4103 // Jump (tail-call) to the function in register r1. | |
4104 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
4105 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
4106 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset)); | |
4107 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); | |
4108 | |
4109 return; | |
4110 } | 4004 } |
4111 | 4005 |
4112 | 4006 |
4113 void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) { | 4007 void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) { |
4114 if (CheckForInlineRuntimeCall(node)) | 4008 if (CheckForInlineRuntimeCall(node)) return; |
4115 return; | |
4116 | 4009 |
4117 ZoneList<Expression*>* args = node->arguments(); | 4010 ZoneList<Expression*>* args = node->arguments(); |
4118 Comment cmnt(masm_, "[ CallRuntime"); | 4011 Comment cmnt(masm_, "[ CallRuntime"); |
4119 Runtime::Function* function = node->function(); | 4012 Runtime::Function* function = node->function(); |
4120 | 4013 |
4121 if (function != NULL) { | 4014 if (function != NULL) { |
4122 // Push the arguments ("left-to-right"). | 4015 // Push the arguments ("left-to-right"). |
4123 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 4016 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
4124 | 4017 |
4125 // Call the C runtime function. | 4018 // Call the C runtime function. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4160 true); | 4053 true); |
4161 cc_reg_ = NegateCondition(cc_reg_); | 4054 cc_reg_ = NegateCondition(cc_reg_); |
4162 | 4055 |
4163 } else if (op == Token::DELETE) { | 4056 } else if (op == Token::DELETE) { |
4164 Property* property = node->expression()->AsProperty(); | 4057 Property* property = node->expression()->AsProperty(); |
4165 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 4058 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
4166 if (property != NULL) { | 4059 if (property != NULL) { |
4167 Load(property->obj()); | 4060 Load(property->obj()); |
4168 Load(property->key()); | 4061 Load(property->key()); |
4169 __ mov(r0, Operand(1)); // not counting receiver | 4062 __ mov(r0, Operand(1)); // not counting receiver |
4170 __ InvokeBuiltin("DELETE", 1, CALL_JS); | 4063 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
4171 | 4064 |
4172 } else if (variable != NULL) { | 4065 } else if (variable != NULL) { |
4173 Slot* slot = variable->slot(); | 4066 Slot* slot = variable->slot(); |
4174 if (variable->is_global()) { | 4067 if (variable->is_global()) { |
4175 LoadGlobal(); | 4068 LoadGlobal(); |
4176 __ mov(r0, Operand(variable->name())); | 4069 __ mov(r0, Operand(variable->name())); |
4177 __ push(r0); | 4070 __ push(r0); |
4178 __ mov(r0, Operand(1)); // not counting receiver | 4071 __ mov(r0, Operand(1)); // not counting receiver |
4179 __ InvokeBuiltin("DELETE", 1, CALL_JS); | 4072 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
4180 | 4073 |
4181 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 4074 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
4182 // lookup the context holding the named variable | 4075 // lookup the context holding the named variable |
4183 __ push(cp); | 4076 __ push(cp); |
4184 __ mov(r0, Operand(variable->name())); | 4077 __ mov(r0, Operand(variable->name())); |
4185 __ push(r0); | 4078 __ push(r0); |
4186 __ CallRuntime(Runtime::kLookupContext, 2); | 4079 __ CallRuntime(Runtime::kLookupContext, 2); |
4187 // r0: context | 4080 // r0: context |
4188 __ push(r0); | 4081 __ push(r0); |
4189 __ mov(r0, Operand(variable->name())); | 4082 __ mov(r0, Operand(variable->name())); |
4190 __ push(r0); | 4083 __ push(r0); |
4191 __ mov(r0, Operand(1)); // not counting receiver | 4084 __ mov(r0, Operand(1)); // not counting receiver |
4192 __ InvokeBuiltin("DELETE", 1, CALL_JS); | 4085 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
4193 | 4086 |
4194 } else { | 4087 } else { |
4195 // Default: Result of deleting non-global, not dynamically | 4088 // Default: Result of deleting non-global, not dynamically |
4196 // introduced variables is false. | 4089 // introduced variables is false. |
4197 __ mov(r0, Operand(Factory::false_value())); | 4090 __ mov(r0, Operand(Factory::false_value())); |
4198 } | 4091 } |
4199 | 4092 |
4200 } else { | 4093 } else { |
4201 // Default: Result of deleting expressions is true. | 4094 // Default: Result of deleting expressions is true. |
4202 Load(node->expression()); // may have side-effects | 4095 Load(node->expression()); // may have side-effects |
(...skipping 27 matching lines...) Expand all Loading... |
4230 | 4123 |
4231 case Token::BIT_NOT: { | 4124 case Token::BIT_NOT: { |
4232 // smi check | 4125 // smi check |
4233 Label smi_label; | 4126 Label smi_label; |
4234 Label continue_label; | 4127 Label continue_label; |
4235 __ tst(r0, Operand(kSmiTagMask)); | 4128 __ tst(r0, Operand(kSmiTagMask)); |
4236 __ b(eq, &smi_label); | 4129 __ b(eq, &smi_label); |
4237 | 4130 |
4238 __ push(r0); | 4131 __ push(r0); |
4239 __ mov(r0, Operand(0)); // not counting receiver | 4132 __ mov(r0, Operand(0)); // not counting receiver |
4240 __ InvokeBuiltin("BIT_NOT", 0, CALL_JS); | 4133 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); |
4241 | 4134 |
4242 __ b(&continue_label); | 4135 __ b(&continue_label); |
4243 __ bind(&smi_label); | 4136 __ bind(&smi_label); |
4244 __ mvn(r0, Operand(r0)); | 4137 __ mvn(r0, Operand(r0)); |
4245 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag | 4138 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag |
4246 __ bind(&continue_label); | 4139 __ bind(&continue_label); |
4247 break; | 4140 break; |
4248 } | 4141 } |
4249 | 4142 |
4250 case Token::VOID: | 4143 case Token::VOID: |
4251 // since the stack top is cached in r0, popping and then | 4144 // since the stack top is cached in r0, popping and then |
4252 // pushing a value can be done by just writing to r0. | 4145 // pushing a value can be done by just writing to r0. |
4253 __ mov(r0, Operand(Factory::undefined_value())); | 4146 __ mov(r0, Operand(Factory::undefined_value())); |
4254 break; | 4147 break; |
4255 | 4148 |
4256 case Token::ADD: { | 4149 case Token::ADD: { |
4257 // Smi check. | 4150 // Smi check. |
4258 Label continue_label; | 4151 Label continue_label; |
4259 __ tst(r0, Operand(kSmiTagMask)); | 4152 __ tst(r0, Operand(kSmiTagMask)); |
4260 __ b(eq, &continue_label); | 4153 __ b(eq, &continue_label); |
4261 __ push(r0); | 4154 __ push(r0); |
4262 __ mov(r0, Operand(0)); // not counting receiver | 4155 __ mov(r0, Operand(0)); // not counting receiver |
4263 __ InvokeBuiltin("TO_NUMBER", 0, CALL_JS); | 4156 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
4264 __ bind(&continue_label); | 4157 __ bind(&continue_label); |
4265 break; | 4158 break; |
4266 } | 4159 } |
4267 default: | 4160 default: |
4268 UNREACHABLE(); | 4161 UNREACHABLE(); |
4269 } | 4162 } |
4270 __ push(r0); // r0 has result | 4163 __ push(r0); // r0 has result |
4271 } | 4164 } |
4272 } | 4165 } |
4273 | 4166 |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4651 case Token::GTE: | 4544 case Token::GTE: |
4652 Comparison(ge); | 4545 Comparison(ge); |
4653 break; | 4546 break; |
4654 | 4547 |
4655 case Token::EQ_STRICT: | 4548 case Token::EQ_STRICT: |
4656 Comparison(eq, true); | 4549 Comparison(eq, true); |
4657 break; | 4550 break; |
4658 | 4551 |
4659 case Token::IN: | 4552 case Token::IN: |
4660 __ mov(r0, Operand(1)); // not counting receiver | 4553 __ mov(r0, Operand(1)); // not counting receiver |
4661 __ InvokeBuiltin("IN", 1, CALL_JS); | 4554 __ InvokeBuiltin(Builtins::IN, CALL_JS); |
4662 __ push(r0); | 4555 __ push(r0); |
4663 break; | 4556 break; |
4664 | 4557 |
4665 case Token::INSTANCEOF: | 4558 case Token::INSTANCEOF: |
4666 __ mov(r0, Operand(1)); // not counting receiver | 4559 __ mov(r0, Operand(1)); // not counting receiver |
4667 __ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS); | 4560 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS); |
4668 __ push(r0); | 4561 __ push(r0); |
4669 break; | 4562 break; |
4670 | 4563 |
4671 default: | 4564 default: |
4672 UNREACHABLE(); | 4565 UNREACHABLE(); |
4673 } | 4566 } |
4674 } | 4567 } |
4675 | 4568 |
4676 | 4569 |
4677 void ArmCodeGenerator::RecordStatementPosition(Node* node) { | 4570 void ArmCodeGenerator::RecordStatementPosition(Node* node) { |
4678 if (FLAG_debug_info) { | 4571 if (FLAG_debug_info) { |
4679 int statement_pos = node->statement_pos(); | 4572 int statement_pos = node->statement_pos(); |
4680 if (statement_pos == kNoPosition) return; | 4573 if (statement_pos == kNoPosition) return; |
4681 __ RecordStatementPosition(statement_pos); | 4574 __ RecordStatementPosition(statement_pos); |
4682 } | 4575 } |
4683 } | 4576 } |
4684 | 4577 |
4685 | 4578 |
4686 void ArmCodeGenerator::EnterJSFrame(int argc) { | 4579 void ArmCodeGenerator::EnterJSFrame() { |
4687 __ EnterJSFrame(argc); | 4580 #if defined(DEBUG) |
| 4581 { Label done, fail; |
| 4582 __ tst(r1, Operand(kSmiTagMask)); |
| 4583 __ b(eq, &fail); |
| 4584 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 4585 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 4586 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| 4587 __ b(eq, &done); |
| 4588 __ bind(&fail); |
| 4589 __ stop("ArmCodeGenerator::EnterJSFrame - r1 not a function"); |
| 4590 __ bind(&done); |
| 4591 } |
| 4592 #endif // DEBUG |
| 4593 |
| 4594 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| 4595 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. |
4688 } | 4596 } |
4689 | 4597 |
4690 | 4598 |
4691 void ArmCodeGenerator::ExitJSFrame(ExitJSFlag flag) { | 4599 void ArmCodeGenerator::ExitJSFrame() { |
4692 JSExitStub stub(flag); | 4600 // Drop the execution stack down to the frame pointer and restore the caller |
4693 __ CallJSExitStub(&stub); | 4601 // frame pointer and return address. |
| 4602 __ mov(sp, fp); |
| 4603 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
4694 } | 4604 } |
4695 | 4605 |
4696 | 4606 |
4697 #undef __ | 4607 #undef __ |
4698 | 4608 |
4699 | 4609 |
4700 // ----------------------------------------------------------------------------- | 4610 // ----------------------------------------------------------------------------- |
4701 // CodeGenerator interface | 4611 // CodeGenerator interface |
4702 | 4612 |
4703 // MakeCode() is just a wrapper for CodeGenerator::MakeCode() | 4613 // MakeCode() is just a wrapper for CodeGenerator::MakeCode() |
4704 // so we don't have to expose the entire CodeGenerator class in | 4614 // so we don't have to expose the entire CodeGenerator class in |
4705 // the .h file. | 4615 // the .h file. |
4706 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun, | 4616 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun, |
4707 Handle<Script> script, | 4617 Handle<Script> script, |
4708 bool is_eval) { | 4618 bool is_eval) { |
4709 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | 4619 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); |
4710 if (!code.is_null()) { | 4620 if (!code.is_null()) { |
4711 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 4621 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
4712 } | 4622 } |
4713 return code; | 4623 return code; |
4714 } | 4624 } |
4715 | 4625 |
4716 | 4626 |
4717 } } // namespace v8::internal | 4627 } } // namespace v8::internal |
OLD | NEW |