OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 ASSERT(!AreAliased(object, address, value, t8)); | 249 ASSERT(!AreAliased(object, address, value, t8)); |
250 ASSERT(!AreAliased(object, address, value, t9)); | 250 ASSERT(!AreAliased(object, address, value, t9)); |
251 // The compiled code assumes that record write doesn't change the | 251 // The compiled code assumes that record write doesn't change the |
252 // context register, so we check that none of the clobbered | 252 // context register, so we check that none of the clobbered |
253 // registers are cp. | 253 // registers are cp. |
254 ASSERT(!address.is(cp) && !value.is(cp)); | 254 ASSERT(!address.is(cp) && !value.is(cp)); |
255 | 255 |
256 if (emit_debug_code()) { | 256 if (emit_debug_code()) { |
257 lw(at, MemOperand(address)); | 257 lw(at, MemOperand(address)); |
258 Assert( | 258 Assert( |
259 eq, kWrongAddressOrValuePassedToRecordWrite, at, Operand(value)); | 259 eq, "Wrong address or value passed to RecordWrite", at, Operand(value)); |
260 } | 260 } |
261 | 261 |
262 Label done; | 262 Label done; |
263 | 263 |
264 if (smi_check == INLINE_SMI_CHECK) { | 264 if (smi_check == INLINE_SMI_CHECK) { |
265 ASSERT_EQ(0, kSmiTag); | 265 ASSERT_EQ(0, kSmiTag); |
266 JumpIfSmi(value, &done); | 266 JumpIfSmi(value, &done); |
267 } | 267 } |
268 | 268 |
269 CheckPageFlag(value, | 269 CheckPageFlag(value, |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 Label same_contexts; | 351 Label same_contexts; |
352 | 352 |
353 ASSERT(!holder_reg.is(scratch)); | 353 ASSERT(!holder_reg.is(scratch)); |
354 ASSERT(!holder_reg.is(at)); | 354 ASSERT(!holder_reg.is(at)); |
355 ASSERT(!scratch.is(at)); | 355 ASSERT(!scratch.is(at)); |
356 | 356 |
357 // Load current lexical context from the stack frame. | 357 // Load current lexical context from the stack frame. |
358 lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 358 lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
359 // In debug mode, make sure the lexical context is set. | 359 // In debug mode, make sure the lexical context is set. |
360 #ifdef DEBUG | 360 #ifdef DEBUG |
361 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext, | 361 Check(ne, "we should not have an empty lexical context", |
362 scratch, Operand(zero_reg)); | 362 scratch, Operand(zero_reg)); |
363 #endif | 363 #endif |
364 | 364 |
365 // Load the native context of the current context. | 365 // Load the native context of the current context. |
366 int offset = | 366 int offset = |
367 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize; | 367 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize; |
368 lw(scratch, FieldMemOperand(scratch, offset)); | 368 lw(scratch, FieldMemOperand(scratch, offset)); |
369 lw(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); | 369 lw(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |
370 | 370 |
371 // Check the context is a native context. | 371 // Check the context is a native context. |
372 if (emit_debug_code()) { | 372 if (emit_debug_code()) { |
373 push(holder_reg); // Temporarily save holder on the stack. | 373 push(holder_reg); // Temporarily save holder on the stack. |
374 // Read the first word and compare to the native_context_map. | 374 // Read the first word and compare to the native_context_map. |
375 lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 375 lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
376 LoadRoot(at, Heap::kNativeContextMapRootIndex); | 376 LoadRoot(at, Heap::kNativeContextMapRootIndex); |
377 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext, | 377 Check(eq, "JSGlobalObject::native_context should be a native context.", |
378 holder_reg, Operand(at)); | 378 holder_reg, Operand(at)); |
379 pop(holder_reg); // Restore holder. | 379 pop(holder_reg); // Restore holder. |
380 } | 380 } |
381 | 381 |
382 // Check if both contexts are the same. | 382 // Check if both contexts are the same. |
383 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 383 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
384 Branch(&same_contexts, eq, scratch, Operand(at)); | 384 Branch(&same_contexts, eq, scratch, Operand(at)); |
385 | 385 |
386 // Check the context is a native context. | 386 // Check the context is a native context. |
387 if (emit_debug_code()) { | 387 if (emit_debug_code()) { |
388 push(holder_reg); // Temporarily save holder on the stack. | 388 push(holder_reg); // Temporarily save holder on the stack. |
389 mov(holder_reg, at); // Move at to its holding place. | 389 mov(holder_reg, at); // Move at to its holding place. |
390 LoadRoot(at, Heap::kNullValueRootIndex); | 390 LoadRoot(at, Heap::kNullValueRootIndex); |
391 Check(ne, kJSGlobalProxyContextShouldNotBeNull, | 391 Check(ne, "JSGlobalProxy::context() should not be null.", |
392 holder_reg, Operand(at)); | 392 holder_reg, Operand(at)); |
393 | 393 |
394 lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 394 lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
395 LoadRoot(at, Heap::kNativeContextMapRootIndex); | 395 LoadRoot(at, Heap::kNativeContextMapRootIndex); |
396 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext, | 396 Check(eq, "JSGlobalObject::native_context should be a native context.", |
397 holder_reg, Operand(at)); | 397 holder_reg, Operand(at)); |
398 // Restore at is not needed. at is reloaded below. | 398 // Restore at is not needed. at is reloaded below. |
399 pop(holder_reg); // Restore holder. | 399 pop(holder_reg); // Restore holder. |
400 // Restore at to holder's context. | 400 // Restore at to holder's context. |
401 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 401 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
402 } | 402 } |
403 | 403 |
404 // Check that the security token in the calling global object is | 404 // Check that the security token in the calling global object is |
405 // compatible with the security token in the receiving global | 405 // compatible with the security token in the receiving global |
406 // object. | 406 // object. |
(...skipping 2524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2931 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 2931 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
2932 // Load allocation top into result and allocation limit into t9. | 2932 // Load allocation top into result and allocation limit into t9. |
2933 lw(result, MemOperand(topaddr)); | 2933 lw(result, MemOperand(topaddr)); |
2934 lw(t9, MemOperand(topaddr, kPointerSize)); | 2934 lw(t9, MemOperand(topaddr, kPointerSize)); |
2935 } else { | 2935 } else { |
2936 if (emit_debug_code()) { | 2936 if (emit_debug_code()) { |
2937 // Assert that result actually contains top on entry. t9 is used | 2937 // Assert that result actually contains top on entry. t9 is used |
2938 // immediately below so this use of t9 does not cause difference with | 2938 // immediately below so this use of t9 does not cause difference with |
2939 // respect to register content between debug and release mode. | 2939 // respect to register content between debug and release mode. |
2940 lw(t9, MemOperand(topaddr)); | 2940 lw(t9, MemOperand(topaddr)); |
2941 Check(eq, kUnexpectedAllocationTop, result, Operand(t9)); | 2941 Check(eq, "Unexpected allocation top", result, Operand(t9)); |
2942 } | 2942 } |
2943 // Load allocation limit into t9. Result already contains allocation top. | 2943 // Load allocation limit into t9. Result already contains allocation top. |
2944 lw(t9, MemOperand(topaddr, limit - top)); | 2944 lw(t9, MemOperand(topaddr, limit - top)); |
2945 } | 2945 } |
2946 | 2946 |
2947 // Calculate new top and bail out if new space is exhausted. Use result | 2947 // Calculate new top and bail out if new space is exhausted. Use result |
2948 // to calculate the new top. | 2948 // to calculate the new top. |
2949 Addu(scratch2, result, Operand(obj_size_reg)); | 2949 Addu(scratch2, result, Operand(obj_size_reg)); |
2950 Branch(gc_required, Ugreater, scratch2, Operand(t9)); | 2950 Branch(gc_required, Ugreater, scratch2, Operand(t9)); |
2951 sw(scratch2, MemOperand(topaddr)); | 2951 sw(scratch2, MemOperand(topaddr)); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3001 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 3001 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
3002 // Load allocation top into result and allocation limit into t9. | 3002 // Load allocation top into result and allocation limit into t9. |
3003 lw(result, MemOperand(topaddr)); | 3003 lw(result, MemOperand(topaddr)); |
3004 lw(t9, MemOperand(topaddr, kPointerSize)); | 3004 lw(t9, MemOperand(topaddr, kPointerSize)); |
3005 } else { | 3005 } else { |
3006 if (emit_debug_code()) { | 3006 if (emit_debug_code()) { |
3007 // Assert that result actually contains top on entry. t9 is used | 3007 // Assert that result actually contains top on entry. t9 is used |
3008 // immediately below so this use of t9 does not cause difference with | 3008 // immediately below so this use of t9 does not cause difference with |
3009 // respect to register content between debug and release mode. | 3009 // respect to register content between debug and release mode. |
3010 lw(t9, MemOperand(topaddr)); | 3010 lw(t9, MemOperand(topaddr)); |
3011 Check(eq, kUnexpectedAllocationTop, result, Operand(t9)); | 3011 Check(eq, "Unexpected allocation top", result, Operand(t9)); |
3012 } | 3012 } |
3013 // Load allocation limit into t9. Result already contains allocation top. | 3013 // Load allocation limit into t9. Result already contains allocation top. |
3014 lw(t9, MemOperand(topaddr, limit - top)); | 3014 lw(t9, MemOperand(topaddr, limit - top)); |
3015 } | 3015 } |
3016 | 3016 |
3017 // Calculate new top and bail out if new space is exhausted. Use result | 3017 // Calculate new top and bail out if new space is exhausted. Use result |
3018 // to calculate the new top. Object size may be in words so a shift is | 3018 // to calculate the new top. Object size may be in words so a shift is |
3019 // required to get the number of bytes. | 3019 // required to get the number of bytes. |
3020 if ((flags & SIZE_IN_WORDS) != 0) { | 3020 if ((flags & SIZE_IN_WORDS) != 0) { |
3021 sll(scratch2, object_size, kPointerSizeLog2); | 3021 sll(scratch2, object_size, kPointerSizeLog2); |
3022 Addu(scratch2, result, scratch2); | 3022 Addu(scratch2, result, scratch2); |
3023 } else { | 3023 } else { |
3024 Addu(scratch2, result, Operand(object_size)); | 3024 Addu(scratch2, result, Operand(object_size)); |
3025 } | 3025 } |
3026 Branch(gc_required, Ugreater, scratch2, Operand(t9)); | 3026 Branch(gc_required, Ugreater, scratch2, Operand(t9)); |
3027 | 3027 |
3028 // Update allocation top. result temporarily holds the new top. | 3028 // Update allocation top. result temporarily holds the new top. |
3029 if (emit_debug_code()) { | 3029 if (emit_debug_code()) { |
3030 And(t9, scratch2, Operand(kObjectAlignmentMask)); | 3030 And(t9, scratch2, Operand(kObjectAlignmentMask)); |
3031 Check(eq, kUnalignedAllocationInNewSpace, t9, Operand(zero_reg)); | 3031 Check(eq, "Unaligned allocation in new space", t9, Operand(zero_reg)); |
3032 } | 3032 } |
3033 sw(scratch2, MemOperand(topaddr)); | 3033 sw(scratch2, MemOperand(topaddr)); |
3034 | 3034 |
3035 // Tag object if requested. | 3035 // Tag object if requested. |
3036 if ((flags & TAG_OBJECT) != 0) { | 3036 if ((flags & TAG_OBJECT) != 0) { |
3037 Addu(result, result, Operand(kHeapObjectTag)); | 3037 Addu(result, result, Operand(kHeapObjectTag)); |
3038 } | 3038 } |
3039 } | 3039 } |
3040 | 3040 |
3041 | 3041 |
3042 void MacroAssembler::UndoAllocationInNewSpace(Register object, | 3042 void MacroAssembler::UndoAllocationInNewSpace(Register object, |
3043 Register scratch) { | 3043 Register scratch) { |
3044 ExternalReference new_space_allocation_top = | 3044 ExternalReference new_space_allocation_top = |
3045 ExternalReference::new_space_allocation_top_address(isolate()); | 3045 ExternalReference::new_space_allocation_top_address(isolate()); |
3046 | 3046 |
3047 // Make sure the object has no tag before resetting top. | 3047 // Make sure the object has no tag before resetting top. |
3048 And(object, object, Operand(~kHeapObjectTagMask)); | 3048 And(object, object, Operand(~kHeapObjectTagMask)); |
3049 #ifdef DEBUG | 3049 #ifdef DEBUG |
3050 // Check that the object un-allocated is below the current top. | 3050 // Check that the object un-allocated is below the current top. |
3051 li(scratch, Operand(new_space_allocation_top)); | 3051 li(scratch, Operand(new_space_allocation_top)); |
3052 lw(scratch, MemOperand(scratch)); | 3052 lw(scratch, MemOperand(scratch)); |
3053 Check(less, kUndoAllocationOfNonAllocatedMemory, | 3053 Check(less, "Undo allocation of non allocated memory", |
3054 object, Operand(scratch)); | 3054 object, Operand(scratch)); |
3055 #endif | 3055 #endif |
3056 // Write the address of the object to un-allocate as the current top. | 3056 // Write the address of the object to un-allocate as the current top. |
3057 li(scratch, Operand(new_space_allocation_top)); | 3057 li(scratch, Operand(new_space_allocation_top)); |
3058 sw(object, MemOperand(scratch)); | 3058 sw(object, MemOperand(scratch)); |
3059 } | 3059 } |
3060 | 3060 |
3061 | 3061 |
3062 void MacroAssembler::AllocateTwoByteString(Register result, | 3062 void MacroAssembler::AllocateTwoByteString(Register result, |
3063 Register length, | 3063 Register length, |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3296 Addu(src, src, 1); | 3296 Addu(src, src, 1); |
3297 sb(scratch, MemOperand(dst)); | 3297 sb(scratch, MemOperand(dst)); |
3298 Addu(dst, dst, 1); | 3298 Addu(dst, dst, 1); |
3299 Subu(length, length, Operand(1)); | 3299 Subu(length, length, Operand(1)); |
3300 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); | 3300 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); |
3301 | 3301 |
3302 // Copy bytes in word size chunks. | 3302 // Copy bytes in word size chunks. |
3303 bind(&word_loop); | 3303 bind(&word_loop); |
3304 if (emit_debug_code()) { | 3304 if (emit_debug_code()) { |
3305 And(scratch, src, kPointerSize - 1); | 3305 And(scratch, src, kPointerSize - 1); |
3306 Assert(eq, kExpectingAlignmentForCopyBytes, | 3306 Assert(eq, "Expecting alignment for CopyBytes", |
3307 scratch, Operand(zero_reg)); | 3307 scratch, Operand(zero_reg)); |
3308 } | 3308 } |
3309 Branch(&byte_loop, lt, length, Operand(kPointerSize)); | 3309 Branch(&byte_loop, lt, length, Operand(kPointerSize)); |
3310 lw(scratch, MemOperand(src)); | 3310 lw(scratch, MemOperand(src)); |
3311 Addu(src, src, kPointerSize); | 3311 Addu(src, src, kPointerSize); |
3312 | 3312 |
3313 // TODO(kalmard) check if this can be optimized to use sw in most cases. | 3313 // TODO(kalmard) check if this can be optimized to use sw in most cases. |
3314 // Can't use unaligned access - copy byte by byte. | 3314 // Can't use unaligned access - copy byte by byte. |
3315 sb(scratch, MemOperand(dst, 0)); | 3315 sb(scratch, MemOperand(dst, 0)); |
3316 srl(scratch, scratch, 8); | 3316 srl(scratch, scratch, 8); |
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4022 } | 4022 } |
4023 // Load value from ReturnValue. | 4023 // Load value from ReturnValue. |
4024 lw(v0, MemOperand(fp, return_value_offset_from_fp*kPointerSize)); | 4024 lw(v0, MemOperand(fp, return_value_offset_from_fp*kPointerSize)); |
4025 bind(&return_value_loaded); | 4025 bind(&return_value_loaded); |
4026 | 4026 |
4027 // No more valid handles (the result handle was the last one). Restore | 4027 // No more valid handles (the result handle was the last one). Restore |
4028 // previous handle scope. | 4028 // previous handle scope. |
4029 sw(s0, MemOperand(s3, kNextOffset)); | 4029 sw(s0, MemOperand(s3, kNextOffset)); |
4030 if (emit_debug_code()) { | 4030 if (emit_debug_code()) { |
4031 lw(a1, MemOperand(s3, kLevelOffset)); | 4031 lw(a1, MemOperand(s3, kLevelOffset)); |
4032 Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2)); | 4032 Check(eq, "Unexpected level after return from api call", a1, Operand(s2)); |
4033 } | 4033 } |
4034 Subu(s2, s2, Operand(1)); | 4034 Subu(s2, s2, Operand(1)); |
4035 sw(s2, MemOperand(s3, kLevelOffset)); | 4035 sw(s2, MemOperand(s3, kLevelOffset)); |
4036 lw(at, MemOperand(s3, kLimitOffset)); | 4036 lw(at, MemOperand(s3, kLimitOffset)); |
4037 Branch(&delete_allocated_handles, ne, s1, Operand(at)); | 4037 Branch(&delete_allocated_handles, ne, s1, Operand(at)); |
4038 | 4038 |
4039 // Check if the function scheduled an exception. | 4039 // Check if the function scheduled an exception. |
4040 bind(&leave_exit_frame); | 4040 bind(&leave_exit_frame); |
4041 LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 4041 LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
4042 li(at, Operand(ExternalReference::scheduled_exception_address(isolate()))); | 4042 li(at, Operand(ExternalReference::scheduled_exception_address(isolate()))); |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4376 lw(scratch1, MemOperand(scratch2)); | 4376 lw(scratch1, MemOperand(scratch2)); |
4377 Subu(scratch1, scratch1, Operand(value)); | 4377 Subu(scratch1, scratch1, Operand(value)); |
4378 sw(scratch1, MemOperand(scratch2)); | 4378 sw(scratch1, MemOperand(scratch2)); |
4379 } | 4379 } |
4380 } | 4380 } |
4381 | 4381 |
4382 | 4382 |
4383 // ----------------------------------------------------------------------------- | 4383 // ----------------------------------------------------------------------------- |
4384 // Debugging. | 4384 // Debugging. |
4385 | 4385 |
4386 void MacroAssembler::Assert(Condition cc, BailoutReason reason, | 4386 void MacroAssembler::Assert(Condition cc, const char* msg, |
4387 Register rs, Operand rt) { | 4387 Register rs, Operand rt) { |
4388 if (emit_debug_code()) | 4388 if (emit_debug_code()) |
4389 Check(cc, reason, rs, rt); | 4389 Check(cc, msg, rs, rt); |
4390 } | 4390 } |
4391 | 4391 |
4392 | 4392 |
4393 void MacroAssembler::AssertRegisterIsRoot(Register reg, | 4393 void MacroAssembler::AssertRegisterIsRoot(Register reg, |
4394 Heap::RootListIndex index) { | 4394 Heap::RootListIndex index) { |
4395 if (emit_debug_code()) { | 4395 if (emit_debug_code()) { |
4396 LoadRoot(at, index); | 4396 LoadRoot(at, index); |
4397 Check(eq, kRegisterDidNotMatchExpectedRoot, reg, Operand(at)); | 4397 Check(eq, "Register did not match expected root", reg, Operand(at)); |
4398 } | 4398 } |
4399 } | 4399 } |
4400 | 4400 |
4401 | 4401 |
4402 void MacroAssembler::AssertFastElements(Register elements) { | 4402 void MacroAssembler::AssertFastElements(Register elements) { |
4403 if (emit_debug_code()) { | 4403 if (emit_debug_code()) { |
4404 ASSERT(!elements.is(at)); | 4404 ASSERT(!elements.is(at)); |
4405 Label ok; | 4405 Label ok; |
4406 push(elements); | 4406 push(elements); |
4407 lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 4407 lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
4408 LoadRoot(at, Heap::kFixedArrayMapRootIndex); | 4408 LoadRoot(at, Heap::kFixedArrayMapRootIndex); |
4409 Branch(&ok, eq, elements, Operand(at)); | 4409 Branch(&ok, eq, elements, Operand(at)); |
4410 LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); | 4410 LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); |
4411 Branch(&ok, eq, elements, Operand(at)); | 4411 Branch(&ok, eq, elements, Operand(at)); |
4412 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); | 4412 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); |
4413 Branch(&ok, eq, elements, Operand(at)); | 4413 Branch(&ok, eq, elements, Operand(at)); |
4414 Abort(kJSObjectWithFastElementsMapHasSlowElements); | 4414 Abort("JSObject with fast elements map has slow elements"); |
4415 bind(&ok); | 4415 bind(&ok); |
4416 pop(elements); | 4416 pop(elements); |
4417 } | 4417 } |
4418 } | 4418 } |
4419 | 4419 |
4420 | 4420 |
4421 void MacroAssembler::Check(Condition cc, BailoutReason reason, | 4421 void MacroAssembler::Check(Condition cc, const char* msg, |
4422 Register rs, Operand rt) { | 4422 Register rs, Operand rt) { |
4423 Label L; | 4423 Label L; |
4424 Branch(&L, cc, rs, rt); | 4424 Branch(&L, cc, rs, rt); |
4425 Abort(reason); | 4425 Abort(msg); |
4426 // Will not return here. | 4426 // Will not return here. |
4427 bind(&L); | 4427 bind(&L); |
4428 } | 4428 } |
4429 | 4429 |
4430 | 4430 |
4431 void MacroAssembler::Abort(BailoutReason reason) { | 4431 void MacroAssembler::Abort(const char* msg) { |
4432 Label abort_start; | 4432 Label abort_start; |
4433 bind(&abort_start); | 4433 bind(&abort_start); |
4434 // We want to pass the msg string like a smi to avoid GC | 4434 // We want to pass the msg string like a smi to avoid GC |
4435 // problems, however msg is not guaranteed to be aligned | 4435 // problems, however msg is not guaranteed to be aligned |
4436 // properly. Instead, we pass an aligned pointer that is | 4436 // properly. Instead, we pass an aligned pointer that is |
4437 // a proper v8 smi, but also pass the alignment difference | 4437 // a proper v8 smi, but also pass the alignment difference |
4438 // from the real pointer as a smi. | 4438 // from the real pointer as a smi. |
4439 const char* msg = GetBailoutReason(reason); | |
4440 intptr_t p1 = reinterpret_cast<intptr_t>(msg); | 4439 intptr_t p1 = reinterpret_cast<intptr_t>(msg); |
4441 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; | 4440 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; |
4442 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); | 4441 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); |
4443 #ifdef DEBUG | 4442 #ifdef DEBUG |
4444 if (msg != NULL) { | 4443 if (msg != NULL) { |
4445 RecordComment("Abort message: "); | 4444 RecordComment("Abort message: "); |
4446 RecordComment(msg); | 4445 RecordComment(msg); |
4447 } | 4446 } |
4448 #endif | 4447 #endif |
4449 | 4448 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4573 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 4572 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
4574 Register map, | 4573 Register map, |
4575 Register scratch) { | 4574 Register scratch) { |
4576 // Load the initial map. The global functions all have initial maps. | 4575 // Load the initial map. The global functions all have initial maps. |
4577 lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 4576 lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
4578 if (emit_debug_code()) { | 4577 if (emit_debug_code()) { |
4579 Label ok, fail; | 4578 Label ok, fail; |
4580 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); | 4579 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); |
4581 Branch(&ok); | 4580 Branch(&ok); |
4582 bind(&fail); | 4581 bind(&fail); |
4583 Abort(kGlobalFunctionsMustHaveInitialMap); | 4582 Abort("Global functions must have initial map"); |
4584 bind(&ok); | 4583 bind(&ok); |
4585 } | 4584 } |
4586 } | 4585 } |
4587 | 4586 |
4588 | 4587 |
4589 void MacroAssembler::EnterFrame(StackFrame::Type type) { | 4588 void MacroAssembler::EnterFrame(StackFrame::Type type) { |
4590 addiu(sp, sp, -5 * kPointerSize); | 4589 addiu(sp, sp, -5 * kPointerSize); |
4591 li(t8, Operand(Smi::FromInt(type))); | 4590 li(t8, Operand(Smi::FromInt(type))); |
4592 li(t9, Operand(CodeObject()), CONSTANT_SIZE); | 4591 li(t9, Operand(CodeObject()), CONSTANT_SIZE); |
4593 sw(ra, MemOperand(sp, 4 * kPointerSize)); | 4592 sw(ra, MemOperand(sp, 4 * kPointerSize)); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4856 // Both Smi tags must be 1 (not Smi). | 4855 // Both Smi tags must be 1 (not Smi). |
4857 and_(at, reg1, reg2); | 4856 and_(at, reg1, reg2); |
4858 JumpIfSmi(at, on_either_smi); | 4857 JumpIfSmi(at, on_either_smi); |
4859 } | 4858 } |
4860 | 4859 |
4861 | 4860 |
4862 void MacroAssembler::AssertNotSmi(Register object) { | 4861 void MacroAssembler::AssertNotSmi(Register object) { |
4863 if (emit_debug_code()) { | 4862 if (emit_debug_code()) { |
4864 STATIC_ASSERT(kSmiTag == 0); | 4863 STATIC_ASSERT(kSmiTag == 0); |
4865 andi(at, object, kSmiTagMask); | 4864 andi(at, object, kSmiTagMask); |
4866 Check(ne, kOperandIsASmi, at, Operand(zero_reg)); | 4865 Check(ne, "Operand is a smi", at, Operand(zero_reg)); |
4867 } | 4866 } |
4868 } | 4867 } |
4869 | 4868 |
4870 | 4869 |
4871 void MacroAssembler::AssertSmi(Register object) { | 4870 void MacroAssembler::AssertSmi(Register object) { |
4872 if (emit_debug_code()) { | 4871 if (emit_debug_code()) { |
4873 STATIC_ASSERT(kSmiTag == 0); | 4872 STATIC_ASSERT(kSmiTag == 0); |
4874 andi(at, object, kSmiTagMask); | 4873 andi(at, object, kSmiTagMask); |
4875 Check(eq, kOperandIsASmi, at, Operand(zero_reg)); | 4874 Check(eq, "Operand is a smi", at, Operand(zero_reg)); |
4876 } | 4875 } |
4877 } | 4876 } |
4878 | 4877 |
4879 | 4878 |
4880 void MacroAssembler::AssertString(Register object) { | 4879 void MacroAssembler::AssertString(Register object) { |
4881 if (emit_debug_code()) { | 4880 if (emit_debug_code()) { |
4882 STATIC_ASSERT(kSmiTag == 0); | 4881 STATIC_ASSERT(kSmiTag == 0); |
4883 And(t0, object, Operand(kSmiTagMask)); | 4882 And(t0, object, Operand(kSmiTagMask)); |
4884 Check(ne, kOperandIsASmiAndNotAString, t0, Operand(zero_reg)); | 4883 Check(ne, "Operand is a smi and not a string", t0, Operand(zero_reg)); |
4885 push(object); | 4884 push(object); |
4886 lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 4885 lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
4887 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); | 4886 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); |
4888 Check(lo, kOperandIsNotAString, object, Operand(FIRST_NONSTRING_TYPE)); | 4887 Check(lo, "Operand is not a string", object, Operand(FIRST_NONSTRING_TYPE)); |
4889 pop(object); | 4888 pop(object); |
4890 } | 4889 } |
4891 } | 4890 } |
4892 | 4891 |
4893 | 4892 |
4894 void MacroAssembler::AssertName(Register object) { | 4893 void MacroAssembler::AssertName(Register object) { |
4895 if (emit_debug_code()) { | 4894 if (emit_debug_code()) { |
4896 STATIC_ASSERT(kSmiTag == 0); | 4895 STATIC_ASSERT(kSmiTag == 0); |
4897 And(t0, object, Operand(kSmiTagMask)); | 4896 And(t0, object, Operand(kSmiTagMask)); |
4898 Check(ne, kOperandIsASmiAndNotAName, t0, Operand(zero_reg)); | 4897 Check(ne, "Operand is a smi and not a name", t0, Operand(zero_reg)); |
4899 push(object); | 4898 push(object); |
4900 lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 4899 lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
4901 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); | 4900 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); |
4902 Check(le, kOperandIsNotAName, object, Operand(LAST_NAME_TYPE)); | 4901 Check(le, "Operand is not a name", object, Operand(LAST_NAME_TYPE)); |
4903 pop(object); | 4902 pop(object); |
4904 } | 4903 } |
4905 } | 4904 } |
4906 | 4905 |
4907 | 4906 |
4908 void MacroAssembler::AssertRootValue(Register src, | 4907 void MacroAssembler::AssertRootValue(Register src, |
4909 Heap::RootListIndex root_value_index, | 4908 Heap::RootListIndex root_value_index, |
4910 BailoutReason reason) { | 4909 const char* message) { |
4911 if (emit_debug_code()) { | 4910 if (emit_debug_code()) { |
4912 ASSERT(!src.is(at)); | 4911 ASSERT(!src.is(at)); |
4913 LoadRoot(at, root_value_index); | 4912 LoadRoot(at, root_value_index); |
4914 Check(eq, reason, src, Operand(at)); | 4913 Check(eq, message, src, Operand(at)); |
4915 } | 4914 } |
4916 } | 4915 } |
4917 | 4916 |
4918 | 4917 |
4919 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 4918 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
4920 Register heap_number_map, | 4919 Register heap_number_map, |
4921 Register scratch, | 4920 Register scratch, |
4922 Label* on_not_heap_number) { | 4921 Label* on_not_heap_number) { |
4923 lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 4922 lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
4924 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 4923 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5121 #undef BRANCH_ARGS_CHECK | 5120 #undef BRANCH_ARGS_CHECK |
5122 | 5121 |
5123 | 5122 |
5124 void MacroAssembler::PatchRelocatedValue(Register li_location, | 5123 void MacroAssembler::PatchRelocatedValue(Register li_location, |
5125 Register scratch, | 5124 Register scratch, |
5126 Register new_value) { | 5125 Register new_value) { |
5127 lw(scratch, MemOperand(li_location)); | 5126 lw(scratch, MemOperand(li_location)); |
5128 // At this point scratch is a lui(at, ...) instruction. | 5127 // At this point scratch is a lui(at, ...) instruction. |
5129 if (emit_debug_code()) { | 5128 if (emit_debug_code()) { |
5130 And(scratch, scratch, kOpcodeMask); | 5129 And(scratch, scratch, kOpcodeMask); |
5131 Check(eq, kTheInstructionToPatchShouldBeALui, | 5130 Check(eq, "The instruction to patch should be a lui.", |
5132 scratch, Operand(LUI)); | 5131 scratch, Operand(LUI)); |
5133 lw(scratch, MemOperand(li_location)); | 5132 lw(scratch, MemOperand(li_location)); |
5134 } | 5133 } |
5135 srl(t9, new_value, kImm16Bits); | 5134 srl(t9, new_value, kImm16Bits); |
5136 Ins(scratch, t9, 0, kImm16Bits); | 5135 Ins(scratch, t9, 0, kImm16Bits); |
5137 sw(scratch, MemOperand(li_location)); | 5136 sw(scratch, MemOperand(li_location)); |
5138 | 5137 |
5139 lw(scratch, MemOperand(li_location, kInstrSize)); | 5138 lw(scratch, MemOperand(li_location, kInstrSize)); |
5140 // scratch is now ori(at, ...). | 5139 // scratch is now ori(at, ...). |
5141 if (emit_debug_code()) { | 5140 if (emit_debug_code()) { |
5142 And(scratch, scratch, kOpcodeMask); | 5141 And(scratch, scratch, kOpcodeMask); |
5143 Check(eq, kTheInstructionToPatchShouldBeAnOri, | 5142 Check(eq, "The instruction to patch should be an ori.", |
5144 scratch, Operand(ORI)); | 5143 scratch, Operand(ORI)); |
5145 lw(scratch, MemOperand(li_location, kInstrSize)); | 5144 lw(scratch, MemOperand(li_location, kInstrSize)); |
5146 } | 5145 } |
5147 Ins(scratch, new_value, 0, kImm16Bits); | 5146 Ins(scratch, new_value, 0, kImm16Bits); |
5148 sw(scratch, MemOperand(li_location, kInstrSize)); | 5147 sw(scratch, MemOperand(li_location, kInstrSize)); |
5149 | 5148 |
5150 // Update the I-cache so the new lui and ori can be executed. | 5149 // Update the I-cache so the new lui and ori can be executed. |
5151 FlushICache(li_location, 2); | 5150 FlushICache(li_location, 2); |
5152 } | 5151 } |
5153 | 5152 |
5154 void MacroAssembler::GetRelocatedValue(Register li_location, | 5153 void MacroAssembler::GetRelocatedValue(Register li_location, |
5155 Register value, | 5154 Register value, |
5156 Register scratch) { | 5155 Register scratch) { |
5157 lw(value, MemOperand(li_location)); | 5156 lw(value, MemOperand(li_location)); |
5158 if (emit_debug_code()) { | 5157 if (emit_debug_code()) { |
5159 And(value, value, kOpcodeMask); | 5158 And(value, value, kOpcodeMask); |
5160 Check(eq, kTheInstructionShouldBeALui, | 5159 Check(eq, "The instruction should be a lui.", |
5161 value, Operand(LUI)); | 5160 value, Operand(LUI)); |
5162 lw(value, MemOperand(li_location)); | 5161 lw(value, MemOperand(li_location)); |
5163 } | 5162 } |
5164 | 5163 |
5165 // value now holds a lui instruction. Extract the immediate. | 5164 // value now holds a lui instruction. Extract the immediate. |
5166 sll(value, value, kImm16Bits); | 5165 sll(value, value, kImm16Bits); |
5167 | 5166 |
5168 lw(scratch, MemOperand(li_location, kInstrSize)); | 5167 lw(scratch, MemOperand(li_location, kInstrSize)); |
5169 if (emit_debug_code()) { | 5168 if (emit_debug_code()) { |
5170 And(scratch, scratch, kOpcodeMask); | 5169 And(scratch, scratch, kOpcodeMask); |
5171 Check(eq, kTheInstructionShouldBeAnOri, | 5170 Check(eq, "The instruction should be an ori.", |
5172 scratch, Operand(ORI)); | 5171 scratch, Operand(ORI)); |
5173 lw(scratch, MemOperand(li_location, kInstrSize)); | 5172 lw(scratch, MemOperand(li_location, kInstrSize)); |
5174 } | 5173 } |
5175 // "scratch" now holds an ori instruction. Extract the immediate. | 5174 // "scratch" now holds an ori instruction. Extract the immediate. |
5176 andi(scratch, scratch, kImm16Mask); | 5175 andi(scratch, scratch, kImm16Mask); |
5177 | 5176 |
5178 // Merge the results. | 5177 // Merge the results. |
5179 or_(value, value, scratch); | 5178 or_(value, value, scratch); |
5180 } | 5179 } |
5181 | 5180 |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5569 opcode == BGTZL); | 5568 opcode == BGTZL); |
5570 opcode = (cond == eq) ? BEQ : BNE; | 5569 opcode = (cond == eq) ? BEQ : BNE; |
5571 instr = (instr & ~kOpcodeMask) | opcode; | 5570 instr = (instr & ~kOpcodeMask) | opcode; |
5572 masm_.emit(instr); | 5571 masm_.emit(instr); |
5573 } | 5572 } |
5574 | 5573 |
5575 | 5574 |
5576 } } // namespace v8::internal | 5575 } } // namespace v8::internal |
5577 | 5576 |
5578 #endif // V8_TARGET_ARCH_MIPS | 5577 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |