| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 __ mov(ip, Operand(argc)); | 652 __ mov(ip, Operand(argc)); |
| 653 __ str(ip, MemOperand(r0, 2 * kPointerSize)); | 653 __ str(ip, MemOperand(r0, 2 * kPointerSize)); |
| 654 // v8::Arguments::is_construct_call = 0 | 654 // v8::Arguments::is_construct_call = 0 |
| 655 __ mov(ip, Operand(0)); | 655 __ mov(ip, Operand(0)); |
| 656 __ str(ip, MemOperand(r0, 3 * kPointerSize)); | 656 __ str(ip, MemOperand(r0, 3 * kPointerSize)); |
| 657 | 657 |
| 658 // Emitting a stub call may try to allocate (if the code is not | 658 // Emitting a stub call may try to allocate (if the code is not |
| 659 // already generated). Do not allow the assembler to perform a | 659 // already generated). Do not allow the assembler to perform a |
| 660 // garbage collection but instead return the allocation failure | 660 // garbage collection but instead return the allocation failure |
| 661 // object. | 661 // object. |
| 662 MaybeObject* result = masm->TryCallApiFunctionAndReturn( | 662 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1; |
| 663 &fun, argc + kFastApiCallArguments + 1); | 663 ExternalReference ref = |
| 664 if (result->IsFailure()) { | 664 ExternalReference(&fun, ExternalReference::DIRECT_API_CALL); |
| 665 return result; | 665 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); |
| 666 } | |
| 667 return Heap::undefined_value(); | |
| 668 } | 666 } |
| 669 | 667 |
| 670 class CallInterceptorCompiler BASE_EMBEDDED { | 668 class CallInterceptorCompiler BASE_EMBEDDED { |
| 671 public: | 669 public: |
| 672 CallInterceptorCompiler(StubCompiler* stub_compiler, | 670 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 673 const ParameterCount& arguments, | 671 const ParameterCount& arguments, |
| 674 Register name) | 672 Register name) |
| 675 : stub_compiler_(stub_compiler), | 673 : stub_compiler_(stub_compiler), |
| 676 arguments_(arguments), | 674 arguments_(arguments), |
| 677 name_(name) {} | 675 name_(name) {} |
| (...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1242 Label* miss) { | 1240 Label* miss) { |
| 1243 // Check that the receiver isn't a smi. | 1241 // Check that the receiver isn't a smi. |
| 1244 __ tst(receiver, Operand(kSmiTagMask)); | 1242 __ tst(receiver, Operand(kSmiTagMask)); |
| 1245 __ b(eq, miss); | 1243 __ b(eq, miss); |
| 1246 | 1244 |
| 1247 // Check that the maps haven't changed. | 1245 // Check that the maps haven't changed. |
| 1248 Register reg = | 1246 Register reg = |
| 1249 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, | 1247 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, |
| 1250 name, miss); | 1248 name, miss); |
| 1251 | 1249 |
| 1252 // Push the arguments on the JS stack of the caller. | 1250 // Build AccessorInfo::args_ list on the stack and push property name below |
| 1253 __ push(receiver); // Receiver. | 1251 // the exit frame to make GC aware of them and store pointers to them. |
| 1254 __ mov(scratch3, Operand(Handle<AccessorInfo>(callback))); // callback data | 1252 __ push(receiver); |
| 1255 __ ldr(ip, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); | 1253 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_ |
| 1256 __ Push(reg, ip, scratch3, name_reg); | 1254 Handle<AccessorInfo> callback_handle(callback); |
| 1255 if (Heap::InNewSpace(callback_handle->data())) { |
| 1256 __ Move(scratch3, callback_handle); |
| 1257 __ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); |
| 1258 } else { |
| 1259 __ Move(scratch3, Handle<Object>(callback_handle->data())); |
| 1260 } |
| 1261 __ Push(reg, scratch3, name_reg); |
| 1262 __ mov(r0, sp); // r0 = Handle<String> |
| 1257 | 1263 |
| 1258 // Do tail-call to the runtime system. | 1264 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1259 ExternalReference load_callback_property = | 1265 ApiFunction fun(getter_address); |
| 1260 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | |
| 1261 __ TailCallExternalReference(load_callback_property, 5, 1); | |
| 1262 | 1266 |
| 1263 return Heap::undefined_value(); // Success. | 1267 const int kApiStackSpace = 1; |
| 1268 __ EnterExitFrame(false, kApiStackSpace); |
| 1269 // Create AccessorInfo instance on the stack above the exit frame with |
| 1270 // scratch2 (internal::Object **args_) as the data. |
| 1271 __ str(scratch2, MemOperand(sp, 1 * kPointerSize)); |
| 1272 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& |
| 1273 |
| 1274 // Emitting a stub call may try to allocate (if the code is not |
| 1275 // already generated). Do not allow the assembler to perform a |
| 1276 // garbage collection but instead return the allocation failure |
| 1277 // object. |
| 1278 const int kStackUnwindSpace = 4; |
| 1279 ExternalReference ref = |
| 1280 ExternalReference(&fun, ExternalReference::DIRECT_GETTER_CALL); |
| 1281 return masm()->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); |
| 1264 } | 1282 } |
| 1265 | 1283 |
| 1266 | 1284 |
| 1267 void StubCompiler::GenerateLoadInterceptor(JSObject* object, | 1285 void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
| 1268 JSObject* interceptor_holder, | 1286 JSObject* interceptor_holder, |
| 1269 LookupResult* lookup, | 1287 LookupResult* lookup, |
| 1270 Register receiver, | 1288 Register receiver, |
| 1271 Register name_reg, | 1289 Register name_reg, |
| 1272 Register scratch1, | 1290 Register scratch1, |
| 1273 Register scratch2, | 1291 Register scratch2, |
| (...skipping 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2336 // Patch the receiver on the stack with the global proxy if | 2354 // Patch the receiver on the stack with the global proxy if |
| 2337 // necessary. | 2355 // necessary. |
| 2338 if (object->IsGlobalObject()) { | 2356 if (object->IsGlobalObject()) { |
| 2339 ASSERT(depth == kInvalidProtoDepth); | 2357 ASSERT(depth == kInvalidProtoDepth); |
| 2340 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 2358 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
| 2341 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 2359 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
| 2342 } | 2360 } |
| 2343 break; | 2361 break; |
| 2344 | 2362 |
| 2345 case STRING_CHECK: | 2363 case STRING_CHECK: |
| 2346 if (!function->IsBuiltin()) { | 2364 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2347 // Calling non-builtins with a value as receiver requires boxing. | 2365 // Calling non-strict non-builtins with a value as the receiver |
| 2366 // requires boxing. |
| 2348 __ jmp(&miss); | 2367 __ jmp(&miss); |
| 2349 } else { | 2368 } else { |
| 2350 // Check that the object is a two-byte string or a symbol. | 2369 // Check that the object is a two-byte string or a symbol. |
| 2351 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); | 2370 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); |
| 2352 __ b(hs, &miss); | 2371 __ b(hs, &miss); |
| 2353 // Check that the maps starting from the prototype haven't changed. | 2372 // Check that the maps starting from the prototype haven't changed. |
| 2354 GenerateDirectLoadGlobalFunctionPrototype( | 2373 GenerateDirectLoadGlobalFunctionPrototype( |
| 2355 masm(), Context::STRING_FUNCTION_INDEX, r0, &miss); | 2374 masm(), Context::STRING_FUNCTION_INDEX, r0, &miss); |
| 2356 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, | 2375 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
| 2357 r1, r4, name, &miss); | 2376 r1, r4, name, &miss); |
| 2358 } | 2377 } |
| 2359 break; | 2378 break; |
| 2360 | 2379 |
| 2361 case NUMBER_CHECK: { | 2380 case NUMBER_CHECK: { |
| 2362 if (!function->IsBuiltin()) { | 2381 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2363 // Calling non-builtins with a value as receiver requires boxing. | 2382 // Calling non-strict non-builtins with a value as the receiver |
| 2383 // requires boxing. |
| 2364 __ jmp(&miss); | 2384 __ jmp(&miss); |
| 2365 } else { | 2385 } else { |
| 2366 Label fast; | 2386 Label fast; |
| 2367 // Check that the object is a smi or a heap number. | 2387 // Check that the object is a smi or a heap number. |
| 2368 __ tst(r1, Operand(kSmiTagMask)); | 2388 __ tst(r1, Operand(kSmiTagMask)); |
| 2369 __ b(eq, &fast); | 2389 __ b(eq, &fast); |
| 2370 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); | 2390 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); |
| 2371 __ b(ne, &miss); | 2391 __ b(ne, &miss); |
| 2372 __ bind(&fast); | 2392 __ bind(&fast); |
| 2373 // Check that the maps starting from the prototype haven't changed. | 2393 // Check that the maps starting from the prototype haven't changed. |
| 2374 GenerateDirectLoadGlobalFunctionPrototype( | 2394 GenerateDirectLoadGlobalFunctionPrototype( |
| 2375 masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss); | 2395 masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss); |
| 2376 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, | 2396 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
| 2377 r1, r4, name, &miss); | 2397 r1, r4, name, &miss); |
| 2378 } | 2398 } |
| 2379 break; | 2399 break; |
| 2380 } | 2400 } |
| 2381 | 2401 |
| 2382 case BOOLEAN_CHECK: { | 2402 case BOOLEAN_CHECK: { |
| 2383 if (!function->IsBuiltin()) { | 2403 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2384 // Calling non-builtins with a value as receiver requires boxing. | 2404 // Calling non-strict non-builtins with a value as the receiver |
| 2405 // requires boxing. |
| 2385 __ jmp(&miss); | 2406 __ jmp(&miss); |
| 2386 } else { | 2407 } else { |
| 2387 Label fast; | 2408 Label fast; |
| 2388 // Check that the object is a boolean. | 2409 // Check that the object is a boolean. |
| 2389 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 2410 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 2390 __ cmp(r1, ip); | 2411 __ cmp(r1, ip); |
| 2391 __ b(eq, &fast); | 2412 __ b(eq, &fast); |
| 2392 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 2413 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 2393 __ cmp(r1, ip); | 2414 __ cmp(r1, ip); |
| 2394 __ b(ne, &miss); | 2415 __ b(ne, &miss); |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2654 if (receiver->IsJSGlobalProxy()) { | 2675 if (receiver->IsJSGlobalProxy()) { |
| 2655 __ CheckAccessGlobalProxy(r1, r3, &miss); | 2676 __ CheckAccessGlobalProxy(r1, r3, &miss); |
| 2656 } | 2677 } |
| 2657 | 2678 |
| 2658 // Stub is never generated for non-global objects that require access | 2679 // Stub is never generated for non-global objects that require access |
| 2659 // checks. | 2680 // checks. |
| 2660 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); | 2681 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); |
| 2661 | 2682 |
| 2662 __ Push(r1, r2, r0); // Receiver, name, value. | 2683 __ Push(r1, r2, r0); // Receiver, name, value. |
| 2663 | 2684 |
| 2685 __ mov(r0, Operand(Smi::FromInt(strict_mode_))); |
| 2686 __ push(r0); // strict mode |
| 2687 |
| 2664 // Do tail-call to the runtime system. | 2688 // Do tail-call to the runtime system. |
| 2665 ExternalReference store_ic_property = | 2689 ExternalReference store_ic_property = |
| 2666 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); | 2690 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); |
| 2667 __ TailCallExternalReference(store_ic_property, 3, 1); | 2691 __ TailCallExternalReference(store_ic_property, 4, 1); |
| 2668 | 2692 |
| 2669 // Handle store cache miss. | 2693 // Handle store cache miss. |
| 2670 __ bind(&miss); | 2694 __ bind(&miss); |
| 2671 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2695 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 2672 __ Jump(ic, RelocInfo::CODE_TARGET); | 2696 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 2673 | 2697 |
| 2674 // Return the generated code. | 2698 // Return the generated code. |
| 2675 return GetCode(INTERCEPTOR, name); | 2699 return GetCode(INTERCEPTOR, name); |
| 2676 } | 2700 } |
| 2677 | 2701 |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3123 __ Ret(); | 3147 __ Ret(); |
| 3124 | 3148 |
| 3125 __ bind(&miss); | 3149 __ bind(&miss); |
| 3126 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3150 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3127 | 3151 |
| 3128 // Return the generated code. | 3152 // Return the generated code. |
| 3129 return GetCode(NORMAL, NULL); | 3153 return GetCode(NORMAL, NULL); |
| 3130 } | 3154 } |
| 3131 | 3155 |
| 3132 | 3156 |
| 3133 MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) { | |
| 3134 // ----------- S t a t e ------------- | |
| 3135 // -- lr : return address | |
| 3136 // -- r0 : key | |
| 3137 // -- r1 : receiver | |
| 3138 // ----------------------------------- | |
| 3139 Label miss; | |
| 3140 | |
| 3141 // Check that the map matches. | |
| 3142 __ CheckMap(r1, r2, Handle<Map>(receiver->map()), &miss, false); | |
| 3143 | |
| 3144 GenerateFastPixelArrayLoad(masm(), | |
| 3145 r1, | |
| 3146 r0, | |
| 3147 r2, | |
| 3148 r3, | |
| 3149 r4, | |
| 3150 r5, | |
| 3151 r0, | |
| 3152 &miss, | |
| 3153 &miss, | |
| 3154 &miss); | |
| 3155 | |
| 3156 __ bind(&miss); | |
| 3157 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Miss)); | |
| 3158 __ Jump(ic, RelocInfo::CODE_TARGET); | |
| 3159 | |
| 3160 // Return the generated code. | |
| 3161 return GetCode(NORMAL, NULL); | |
| 3162 } | |
| 3163 | |
| 3164 | |
| 3165 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, | 3157 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, |
| 3166 int index, | 3158 int index, |
| 3167 Map* transition, | 3159 Map* transition, |
| 3168 String* name) { | 3160 String* name) { |
| 3169 // ----------- S t a t e ------------- | 3161 // ----------- S t a t e ------------- |
| 3170 // -- r0 : value | 3162 // -- r0 : value |
| 3171 // -- r1 : name | 3163 // -- r1 : name |
| 3172 // -- r2 : receiver | 3164 // -- r2 : receiver |
| 3173 // -- lr : return address | 3165 // -- lr : return address |
| 3174 // ----------------------------------- | 3166 // ----------------------------------- |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3265 | 3257 |
| 3266 __ bind(&miss); | 3258 __ bind(&miss); |
| 3267 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 3259 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 3268 __ Jump(ic, RelocInfo::CODE_TARGET); | 3260 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 3269 | 3261 |
| 3270 // Return the generated code. | 3262 // Return the generated code. |
| 3271 return GetCode(NORMAL, NULL); | 3263 return GetCode(NORMAL, NULL); |
| 3272 } | 3264 } |
| 3273 | 3265 |
| 3274 | 3266 |
| 3275 MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray( | |
| 3276 JSObject* receiver) { | |
| 3277 // ----------- S t a t e ------------- | |
| 3278 // -- r0 : value | |
| 3279 // -- r1 : key | |
| 3280 // -- r2 : receiver | |
| 3281 // -- r3 : scratch | |
| 3282 // -- r4 : scratch | |
| 3283 // -- r5 : scratch | |
| 3284 // -- r6 : scratch | |
| 3285 // -- lr : return address | |
| 3286 // ----------------------------------- | |
| 3287 Label miss; | |
| 3288 | |
| 3289 // Check that the map matches. | |
| 3290 __ CheckMap(r2, r6, Handle<Map>(receiver->map()), &miss, false); | |
| 3291 | |
| 3292 GenerateFastPixelArrayStore(masm(), | |
| 3293 r2, | |
| 3294 r1, | |
| 3295 r0, | |
| 3296 r3, | |
| 3297 r4, | |
| 3298 r5, | |
| 3299 r6, | |
| 3300 true, | |
| 3301 true, | |
| 3302 &miss, | |
| 3303 &miss, | |
| 3304 NULL, | |
| 3305 &miss); | |
| 3306 | |
| 3307 __ bind(&miss); | |
| 3308 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | |
| 3309 __ Jump(ic, RelocInfo::CODE_TARGET); | |
| 3310 | |
| 3311 // Return the generated code. | |
| 3312 return GetCode(NORMAL, NULL); | |
| 3313 } | |
| 3314 | |
| 3315 | |
| 3316 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3267 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3317 // ----------- S t a t e ------------- | 3268 // ----------- S t a t e ------------- |
| 3318 // -- r0 : argc | 3269 // -- r0 : argc |
| 3319 // -- r1 : constructor | 3270 // -- r1 : constructor |
| 3320 // -- lr : return address | 3271 // -- lr : return address |
| 3321 // -- [sp] : last argument | 3272 // -- [sp] : last argument |
| 3322 // ----------------------------------- | 3273 // ----------------------------------- |
| 3323 Label generic_stub_call; | 3274 Label generic_stub_call; |
| 3324 | 3275 |
| 3325 // Use r7 for holding undefined which is used in several places below. | 3276 // Use r7 for holding undefined which is used in several places below. |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3470 return false; | 3421 return false; |
| 3471 | 3422 |
| 3472 default: | 3423 default: |
| 3473 UNREACHABLE(); | 3424 UNREACHABLE(); |
| 3474 return false; | 3425 return false; |
| 3475 } | 3426 } |
| 3476 } | 3427 } |
| 3477 | 3428 |
| 3478 | 3429 |
| 3479 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3430 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3480 ExternalArrayType array_type, Code::Flags flags) { | 3431 JSObject* receiver_object, |
| 3432 ExternalArrayType array_type, |
| 3433 Code::Flags flags) { |
| 3481 // ---------- S t a t e -------------- | 3434 // ---------- S t a t e -------------- |
| 3482 // -- lr : return address | 3435 // -- lr : return address |
| 3483 // -- r0 : key | 3436 // -- r0 : key |
| 3484 // -- r1 : receiver | 3437 // -- r1 : receiver |
| 3485 // ----------------------------------- | 3438 // ----------------------------------- |
| 3486 Label slow, failed_allocation; | 3439 Label slow, failed_allocation; |
| 3487 | 3440 |
| 3488 Register key = r0; | 3441 Register key = r0; |
| 3489 Register receiver = r1; | 3442 Register receiver = r1; |
| 3490 | 3443 |
| 3491 // Check that the object isn't a smi | 3444 // Check that the object isn't a smi |
| 3492 __ JumpIfSmi(receiver, &slow); | 3445 __ JumpIfSmi(receiver, &slow); |
| 3493 | 3446 |
| 3494 // Check that the key is a smi. | 3447 // Check that the key is a smi. |
| 3495 __ JumpIfNotSmi(key, &slow); | 3448 __ JumpIfNotSmi(key, &slow); |
| 3496 | 3449 |
| 3497 // Check that the object is a JS object. Load map into r2. | 3450 // Make sure that we've got the right map. |
| 3498 __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE); | 3451 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 3499 __ b(lt, &slow); | 3452 __ cmp(r2, Operand(Handle<Map>(receiver_object->map()))); |
| 3500 | |
| 3501 // Check that the receiver does not require access checks. We need | |
| 3502 // to check this explicitly since this generic stub does not perform | |
| 3503 // map checks. | |
| 3504 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); | |
| 3505 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); | |
| 3506 __ b(ne, &slow); | 3453 __ b(ne, &slow); |
| 3507 | 3454 |
| 3508 // Check that the elements array is the appropriate type of | |
| 3509 // ExternalArray. | |
| 3510 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 3455 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 3511 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3456 // r3: elements array |
| 3512 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type)); | |
| 3513 __ cmp(r2, ip); | |
| 3514 __ b(ne, &slow); | |
| 3515 | 3457 |
| 3516 // Check that the index is in range. | 3458 // Check that the index is in range. |
| 3517 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); | 3459 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); |
| 3518 __ cmp(ip, Operand(key, ASR, kSmiTagSize)); | 3460 __ cmp(ip, Operand(key, ASR, kSmiTagSize)); |
| 3519 // Unsigned comparison catches both negative and too-large values. | 3461 // Unsigned comparison catches both negative and too-large values. |
| 3520 __ b(lo, &slow); | 3462 __ b(lo, &slow); |
| 3521 | 3463 |
| 3522 // r3: elements array | |
| 3523 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); | 3464 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
| 3524 // r3: base pointer of external storage | 3465 // r3: base pointer of external storage |
| 3525 | 3466 |
| 3526 // We are not untagging smi key and instead work with it | 3467 // We are not untagging smi key and instead work with it |
| 3527 // as if it was premultiplied by 2. | 3468 // as if it was premultiplied by 2. |
| 3528 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); | 3469 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); |
| 3529 | 3470 |
| 3530 Register value = r2; | 3471 Register value = r2; |
| 3531 switch (array_type) { | 3472 switch (array_type) { |
| 3532 case kExternalByteArray: | 3473 case kExternalByteArray: |
| 3533 __ ldrsb(value, MemOperand(r3, key, LSR, 1)); | 3474 __ ldrsb(value, MemOperand(r3, key, LSR, 1)); |
| 3534 break; | 3475 break; |
| 3476 case kExternalPixelArray: |
| 3535 case kExternalUnsignedByteArray: | 3477 case kExternalUnsignedByteArray: |
| 3536 __ ldrb(value, MemOperand(r3, key, LSR, 1)); | 3478 __ ldrb(value, MemOperand(r3, key, LSR, 1)); |
| 3537 break; | 3479 break; |
| 3538 case kExternalShortArray: | 3480 case kExternalShortArray: |
| 3539 __ ldrsh(value, MemOperand(r3, key, LSL, 0)); | 3481 __ ldrsh(value, MemOperand(r3, key, LSL, 0)); |
| 3540 break; | 3482 break; |
| 3541 case kExternalUnsignedShortArray: | 3483 case kExternalUnsignedShortArray: |
| 3542 __ ldrh(value, MemOperand(r3, key, LSL, 0)); | 3484 __ ldrh(value, MemOperand(r3, key, LSL, 0)); |
| 3543 break; | 3485 break; |
| 3544 case kExternalIntArray: | 3486 case kExternalIntArray: |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3750 | 3692 |
| 3751 __ Push(r1, r0); | 3693 __ Push(r1, r0); |
| 3752 | 3694 |
| 3753 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 3695 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3754 | 3696 |
| 3755 return GetCode(flags); | 3697 return GetCode(flags); |
| 3756 } | 3698 } |
| 3757 | 3699 |
| 3758 | 3700 |
| 3759 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | 3701 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( |
| 3760 ExternalArrayType array_type, Code::Flags flags) { | 3702 JSObject* receiver_object, |
| 3703 ExternalArrayType array_type, |
| 3704 Code::Flags flags) { |
| 3761 // ---------- S t a t e -------------- | 3705 // ---------- S t a t e -------------- |
| 3762 // -- r0 : value | 3706 // -- r0 : value |
| 3763 // -- r1 : key | 3707 // -- r1 : key |
| 3764 // -- r2 : receiver | 3708 // -- r2 : receiver |
| 3765 // -- lr : return address | 3709 // -- lr : return address |
| 3766 // ----------------------------------- | 3710 // ----------------------------------- |
| 3767 Label slow, check_heap_number; | 3711 Label slow, check_heap_number; |
| 3768 | 3712 |
| 3769 // Register usage. | 3713 // Register usage. |
| 3770 Register value = r0; | 3714 Register value = r0; |
| 3771 Register key = r1; | 3715 Register key = r1; |
| 3772 Register receiver = r2; | 3716 Register receiver = r2; |
| 3773 // r3 mostly holds the elements array or the destination external array. | 3717 // r3 mostly holds the elements array or the destination external array. |
| 3774 | 3718 |
| 3775 // Check that the object isn't a smi. | 3719 // Check that the object isn't a smi. |
| 3776 __ JumpIfSmi(receiver, &slow); | 3720 __ JumpIfSmi(receiver, &slow); |
| 3777 | 3721 |
| 3778 // Check that the object is a JS object. Load map into r3. | 3722 // Make sure that we've got the right map. |
| 3779 __ CompareObjectType(receiver, r3, r4, FIRST_JS_OBJECT_TYPE); | 3723 __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 3780 __ b(le, &slow); | 3724 __ cmp(r3, Operand(Handle<Map>(receiver_object->map()))); |
| 3725 __ b(ne, &slow); |
| 3781 | 3726 |
| 3782 // Check that the receiver does not require access checks. We need | 3727 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 3783 // to do this because this generic stub does not perform map checks. | |
| 3784 __ ldrb(ip, FieldMemOperand(r3, Map::kBitFieldOffset)); | |
| 3785 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded)); | |
| 3786 __ b(ne, &slow); | |
| 3787 | 3728 |
| 3788 // Check that the key is a smi. | 3729 // Check that the key is a smi. |
| 3789 __ JumpIfNotSmi(key, &slow); | 3730 __ JumpIfNotSmi(key, &slow); |
| 3790 | 3731 |
| 3791 // Check that the elements array is the appropriate type of ExternalArray. | 3732 // Check that the index is in range |
| 3792 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 3733 __ SmiUntag(r4, key); |
| 3793 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); | |
| 3794 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type)); | |
| 3795 __ cmp(r4, ip); | |
| 3796 __ b(ne, &slow); | |
| 3797 | |
| 3798 // Check that the index is in range. | |
| 3799 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the index. | |
| 3800 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); | 3734 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); |
| 3801 __ cmp(r4, ip); | 3735 __ cmp(r4, ip); |
| 3802 // Unsigned comparison catches both negative and too-large values. | 3736 // Unsigned comparison catches both negative and too-large values. |
| 3803 __ b(hs, &slow); | 3737 __ b(hs, &slow); |
| 3804 | 3738 |
| 3805 // Handle both smis and HeapNumbers in the fast path. Go to the | 3739 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3806 // runtime for all other kinds of values. | 3740 // runtime for all other kinds of values. |
| 3807 // r3: external array. | 3741 // r3: external array. |
| 3808 // r4: key (integer). | 3742 // r4: key (integer). |
| 3809 __ JumpIfNotSmi(value, &check_heap_number); | 3743 if (array_type == kExternalPixelArray) { |
| 3810 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value. | 3744 // Double to pixel conversion is only implemented in the runtime for now. |
| 3745 __ JumpIfNotSmi(value, &slow); |
| 3746 } else { |
| 3747 __ JumpIfNotSmi(value, &check_heap_number); |
| 3748 } |
| 3749 __ SmiUntag(r5, value); |
| 3811 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); | 3750 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
| 3812 | 3751 |
| 3813 // r3: base pointer of external storage. | 3752 // r3: base pointer of external storage. |
| 3814 // r4: key (integer). | 3753 // r4: key (integer). |
| 3815 // r5: value (integer). | 3754 // r5: value (integer). |
| 3816 switch (array_type) { | 3755 switch (array_type) { |
| 3756 case kExternalPixelArray: |
| 3757 // Clamp the value to [0..255]. |
| 3758 __ Usat(r5, 8, Operand(r5)); |
| 3759 __ strb(r5, MemOperand(r3, r4, LSL, 0)); |
| 3760 break; |
| 3817 case kExternalByteArray: | 3761 case kExternalByteArray: |
| 3818 case kExternalUnsignedByteArray: | 3762 case kExternalUnsignedByteArray: |
| 3819 __ strb(r5, MemOperand(r3, r4, LSL, 0)); | 3763 __ strb(r5, MemOperand(r3, r4, LSL, 0)); |
| 3820 break; | 3764 break; |
| 3821 case kExternalShortArray: | 3765 case kExternalShortArray: |
| 3822 case kExternalUnsignedShortArray: | 3766 case kExternalUnsignedShortArray: |
| 3823 __ strh(r5, MemOperand(r3, r4, LSL, 1)); | 3767 __ strh(r5, MemOperand(r3, r4, LSL, 1)); |
| 3824 break; | 3768 break; |
| 3825 case kExternalIntArray: | 3769 case kExternalIntArray: |
| 3826 case kExternalUnsignedIntArray: | 3770 case kExternalUnsignedIntArray: |
| 3827 __ str(r5, MemOperand(r3, r4, LSL, 2)); | 3771 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 3828 break; | 3772 break; |
| 3829 case kExternalFloatArray: | 3773 case kExternalFloatArray: |
| 3830 // Perform int-to-float conversion and store to memory. | 3774 // Perform int-to-float conversion and store to memory. |
| 3831 StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9); | 3775 StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9); |
| 3832 break; | 3776 break; |
| 3833 default: | 3777 default: |
| 3834 UNREACHABLE(); | 3778 UNREACHABLE(); |
| 3835 break; | 3779 break; |
| 3836 } | 3780 } |
| 3837 | 3781 |
| 3838 // Entry registers are intact, r0 holds the value which is the return value. | 3782 // Entry registers are intact, r0 holds the value which is the return value. |
| 3839 __ Ret(); | 3783 __ Ret(); |
| 3840 | 3784 |
| 3841 | 3785 if (array_type != kExternalPixelArray) { |
| 3842 // r3: external array. | 3786 // r3: external array. |
| 3843 // r4: index (integer). | 3787 // r4: index (integer). |
| 3844 __ bind(&check_heap_number); | 3788 __ bind(&check_heap_number); |
| 3845 __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); | 3789 __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); |
| 3846 __ b(ne, &slow); | 3790 __ b(ne, &slow); |
| 3847 | 3791 |
| 3848 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); | 3792 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); |
| 3849 | 3793 |
| 3850 // r3: base pointer of external storage. | 3794 // r3: base pointer of external storage. |
| 3851 // r4: key (integer). | 3795 // r4: key (integer). |
| 3852 | 3796 |
| 3853 // The WebGL specification leaves the behavior of storing NaN and | 3797 // The WebGL specification leaves the behavior of storing NaN and |
| 3854 // +/-Infinity into integer arrays basically undefined. For more | 3798 // +/-Infinity into integer arrays basically undefined. For more |
| 3855 // reproducible behavior, convert these to zero. | 3799 // reproducible behavior, convert these to zero. |
| 3856 if (CpuFeatures::IsSupported(VFP3)) { | 3800 if (CpuFeatures::IsSupported(VFP3)) { |
| 3857 CpuFeatures::Scope scope(VFP3); | 3801 CpuFeatures::Scope scope(VFP3); |
| 3858 | 3802 |
| 3859 | 3803 |
| 3860 if (array_type == kExternalFloatArray) { | 3804 if (array_type == kExternalFloatArray) { |
| 3861 // vldr requires offset to be a multiple of 4 so we can not | 3805 // vldr requires offset to be a multiple of 4 so we can not |
| 3862 // include -kHeapObjectTag into it. | 3806 // include -kHeapObjectTag into it. |
| 3863 __ sub(r5, r0, Operand(kHeapObjectTag)); | 3807 __ sub(r5, r0, Operand(kHeapObjectTag)); |
| 3864 __ vldr(d0, r5, HeapNumber::kValueOffset); | 3808 __ vldr(d0, r5, HeapNumber::kValueOffset); |
| 3865 __ add(r5, r3, Operand(r4, LSL, 2)); | 3809 __ add(r5, r3, Operand(r4, LSL, 2)); |
| 3866 __ vcvt_f32_f64(s0, d0); | 3810 __ vcvt_f32_f64(s0, d0); |
| 3867 __ vstr(s0, r5, 0); | 3811 __ vstr(s0, r5, 0); |
| 3868 } else { | |
| 3869 // Need to perform float-to-int conversion. | |
| 3870 // Test for NaN or infinity (both give zero). | |
| 3871 __ ldr(r6, FieldMemOperand(value, HeapNumber::kExponentOffset)); | |
| 3872 | |
| 3873 // Hoisted load. vldr requires offset to be a multiple of 4 so we can not | |
| 3874 // include -kHeapObjectTag into it. | |
| 3875 __ sub(r5, value, Operand(kHeapObjectTag)); | |
| 3876 __ vldr(d0, r5, HeapNumber::kValueOffset); | |
| 3877 | |
| 3878 __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits); | |
| 3879 // NaNs and Infinities have all-one exponents so they sign extend to -1. | |
| 3880 __ cmp(r6, Operand(-1)); | |
| 3881 __ mov(r5, Operand(0), LeaveCC, eq); | |
| 3882 | |
| 3883 // Not infinity or NaN simply convert to int. | |
| 3884 if (IsElementTypeSigned(array_type)) { | |
| 3885 __ vcvt_s32_f64(s0, d0, kDefaultRoundToZero, ne); | |
| 3886 } else { | 3812 } else { |
| 3887 __ vcvt_u32_f64(s0, d0, kDefaultRoundToZero, ne); | 3813 // Need to perform float-to-int conversion. |
| 3814 // Test for NaN or infinity (both give zero). |
| 3815 __ ldr(r6, FieldMemOperand(value, HeapNumber::kExponentOffset)); |
| 3816 |
| 3817 // Hoisted load. vldr requires offset to be a multiple of 4 so we can |
| 3818 // not include -kHeapObjectTag into it. |
| 3819 __ sub(r5, value, Operand(kHeapObjectTag)); |
| 3820 __ vldr(d0, r5, HeapNumber::kValueOffset); |
| 3821 |
| 3822 __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits); |
| 3823 // NaNs and Infinities have all-one exponents so they sign extend to -1. |
| 3824 __ cmp(r6, Operand(-1)); |
| 3825 __ mov(r5, Operand(0), LeaveCC, eq); |
| 3826 |
| 3827 // Not infinity or NaN simply convert to int. |
| 3828 if (IsElementTypeSigned(array_type)) { |
| 3829 __ vcvt_s32_f64(s0, d0, kDefaultRoundToZero, ne); |
| 3830 } else { |
| 3831 __ vcvt_u32_f64(s0, d0, kDefaultRoundToZero, ne); |
| 3832 } |
| 3833 __ vmov(r5, s0, ne); |
| 3834 |
| 3835 switch (array_type) { |
| 3836 case kExternalByteArray: |
| 3837 case kExternalUnsignedByteArray: |
| 3838 __ strb(r5, MemOperand(r3, r4, LSL, 0)); |
| 3839 break; |
| 3840 case kExternalShortArray: |
| 3841 case kExternalUnsignedShortArray: |
| 3842 __ strh(r5, MemOperand(r3, r4, LSL, 1)); |
| 3843 break; |
| 3844 case kExternalIntArray: |
| 3845 case kExternalUnsignedIntArray: |
| 3846 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 3847 break; |
| 3848 default: |
| 3849 UNREACHABLE(); |
| 3850 break; |
| 3851 } |
| 3888 } | 3852 } |
| 3889 __ vmov(r5, s0, ne); | 3853 |
| 3890 | |
| 3891 switch (array_type) { | |
| 3892 case kExternalByteArray: | |
| 3893 case kExternalUnsignedByteArray: | |
| 3894 __ strb(r5, MemOperand(r3, r4, LSL, 0)); | |
| 3895 break; | |
| 3896 case kExternalShortArray: | |
| 3897 case kExternalUnsignedShortArray: | |
| 3898 __ strh(r5, MemOperand(r3, r4, LSL, 1)); | |
| 3899 break; | |
| 3900 case kExternalIntArray: | |
| 3901 case kExternalUnsignedIntArray: | |
| 3902 __ str(r5, MemOperand(r3, r4, LSL, 2)); | |
| 3903 break; | |
| 3904 default: | |
| 3905 UNREACHABLE(); | |
| 3906 break; | |
| 3907 } | |
| 3908 } | |
| 3909 | |
| 3910 // Entry registers are intact, r0 holds the value which is the return value. | |
| 3911 __ Ret(); | |
| 3912 } else { | |
| 3913 // VFP3 is not available do manual conversions. | |
| 3914 __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset)); | |
| 3915 __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset)); | |
| 3916 | |
| 3917 if (array_type == kExternalFloatArray) { | |
| 3918 Label done, nan_or_infinity_or_zero; | |
| 3919 static const int kMantissaInHiWordShift = | |
| 3920 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; | |
| 3921 | |
| 3922 static const int kMantissaInLoWordShift = | |
| 3923 kBitsPerInt - kMantissaInHiWordShift; | |
| 3924 | |
| 3925 // Test for all special exponent values: zeros, subnormal numbers, NaNs | |
| 3926 // and infinities. All these should be converted to 0. | |
| 3927 __ mov(r7, Operand(HeapNumber::kExponentMask)); | |
| 3928 __ and_(r9, r5, Operand(r7), SetCC); | |
| 3929 __ b(eq, &nan_or_infinity_or_zero); | |
| 3930 | |
| 3931 __ teq(r9, Operand(r7)); | |
| 3932 __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq); | |
| 3933 __ b(eq, &nan_or_infinity_or_zero); | |
| 3934 | |
| 3935 // Rebias exponent. | |
| 3936 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); | |
| 3937 __ add(r9, | |
| 3938 r9, | |
| 3939 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias)); | |
| 3940 | |
| 3941 __ cmp(r9, Operand(kBinary32MaxExponent)); | |
| 3942 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt); | |
| 3943 __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt); | |
| 3944 __ b(gt, &done); | |
| 3945 | |
| 3946 __ cmp(r9, Operand(kBinary32MinExponent)); | |
| 3947 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt); | |
| 3948 __ b(lt, &done); | |
| 3949 | |
| 3950 __ and_(r7, r5, Operand(HeapNumber::kSignMask)); | |
| 3951 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); | |
| 3952 __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift)); | |
| 3953 __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift)); | |
| 3954 __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift)); | |
| 3955 | |
| 3956 __ bind(&done); | |
| 3957 __ str(r5, MemOperand(r3, r4, LSL, 2)); | |
| 3958 // Entry registers are intact, r0 holds the value which is the return | 3854 // Entry registers are intact, r0 holds the value which is the return |
| 3959 // value. | 3855 // value. |
| 3960 __ Ret(); | 3856 __ Ret(); |
| 3961 | |
| 3962 __ bind(&nan_or_infinity_or_zero); | |
| 3963 __ and_(r7, r5, Operand(HeapNumber::kSignMask)); | |
| 3964 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); | |
| 3965 __ orr(r9, r9, r7); | |
| 3966 __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift)); | |
| 3967 __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift)); | |
| 3968 __ b(&done); | |
| 3969 } else { | 3857 } else { |
| 3970 bool is_signed_type = IsElementTypeSigned(array_type); | 3858 // VFP3 is not available do manual conversions. |
| 3971 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt; | 3859 __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset)); |
| 3972 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000; | 3860 __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset)); |
| 3973 | 3861 |
| 3974 Label done, sign; | 3862 if (array_type == kExternalFloatArray) { |
| 3975 | 3863 Label done, nan_or_infinity_or_zero; |
| 3976 // Test for all special exponent values: zeros, subnormal numbers, NaNs | 3864 static const int kMantissaInHiWordShift = |
| 3977 // and infinities. All these should be converted to 0. | 3865 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord; |
| 3978 __ mov(r7, Operand(HeapNumber::kExponentMask)); | 3866 |
| 3979 __ and_(r9, r5, Operand(r7), SetCC); | 3867 static const int kMantissaInLoWordShift = |
| 3980 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 3868 kBitsPerInt - kMantissaInHiWordShift; |
| 3981 __ b(eq, &done); | 3869 |
| 3982 | 3870 // Test for all special exponent values: zeros, subnormal numbers, NaNs |
| 3983 __ teq(r9, Operand(r7)); | 3871 // and infinities. All these should be converted to 0. |
| 3984 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 3872 __ mov(r7, Operand(HeapNumber::kExponentMask)); |
| 3985 __ b(eq, &done); | 3873 __ and_(r9, r5, Operand(r7), SetCC); |
| 3986 | 3874 __ b(eq, &nan_or_infinity_or_zero); |
| 3987 // Unbias exponent. | 3875 |
| 3988 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); | 3876 __ teq(r9, Operand(r7)); |
| 3989 __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC); | 3877 __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq); |
| 3990 // If exponent is negative then result is 0. | 3878 __ b(eq, &nan_or_infinity_or_zero); |
| 3991 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi); | 3879 |
| 3992 __ b(mi, &done); | 3880 // Rebias exponent. |
| 3993 | 3881 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); |
| 3994 // If exponent is too big then result is minimal value. | 3882 __ add(r9, |
| 3995 __ cmp(r9, Operand(meaningfull_bits - 1)); | 3883 r9, |
| 3996 __ mov(r5, Operand(min_value), LeaveCC, ge); | 3884 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias)); |
| 3997 __ b(ge, &done); | 3885 |
| 3998 | 3886 __ cmp(r9, Operand(kBinary32MaxExponent)); |
| 3999 __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC); | 3887 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt); |
| 4000 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); | 3888 __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt); |
| 4001 __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord)); | 3889 __ b(gt, &done); |
| 4002 | 3890 |
| 4003 __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC); | 3891 __ cmp(r9, Operand(kBinary32MinExponent)); |
| 4004 __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl); | 3892 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt); |
| 4005 __ b(pl, &sign); | 3893 __ b(lt, &done); |
| 4006 | 3894 |
| 4007 __ rsb(r9, r9, Operand(0, RelocInfo::NONE)); | 3895 __ and_(r7, r5, Operand(HeapNumber::kSignMask)); |
| 4008 __ mov(r5, Operand(r5, LSL, r9)); | 3896 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
| 4009 __ rsb(r9, r9, Operand(meaningfull_bits)); | 3897 __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift)); |
| 4010 __ orr(r5, r5, Operand(r6, LSR, r9)); | 3898 __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift)); |
| 4011 | 3899 __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift)); |
| 4012 __ bind(&sign); | 3900 |
| 4013 __ teq(r7, Operand(0, RelocInfo::NONE)); | 3901 __ bind(&done); |
| 4014 __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne); | 3902 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 4015 | 3903 // Entry registers are intact, r0 holds the value which is the return |
| 4016 __ bind(&done); | 3904 // value. |
| 4017 switch (array_type) { | 3905 __ Ret(); |
| 4018 case kExternalByteArray: | 3906 |
| 4019 case kExternalUnsignedByteArray: | 3907 __ bind(&nan_or_infinity_or_zero); |
| 4020 __ strb(r5, MemOperand(r3, r4, LSL, 0)); | 3908 __ and_(r7, r5, Operand(HeapNumber::kSignMask)); |
| 4021 break; | 3909 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
| 4022 case kExternalShortArray: | 3910 __ orr(r9, r9, r7); |
| 4023 case kExternalUnsignedShortArray: | 3911 __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift)); |
| 4024 __ strh(r5, MemOperand(r3, r4, LSL, 1)); | 3912 __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift)); |
| 4025 break; | 3913 __ b(&done); |
| 4026 case kExternalIntArray: | 3914 } else { |
| 4027 case kExternalUnsignedIntArray: | 3915 bool is_signed_type = IsElementTypeSigned(array_type); |
| 4028 __ str(r5, MemOperand(r3, r4, LSL, 2)); | 3916 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt; |
| 4029 break; | 3917 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000; |
| 4030 default: | 3918 |
| 4031 UNREACHABLE(); | 3919 Label done, sign; |
| 4032 break; | 3920 |
| 3921 // Test for all special exponent values: zeros, subnormal numbers, NaNs |
| 3922 // and infinities. All these should be converted to 0. |
| 3923 __ mov(r7, Operand(HeapNumber::kExponentMask)); |
| 3924 __ and_(r9, r5, Operand(r7), SetCC); |
| 3925 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 3926 __ b(eq, &done); |
| 3927 |
| 3928 __ teq(r9, Operand(r7)); |
| 3929 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 3930 __ b(eq, &done); |
| 3931 |
| 3932 // Unbias exponent. |
| 3933 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift)); |
| 3934 __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC); |
| 3935 // If exponent is negative then result is 0. |
| 3936 __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi); |
| 3937 __ b(mi, &done); |
| 3938 |
| 3939 // If exponent is too big then result is minimal value. |
| 3940 __ cmp(r9, Operand(meaningfull_bits - 1)); |
| 3941 __ mov(r5, Operand(min_value), LeaveCC, ge); |
| 3942 __ b(ge, &done); |
| 3943 |
| 3944 __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC); |
| 3945 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask)); |
| 3946 __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord)); |
| 3947 |
| 3948 __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC); |
| 3949 __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl); |
| 3950 __ b(pl, &sign); |
| 3951 |
| 3952 __ rsb(r9, r9, Operand(0, RelocInfo::NONE)); |
| 3953 __ mov(r5, Operand(r5, LSL, r9)); |
| 3954 __ rsb(r9, r9, Operand(meaningfull_bits)); |
| 3955 __ orr(r5, r5, Operand(r6, LSR, r9)); |
| 3956 |
| 3957 __ bind(&sign); |
| 3958 __ teq(r7, Operand(0, RelocInfo::NONE)); |
| 3959 __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne); |
| 3960 |
| 3961 __ bind(&done); |
| 3962 switch (array_type) { |
| 3963 case kExternalByteArray: |
| 3964 case kExternalUnsignedByteArray: |
| 3965 __ strb(r5, MemOperand(r3, r4, LSL, 0)); |
| 3966 break; |
| 3967 case kExternalShortArray: |
| 3968 case kExternalUnsignedShortArray: |
| 3969 __ strh(r5, MemOperand(r3, r4, LSL, 1)); |
| 3970 break; |
| 3971 case kExternalIntArray: |
| 3972 case kExternalUnsignedIntArray: |
| 3973 __ str(r5, MemOperand(r3, r4, LSL, 2)); |
| 3974 break; |
| 3975 default: |
| 3976 UNREACHABLE(); |
| 3977 break; |
| 3978 } |
| 4033 } | 3979 } |
| 4034 } | 3980 } |
| 4035 } | 3981 } |
| 4036 | 3982 |
| 4037 // Slow case: call runtime. | 3983 // Slow case: call runtime. |
| 4038 __ bind(&slow); | 3984 __ bind(&slow); |
| 4039 | 3985 |
| 4040 // Entry registers are intact. | 3986 // Entry registers are intact. |
| 4041 // ---------- S t a t e -------------- | 3987 // ---------- S t a t e -------------- |
| 4042 // -- r0 : value | 3988 // -- r0 : value |
| 4043 // -- r1 : key | 3989 // -- r1 : key |
| 4044 // -- r2 : receiver | 3990 // -- r2 : receiver |
| 4045 // -- lr : return address | 3991 // -- lr : return address |
| 4046 // ----------------------------------- | 3992 // ----------------------------------- |
| 4047 | 3993 |
| 4048 // Push receiver, key and value for runtime call. | 3994 // Push receiver, key and value for runtime call. |
| 4049 __ Push(r2, r1, r0); | 3995 __ Push(r2, r1, r0); |
| 4050 | 3996 |
| 4051 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); | 3997 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes |
| 3998 __ mov(r0, Operand(Smi::FromInt( |
| 3999 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); |
| 4000 __ Push(r1, r0); |
| 4001 |
| 4002 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); |
| 4052 | 4003 |
| 4053 return GetCode(flags); | 4004 return GetCode(flags); |
| 4054 } | 4005 } |
| 4055 | 4006 |
| 4056 | 4007 |
| 4057 #undef __ | 4008 #undef __ |
| 4058 | 4009 |
| 4059 } } // namespace v8::internal | 4010 } } // namespace v8::internal |
| 4060 | 4011 |
| 4061 #endif // V8_TARGET_ARCH_ARM | 4012 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |