| 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 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 | 242 |
| 243 ldr(scratch, MemOperand(object)); | 243 ldr(scratch, MemOperand(object)); |
| 244 mov(ip, Operand(1)); | 244 mov(ip, Operand(1)); |
| 245 orr(scratch, scratch, Operand(ip, LSL, offset)); | 245 orr(scratch, scratch, Operand(ip, LSL, offset)); |
| 246 str(scratch, MemOperand(object)); | 246 str(scratch, MemOperand(object)); |
| 247 | 247 |
| 248 bind(&done); | 248 bind(&done); |
| 249 } | 249 } |
| 250 | 250 |
| 251 | 251 |
| 252 void MacroAssembler::EnterJSFrame(int argc) { | 252 void MacroAssembler::EnterInternalFrame() { |
| 253 // Generate code entering a JS function called from a JS function | 253 // r0-r3: preserved |
| 254 // stack: receiver, arguments | 254 int type = StackFrame::INTERNAL; |
| 255 // r0: number of arguments (not including function, nor receiver) | |
| 256 // r1: preserved | |
| 257 // sp: stack pointer | |
| 258 // fp: frame pointer | |
| 259 // cp: callee's context | |
| 260 // pp: caller's parameter pointer | |
| 261 // lr: return address | |
| 262 | 255 |
| 263 // compute parameter pointer before making changes | 256 stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
| 264 // ip = sp + kPointerSize*(args_len+1); // +1 for receiver | 257 mov(ip, Operand(Smi::FromInt(type))); |
| 265 add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); | 258 push(ip); |
| 266 add(ip, ip, Operand(kPointerSize)); | 259 mov(ip, Operand(0)); |
| 267 | 260 push(ip); // Push an empty code cache slot. |
| 268 // push extra parameters if we don't have enough | 261 add(fp, sp, Operand(3 * kPointerSize)); // Adjust FP to point to saved FP. |
| 269 // (this can only happen if argc > 0 to begin with) | |
| 270 if (argc > 0) { | |
| 271 Label loop, done; | |
| 272 | |
| 273 // assume enough arguments to be the most common case | |
| 274 sub(r2, r0, Operand(argc), SetCC); // number of missing arguments | |
| 275 b(ge, &done); // enough arguments | |
| 276 | |
| 277 // not enough arguments | |
| 278 mov(r3, Operand(Factory::undefined_value())); | |
| 279 bind(&loop); | |
| 280 push(r3); | |
| 281 add(r2, r2, Operand(1), SetCC); | |
| 282 b(lt, &loop); | |
| 283 | |
| 284 bind(&done); | |
| 285 } | |
| 286 | |
| 287 mov(r3, Operand(r0)); // args_len to be saved | |
| 288 mov(r2, Operand(cp)); // context to be saved | |
| 289 | |
| 290 // push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp, | |
| 291 // sp_on_exit (ip == pp, may be patched on exit), return address | |
| 292 stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() | | |
| 293 ip.bit() | lr.bit()); | |
| 294 | |
| 295 // Setup new frame pointer. | |
| 296 add(fp, sp, Operand(-StandardFrameConstants::kContextOffset)); | |
| 297 mov(pp, Operand(ip)); // setup new parameter pointer | |
| 298 mov(r0, Operand(0)); // spare slot to store caller code object during GC | |
| 299 push(r0); | |
| 300 // r1: preserved | |
| 301 } | 262 } |
| 302 | 263 |
| 303 | 264 |
| 304 void MacroAssembler::ExitJSFrame(ExitJSFlag flag) { | 265 void MacroAssembler::ExitInternalFrame() { |
| 305 // r0: result | 266 // r0: preserved |
| 306 // sp: stack pointer | 267 // r1: preserved |
| 307 // fp: frame pointer | 268 // r2: preserved |
| 308 // pp: parameter pointer | |
| 309 | 269 |
| 310 if (flag == DO_NOT_RETURN) { | 270 // Drop the execution stack down to the frame pointer and restore the caller |
| 311 add(r3, fp, Operand(JavaScriptFrameConstants::kSavedRegistersOffset)); | 271 // frame pointer and return address. |
| 312 } | 272 mov(sp, fp); |
| 313 | 273 ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 314 if (flag == DO_NOT_RETURN) { | |
| 315 // restore sp as caller_sp (not as pp) | |
| 316 str(r3, MemOperand(fp, JavaScriptFrameConstants::kSPOnExitOffset)); | |
| 317 } | |
| 318 | |
| 319 if (flag == DO_NOT_RETURN && generating_stub()) { | |
| 320 // If we're generating a stub, we need to preserve the link | |
| 321 // register to be able to return to the place the stub was called | |
| 322 // from. | |
| 323 mov(ip, Operand(lr)); | |
| 324 } | |
| 325 | |
| 326 mov(sp, Operand(fp)); // respect ABI stack constraint | |
| 327 ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | | |
| 328 ((flag == RETURN) ? pc.bit() : lr.bit())); | |
| 329 | |
| 330 if (flag == DO_NOT_RETURN && generating_stub()) { | |
| 331 // Return to the place where the stub was called without | |
| 332 // clobbering the value of the link register. | |
| 333 mov(pc, Operand(ip)); | |
| 334 } | |
| 335 | |
| 336 // r0: result | |
| 337 // sp: points to function arg (if return) or to last arg (if no return) | |
| 338 // fp: restored frame pointer | |
| 339 // pp: restored parameter pointer | |
| 340 } | 274 } |
| 341 | 275 |
| 342 | 276 |
| 343 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | 277 void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
| 344 const ParameterCount& actual, | 278 const ParameterCount& actual, |
| 345 Handle<Code> code_constant, | 279 Handle<Code> code_constant, |
| 346 Register code_reg, | 280 Register code_reg, |
| 347 Label* done, | 281 Label* done, |
| 348 InvokeFlag flag) { | 282 InvokeFlag flag) { |
| 349 if (actual.is_immediate()) { | 283 bool definitely_matches = false; |
| 350 mov(r0, Operand(actual.immediate())); // Push the number of arguments. | 284 Label regular_invoke; |
| 285 |
| 286 // Check whether the expected and actual arguments count match. If not, |
| 287 // setup registers according to contract with ArgumentsAdaptorTrampoline: |
| 288 // r0: actual arguments count |
| 289 // r1: function (passed through to callee) |
| 290 // r2: expected arguments count |
| 291 // r3: callee code entry |
| 292 |
| 293 // The code below is made a lot easier because the calling code already sets |
| 294 // up actual and expected registers according to the contract if values are |
| 295 // passed in registers. |
| 296 ASSERT(actual.is_immediate() || actual.reg().is(r0)); |
| 297 ASSERT(expected.is_immediate() || expected.reg().is(r2)); |
| 298 ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(r3)); |
| 299 |
| 300 if (expected.is_immediate()) { |
| 301 ASSERT(actual.is_immediate()); |
| 302 if (expected.immediate() == actual.immediate()) { |
| 303 definitely_matches = true; |
| 304 } else { |
| 305 mov(r0, Operand(actual.immediate())); |
| 306 mov(r2, Operand(expected.immediate())); |
| 307 } |
| 351 } else { | 308 } else { |
| 352 if (!actual.reg().is(r0)) { | 309 if (actual.is_immediate()) { |
| 353 mov(r0, Operand(actual.reg())); | 310 cmp(expected.reg(), Operand(actual.immediate())); |
| 311 b(eq, ®ular_invoke); |
| 312 mov(r0, Operand(actual.immediate())); |
| 313 } else { |
| 314 cmp(expected.reg(), Operand(actual.reg())); |
| 315 b(eq, ®ular_invoke); |
| 354 } | 316 } |
| 355 } | 317 } |
| 318 |
| 319 if (!definitely_matches) { |
| 320 if (!code_constant.is_null()) { |
| 321 mov(r3, Operand(code_constant)); |
| 322 add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 323 } |
| 324 |
| 325 Handle<Code> adaptor = |
| 326 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
| 327 if (flag == CALL_FUNCTION) { |
| 328 Call(adaptor, code_target); |
| 329 b(done); |
| 330 } else { |
| 331 Jump(adaptor, code_target); |
| 332 } |
| 333 bind(®ular_invoke); |
| 334 } |
| 356 } | 335 } |
| 357 | 336 |
| 358 | 337 |
| 359 void MacroAssembler::InvokeCode(Register code, | 338 void MacroAssembler::InvokeCode(Register code, |
| 360 const ParameterCount& expected, | 339 const ParameterCount& expected, |
| 361 const ParameterCount& actual, | 340 const ParameterCount& actual, |
| 362 InvokeFlag flag) { | 341 InvokeFlag flag) { |
| 363 Label done; | 342 Label done; |
| 364 | 343 |
| 365 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag); | 344 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 395 bind(&done); | 374 bind(&done); |
| 396 } | 375 } |
| 397 | 376 |
| 398 | 377 |
| 399 void MacroAssembler::InvokeFunction(Register fun, | 378 void MacroAssembler::InvokeFunction(Register fun, |
| 400 const ParameterCount& actual, | 379 const ParameterCount& actual, |
| 401 InvokeFlag flag) { | 380 InvokeFlag flag) { |
| 402 // Contract with called JS functions requires that function is passed in r1. | 381 // Contract with called JS functions requires that function is passed in r1. |
| 403 ASSERT(fun.is(r1)); | 382 ASSERT(fun.is(r1)); |
| 404 | 383 |
| 384 Register expected_reg = r2; |
| 405 Register code_reg = r3; | 385 Register code_reg = r3; |
| 406 Register expected_reg = r2; | |
| 407 | |
| 408 // Make sure that the code and expected registers do not collide with the | |
| 409 // actual register being passed in. | |
| 410 if (actual.is_reg()) { | |
| 411 if (actual.reg().is(code_reg)) { | |
| 412 code_reg = r4; | |
| 413 } else if (actual.reg().is(expected_reg)) { | |
| 414 expected_reg = r4; | |
| 415 } | |
| 416 } | |
| 417 | 386 |
| 418 ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | 387 ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 419 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 388 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 420 ldr(expected_reg, | 389 ldr(expected_reg, |
| 421 FieldMemOperand(code_reg, | 390 FieldMemOperand(code_reg, |
| 422 SharedFunctionInfo::kFormalParameterCountOffset)); | 391 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 423 ldr(code_reg, | 392 ldr(code_reg, |
| 424 MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); | 393 MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); |
| 425 add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); | 394 add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 426 | 395 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 mov(r3, Operand(StackHandler::TRY_FINALLY)); | 469 mov(r3, Operand(StackHandler::TRY_FINALLY)); |
| 501 } | 470 } |
| 502 push(r3); // state | 471 push(r3); // state |
| 503 mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 472 mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 504 ldr(r1, MemOperand(r3)); | 473 ldr(r1, MemOperand(r3)); |
| 505 push(r1); // next sp | 474 push(r1); // next sp |
| 506 str(sp, MemOperand(r3)); // chain handler | 475 str(sp, MemOperand(r3)); // chain handler |
| 507 mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS | 476 mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS |
| 508 push(r0); | 477 push(r0); |
| 509 } else { | 478 } else { |
| 510 // Must preserve r0-r3, r5-r7 are available. | 479 // Must preserve r0-r4, r5-r7 are available. |
| 511 ASSERT(try_location == IN_JS_ENTRY); | 480 ASSERT(try_location == IN_JS_ENTRY); |
| 512 // The parameter pointer is meaningless here and fp does not point to a JS | 481 // The parameter pointer is meaningless here and fp does not point to a JS |
| 513 // frame. So we save NULL for both pp and fp. We expect the code throwing an | 482 // frame. So we save NULL for both pp and fp. We expect the code throwing an |
| 514 // exception to check fp before dereferencing it to restore the context. | 483 // exception to check fp before dereferencing it to restore the context. |
| 515 mov(pp, Operand(0)); // set pp to NULL | 484 mov(pp, Operand(0)); // set pp to NULL |
| 516 mov(ip, Operand(0)); // to save a NULL fp | 485 mov(ip, Operand(0)); // to save a NULL fp |
| 517 stm(db_w, sp, pp.bit() | ip.bit() | lr.bit()); | 486 stm(db_w, sp, pp.bit() | ip.bit() | lr.bit()); |
| 518 mov(r6, Operand(StackHandler::ENTRY)); | 487 mov(r6, Operand(StackHandler::ENTRY)); |
| 519 push(r6); // state | 488 push(r6); // state |
| 520 mov(r7, Operand(ExternalReference(Top::k_handler_address))); | 489 mov(r7, Operand(ExternalReference(Top::k_handler_address))); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 #if defined(__thumb__) | 650 #if defined(__thumb__) |
| 682 // Thumb mode builtin. | 651 // Thumb mode builtin. |
| 683 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); | 652 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); |
| 684 #endif | 653 #endif |
| 685 mov(r1, Operand(builtin)); | 654 mov(r1, Operand(builtin)); |
| 686 CEntryStub stub; | 655 CEntryStub stub; |
| 687 Jump(stub.GetCode(), code_target); | 656 Jump(stub.GetCode(), code_target); |
| 688 } | 657 } |
| 689 | 658 |
| 690 | 659 |
| 691 void MacroAssembler::InvokeBuiltin(const char* name, | 660 Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id, |
| 692 int argc, | 661 bool* resolved) { |
| 662 // Contract with compiled functions is that the function is passed in r1. |
| 663 int builtins_offset = |
| 664 JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); |
| 665 ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 666 ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); |
| 667 ldr(r1, FieldMemOperand(r1, builtins_offset)); |
| 668 |
| 669 return Builtins::GetCode(id, resolved); |
| 670 } |
| 671 |
| 672 |
| 673 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
| 693 InvokeJSFlags flags) { | 674 InvokeJSFlags flags) { |
| 694 Handle<String> symbol = Factory::LookupAsciiSymbol(name); | 675 bool resolved; |
| 695 Object* object = Top::security_context_builtins()->GetProperty(*symbol); | 676 Handle<Code> code = ResolveBuiltin(id, &resolved); |
| 696 bool unresolved = true; | |
| 697 Code* code = Builtins::builtin(Builtins::Illegal); | |
| 698 | 677 |
| 699 if (object->IsJSFunction()) { | 678 if (flags == CALL_JS) { |
| 700 Handle<JSFunction> function(JSFunction::cast(object)); | 679 Call(code, code_target); |
| 701 if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) { | 680 } else { |
| 702 code = function->code(); | 681 ASSERT(flags == JUMP_JS); |
| 703 unresolved = false; | 682 Jump(code, code_target); |
| 704 } | |
| 705 } | 683 } |
| 706 | 684 |
| 707 if (flags == CALL_JS) { | 685 if (!resolved) { |
| 708 Call(Handle<Code>(code), code_target); | 686 const char* name = Builtins::GetName(id); |
| 709 } else { | 687 int argc = Builtins::GetArgumentsCount(id); |
| 710 ASSERT(flags == JUMP_JS); | |
| 711 Jump(Handle<Code>(code), code_target); | |
| 712 } | |
| 713 | |
| 714 if (unresolved) { | |
| 715 uint32_t flags = | 688 uint32_t flags = |
| 716 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | | 689 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | |
| 717 Bootstrapper::FixupFlagsIsPCRelative::encode(false); | 690 Bootstrapper::FixupFlagsIsPCRelative::encode(true); |
| 691 Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; |
| 692 unresolved_.Add(entry); |
| 693 } |
| 694 } |
| 695 |
| 696 |
| 697 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { |
| 698 bool resolved; |
| 699 Handle<Code> code = ResolveBuiltin(id, &resolved); |
| 700 |
| 701 mov(target, Operand(code)); |
| 702 if (!resolved) { |
| 703 const char* name = Builtins::GetName(id); |
| 704 int argc = Builtins::GetArgumentsCount(id); |
| 705 uint32_t flags = |
| 706 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | |
| 707 Bootstrapper::FixupFlagsIsPCRelative::encode(true); |
| 718 Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; | 708 Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; |
| 719 unresolved_.Add(entry); | 709 unresolved_.Add(entry); |
| 720 } | 710 } |
| 721 } | 711 } |
| 722 | 712 |
| 723 | 713 |
| 724 void MacroAssembler::Assert(Condition cc, const char* msg) { | 714 void MacroAssembler::Assert(Condition cc, const char* msg) { |
| 725 if (FLAG_debug_code) | 715 if (FLAG_debug_code) |
| 726 Check(cc, msg); | 716 Check(cc, msg); |
| 727 } | 717 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 753 #endif | 743 #endif |
| 754 mov(r0, Operand(p0)); | 744 mov(r0, Operand(p0)); |
| 755 push(r0); | 745 push(r0); |
| 756 mov(r0, Operand(Smi::FromInt(p1 - p0))); | 746 mov(r0, Operand(Smi::FromInt(p1 - p0))); |
| 757 push(r0); | 747 push(r0); |
| 758 CallRuntime(Runtime::kAbort, 2); | 748 CallRuntime(Runtime::kAbort, 2); |
| 759 // will not return here | 749 // will not return here |
| 760 } | 750 } |
| 761 | 751 |
| 762 } } // namespace v8::internal | 752 } } // namespace v8::internal |
| OLD | NEW |