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 |