| 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 2195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2206 // Patch the receiver on the stack with the global proxy if | 2206 // Patch the receiver on the stack with the global proxy if |
| 2207 // necessary. | 2207 // necessary. |
| 2208 if (object->IsGlobalObject()) { | 2208 if (object->IsGlobalObject()) { |
| 2209 ASSERT(depth == kInvalidProtoDepth); | 2209 ASSERT(depth == kInvalidProtoDepth); |
| 2210 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2210 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2211 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2211 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2212 } | 2212 } |
| 2213 break; | 2213 break; |
| 2214 | 2214 |
| 2215 case STRING_CHECK: | 2215 case STRING_CHECK: |
| 2216 if (!function->IsBuiltin()) { | 2216 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2217 // Calling non-builtins with a value as receiver requires boxing. | 2217 // Calling non-strict non-builtins with a value as the receiver |
| 2218 // requires boxing. |
| 2218 __ jmp(&miss); | 2219 __ jmp(&miss); |
| 2219 } else { | 2220 } else { |
| 2220 // Check that the object is a string or a symbol. | 2221 // Check that the object is a string or a symbol. |
| 2221 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); | 2222 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); |
| 2222 __ j(above_equal, &miss, not_taken); | 2223 __ j(above_equal, &miss, not_taken); |
| 2223 // Check that the maps starting from the prototype haven't changed. | 2224 // Check that the maps starting from the prototype haven't changed. |
| 2224 GenerateDirectLoadGlobalFunctionPrototype( | 2225 GenerateDirectLoadGlobalFunctionPrototype( |
| 2225 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); | 2226 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); |
| 2226 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2227 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2227 ebx, edx, edi, name, &miss); | 2228 ebx, edx, edi, name, &miss); |
| 2228 } | 2229 } |
| 2229 break; | 2230 break; |
| 2230 | 2231 |
| 2231 case NUMBER_CHECK: { | 2232 case NUMBER_CHECK: { |
| 2232 if (!function->IsBuiltin()) { | 2233 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2233 // Calling non-builtins with a value as receiver requires boxing. | 2234 // Calling non-strict non-builtins with a value as the receiver |
| 2235 // requires boxing. |
| 2234 __ jmp(&miss); | 2236 __ jmp(&miss); |
| 2235 } else { | 2237 } else { |
| 2236 Label fast; | 2238 Label fast; |
| 2237 // Check that the object is a smi or a heap number. | 2239 // Check that the object is a smi or a heap number. |
| 2238 __ test(edx, Immediate(kSmiTagMask)); | 2240 __ test(edx, Immediate(kSmiTagMask)); |
| 2239 __ j(zero, &fast, taken); | 2241 __ j(zero, &fast, taken); |
| 2240 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); | 2242 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); |
| 2241 __ j(not_equal, &miss, not_taken); | 2243 __ j(not_equal, &miss, not_taken); |
| 2242 __ bind(&fast); | 2244 __ bind(&fast); |
| 2243 // Check that the maps starting from the prototype haven't changed. | 2245 // Check that the maps starting from the prototype haven't changed. |
| 2244 GenerateDirectLoadGlobalFunctionPrototype( | 2246 GenerateDirectLoadGlobalFunctionPrototype( |
| 2245 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); | 2247 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); |
| 2246 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2248 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2247 ebx, edx, edi, name, &miss); | 2249 ebx, edx, edi, name, &miss); |
| 2248 } | 2250 } |
| 2249 break; | 2251 break; |
| 2250 } | 2252 } |
| 2251 | 2253 |
| 2252 case BOOLEAN_CHECK: { | 2254 case BOOLEAN_CHECK: { |
| 2253 if (!function->IsBuiltin()) { | 2255 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2254 // Calling non-builtins with a value as receiver requires boxing. | 2256 // Calling non-strict non-builtins with a value as the receiver |
| 2257 // requires boxing. |
| 2255 __ jmp(&miss); | 2258 __ jmp(&miss); |
| 2256 } else { | 2259 } else { |
| 2257 Label fast; | 2260 Label fast; |
| 2258 // Check that the object is a boolean. | 2261 // Check that the object is a boolean. |
| 2259 __ cmp(edx, Factory::true_value()); | 2262 __ cmp(edx, Factory::true_value()); |
| 2260 __ j(equal, &fast, taken); | 2263 __ j(equal, &fast, taken); |
| 2261 __ cmp(edx, Factory::false_value()); | 2264 __ cmp(edx, Factory::false_value()); |
| 2262 __ j(not_equal, &miss, not_taken); | 2265 __ j(not_equal, &miss, not_taken); |
| 2263 __ bind(&fast); | 2266 __ bind(&fast); |
| 2264 // Check that the maps starting from the prototype haven't changed. | 2267 // Check that the maps starting from the prototype haven't changed. |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2551 } | 2554 } |
| 2552 | 2555 |
| 2553 // Stub never generated for non-global objects that require access | 2556 // Stub never generated for non-global objects that require access |
| 2554 // checks. | 2557 // checks. |
| 2555 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); | 2558 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); |
| 2556 | 2559 |
| 2557 __ pop(ebx); // remove the return address | 2560 __ pop(ebx); // remove the return address |
| 2558 __ push(edx); // receiver | 2561 __ push(edx); // receiver |
| 2559 __ push(ecx); // name | 2562 __ push(ecx); // name |
| 2560 __ push(eax); // value | 2563 __ push(eax); // value |
| 2564 __ push(Immediate(Smi::FromInt(strict_mode_))); |
| 2561 __ push(ebx); // restore return address | 2565 __ push(ebx); // restore return address |
| 2562 | 2566 |
| 2563 // Do tail-call to the runtime system. | 2567 // Do tail-call to the runtime system. |
| 2564 ExternalReference store_ic_property = | 2568 ExternalReference store_ic_property = |
| 2565 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); | 2569 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); |
| 2566 __ TailCallExternalReference(store_ic_property, 3, 1); | 2570 __ TailCallExternalReference(store_ic_property, 4, 1); |
| 2567 | 2571 |
| 2568 // Handle store cache miss. | 2572 // Handle store cache miss. |
| 2569 __ bind(&miss); | 2573 __ bind(&miss); |
| 2570 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2574 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 2571 __ jmp(ic, RelocInfo::CODE_TARGET); | 2575 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2572 | 2576 |
| 2573 // Return the generated code. | 2577 // Return the generated code. |
| 2574 return GetCode(INTERCEPTOR, name); | 2578 return GetCode(INTERCEPTOR, name); |
| 2575 } | 2579 } |
| 2576 | 2580 |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2722 // Handle store cache miss. | 2726 // Handle store cache miss. |
| 2723 __ bind(&miss); | 2727 __ bind(&miss); |
| 2724 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2728 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2725 __ jmp(ic, RelocInfo::CODE_TARGET); | 2729 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2726 | 2730 |
| 2727 // Return the generated code. | 2731 // Return the generated code. |
| 2728 return GetCode(NORMAL, NULL); | 2732 return GetCode(NORMAL, NULL); |
| 2729 } | 2733 } |
| 2730 | 2734 |
| 2731 | 2735 |
| 2732 MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray( | |
| 2733 JSObject* receiver) { | |
| 2734 // ----------- S t a t e ------------- | |
| 2735 // -- eax : value | |
| 2736 // -- ecx : key | |
| 2737 // -- edx : receiver | |
| 2738 // -- esp[0] : return address | |
| 2739 // ----------------------------------- | |
| 2740 Label miss; | |
| 2741 | |
| 2742 // Check that the map matches. | |
| 2743 __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false); | |
| 2744 | |
| 2745 // Do the load. | |
| 2746 GenerateFastPixelArrayStore(masm(), | |
| 2747 edx, | |
| 2748 ecx, | |
| 2749 eax, | |
| 2750 edi, | |
| 2751 ebx, | |
| 2752 true, | |
| 2753 &miss, | |
| 2754 &miss, | |
| 2755 NULL, | |
| 2756 &miss); | |
| 2757 | |
| 2758 // Handle store cache miss. | |
| 2759 __ bind(&miss); | |
| 2760 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | |
| 2761 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 2762 | |
| 2763 // Return the generated code. | |
| 2764 return GetCode(NORMAL, NULL); | |
| 2765 } | |
| 2766 | |
| 2767 | |
| 2768 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2736 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2769 JSObject* object, | 2737 JSObject* object, |
| 2770 JSObject* last) { | 2738 JSObject* last) { |
| 2771 // ----------- S t a t e ------------- | 2739 // ----------- S t a t e ------------- |
| 2772 // -- eax : receiver | 2740 // -- eax : receiver |
| 2773 // -- ecx : name | 2741 // -- ecx : name |
| 2774 // -- esp[0] : return address | 2742 // -- esp[0] : return address |
| 2775 // ----------------------------------- | 2743 // ----------------------------------- |
| 2776 Label miss; | 2744 Label miss; |
| 2777 | 2745 |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3204 __ ret(0); | 3172 __ ret(0); |
| 3205 | 3173 |
| 3206 __ bind(&miss); | 3174 __ bind(&miss); |
| 3207 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3175 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3208 | 3176 |
| 3209 // Return the generated code. | 3177 // Return the generated code. |
| 3210 return GetCode(NORMAL, NULL); | 3178 return GetCode(NORMAL, NULL); |
| 3211 } | 3179 } |
| 3212 | 3180 |
| 3213 | 3181 |
| 3214 MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) { | |
| 3215 // ----------- S t a t e ------------- | |
| 3216 // -- eax : key | |
| 3217 // -- edx : receiver | |
| 3218 // -- esp[0] : return address | |
| 3219 // ----------------------------------- | |
| 3220 Label miss; | |
| 3221 | |
| 3222 // Check that the map matches. | |
| 3223 __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false); | |
| 3224 | |
| 3225 GenerateFastPixelArrayLoad(masm(), | |
| 3226 edx, | |
| 3227 eax, | |
| 3228 ecx, | |
| 3229 ebx, | |
| 3230 eax, | |
| 3231 &miss, | |
| 3232 &miss, | |
| 3233 &miss); | |
| 3234 | |
| 3235 // Handle load cache miss. | |
| 3236 __ bind(&miss); | |
| 3237 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Miss)); | |
| 3238 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 3239 | |
| 3240 // Return the generated code. | |
| 3241 return GetCode(NORMAL, NULL); | |
| 3242 } | |
| 3243 | |
| 3244 | |
| 3245 // Specialized stub for constructing objects from functions which only have only | 3182 // Specialized stub for constructing objects from functions which only have only |
| 3246 // simple assignments of the form this.x = ...; in their body. | 3183 // simple assignments of the form this.x = ...; in their body. |
| 3247 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3184 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3248 // ----------- S t a t e ------------- | 3185 // ----------- S t a t e ------------- |
| 3249 // -- eax : argc | 3186 // -- eax : argc |
| 3250 // -- edi : constructor | 3187 // -- edi : constructor |
| 3251 // -- esp[0] : return address | 3188 // -- esp[0] : return address |
| 3252 // -- esp[4] : last argument | 3189 // -- esp[4] : last argument |
| 3253 // ----------------------------------- | 3190 // ----------------------------------- |
| 3254 Label generic_stub_call; | 3191 Label generic_stub_call; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3374 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3311 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); |
| 3375 Handle<Code> generic_construct_stub(code); | 3312 Handle<Code> generic_construct_stub(code); |
| 3376 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 3313 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3377 | 3314 |
| 3378 // Return the generated code. | 3315 // Return the generated code. |
| 3379 return GetCode(); | 3316 return GetCode(); |
| 3380 } | 3317 } |
| 3381 | 3318 |
| 3382 | 3319 |
| 3383 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3320 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3384 ExternalArrayType array_type, Code::Flags flags) { | 3321 JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) { |
| 3385 // ----------- S t a t e ------------- | 3322 // ----------- S t a t e ------------- |
| 3386 // -- eax : key | 3323 // -- eax : key |
| 3387 // -- edx : receiver | 3324 // -- edx : receiver |
| 3388 // -- esp[0] : return address | 3325 // -- esp[0] : return address |
| 3389 // ----------------------------------- | 3326 // ----------------------------------- |
| 3390 Label slow, failed_allocation; | 3327 Label slow, failed_allocation; |
| 3391 | 3328 |
| 3392 // Check that the object isn't a smi. | 3329 // Check that the object isn't a smi. |
| 3393 __ test(edx, Immediate(kSmiTagMask)); | 3330 __ test(edx, Immediate(kSmiTagMask)); |
| 3394 __ j(zero, &slow, not_taken); | 3331 __ j(zero, &slow, not_taken); |
| 3395 | 3332 |
| 3396 // Check that the key is a smi. | 3333 // Check that the key is a smi. |
| 3397 __ test(eax, Immediate(kSmiTagMask)); | 3334 __ test(eax, Immediate(kSmiTagMask)); |
| 3398 __ j(not_zero, &slow, not_taken); | 3335 __ j(not_zero, &slow, not_taken); |
| 3399 | 3336 |
| 3400 // Get the map of the receiver. | 3337 // Check that the map matches. |
| 3401 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 3338 __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false); |
| 3402 // Check that the receiver does not require access checks. We need | |
| 3403 // to check this explicitly since this generic stub does not perform | |
| 3404 // map checks. | |
| 3405 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), | |
| 3406 1 << Map::kIsAccessCheckNeeded); | |
| 3407 __ j(not_zero, &slow, not_taken); | |
| 3408 | |
| 3409 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); | |
| 3410 __ j(not_equal, &slow, not_taken); | |
| 3411 | |
| 3412 // Check that the elements array is the appropriate type of | |
| 3413 // ExternalArray. | |
| 3414 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); | 3339 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3415 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); | |
| 3416 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | |
| 3417 Immediate(map)); | |
| 3418 __ j(not_equal, &slow, not_taken); | |
| 3419 | 3340 |
| 3420 // eax: key, known to be a smi. | 3341 // eax: key, known to be a smi. |
| 3421 // edx: receiver, known to be a JSObject. | 3342 // edx: receiver, known to be a JSObject. |
| 3422 // ebx: elements object, known to be an external array. | 3343 // ebx: elements object, known to be an external array. |
| 3423 // Check that the index is in range. | 3344 // Check that the index is in range. |
| 3424 __ mov(ecx, eax); | 3345 __ mov(ecx, eax); |
| 3425 __ SmiUntag(ecx); // Untag the index. | 3346 __ SmiUntag(ecx); // Untag the index. |
| 3426 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); | 3347 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); |
| 3427 // Unsigned comparison catches both negative and too-large values. | 3348 // Unsigned comparison catches both negative and too-large values. |
| 3428 __ j(above_equal, &slow); | 3349 __ j(above_equal, &slow); |
| 3429 | |
| 3430 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); | 3350 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); |
| 3431 // ebx: base pointer of external storage | 3351 // ebx: base pointer of external storage |
| 3432 switch (array_type) { | 3352 switch (array_type) { |
| 3433 case kExternalByteArray: | 3353 case kExternalByteArray: |
| 3434 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); | 3354 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3435 break; | 3355 break; |
| 3436 case kExternalUnsignedByteArray: | 3356 case kExternalUnsignedByteArray: |
| 3437 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); | 3357 case kExternalPixelArray: |
| 3358 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3438 break; | 3359 break; |
| 3439 case kExternalShortArray: | 3360 case kExternalShortArray: |
| 3440 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); | 3361 __ movsx_w(eax, Operand(ebx, ecx, times_2, 0)); |
| 3441 break; | 3362 break; |
| 3442 case kExternalUnsignedShortArray: | 3363 case kExternalUnsignedShortArray: |
| 3443 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); | 3364 __ movzx_w(eax, Operand(ebx, ecx, times_2, 0)); |
| 3444 break; | 3365 break; |
| 3445 case kExternalIntArray: | 3366 case kExternalIntArray: |
| 3446 case kExternalUnsignedIntArray: | 3367 case kExternalUnsignedIntArray: |
| 3447 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); | 3368 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); |
| 3448 break; | 3369 break; |
| 3449 case kExternalFloatArray: | 3370 case kExternalFloatArray: |
| 3450 __ fld_s(Operand(ebx, ecx, times_4, 0)); | 3371 __ fld_s(Operand(ebx, ecx, times_4, 0)); |
| 3451 break; | 3372 break; |
| 3452 default: | 3373 default: |
| 3453 UNREACHABLE(); | 3374 UNREACHABLE(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3508 __ ret(0); | 3429 __ ret(0); |
| 3509 } else if (array_type == kExternalFloatArray) { | 3430 } else if (array_type == kExternalFloatArray) { |
| 3510 // For the floating-point array type, we need to always allocate a | 3431 // For the floating-point array type, we need to always allocate a |
| 3511 // HeapNumber. | 3432 // HeapNumber. |
| 3512 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); | 3433 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); |
| 3513 // Set the value. | 3434 // Set the value. |
| 3514 __ mov(eax, ecx); | 3435 __ mov(eax, ecx); |
| 3515 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3436 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3516 __ ret(0); | 3437 __ ret(0); |
| 3517 } else { | 3438 } else { |
| 3518 __ mov(eax, ecx); | |
| 3519 __ SmiTag(eax); | 3439 __ SmiTag(eax); |
| 3520 __ ret(0); | 3440 __ ret(0); |
| 3521 } | 3441 } |
| 3522 | 3442 |
| 3523 // If we fail allocation of the HeapNumber, we still have a value on | 3443 // If we fail allocation of the HeapNumber, we still have a value on |
| 3524 // top of the FPU stack. Remove it. | 3444 // top of the FPU stack. Remove it. |
| 3525 __ bind(&failed_allocation); | 3445 __ bind(&failed_allocation); |
| 3526 __ ffree(); | 3446 __ ffree(); |
| 3527 __ fincstp(); | 3447 __ fincstp(); |
| 3528 // Fall through to slow case. | 3448 // Fall through to slow case. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3543 | 3463 |
| 3544 // Perform tail call to the entry. | 3464 // Perform tail call to the entry. |
| 3545 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 3465 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3546 | 3466 |
| 3547 // Return the generated code. | 3467 // Return the generated code. |
| 3548 return GetCode(flags); | 3468 return GetCode(flags); |
| 3549 } | 3469 } |
| 3550 | 3470 |
| 3551 | 3471 |
| 3552 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | 3472 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( |
| 3553 ExternalArrayType array_type, Code::Flags flags) { | 3473 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { |
| 3554 // ----------- S t a t e ------------- | 3474 // ----------- S t a t e ------------- |
| 3555 // -- eax : value | 3475 // -- eax : value |
| 3556 // -- ecx : key | 3476 // -- ecx : key |
| 3557 // -- edx : receiver | 3477 // -- edx : receiver |
| 3558 // -- esp[0] : return address | 3478 // -- esp[0] : return address |
| 3559 // ----------------------------------- | 3479 // ----------------------------------- |
| 3560 Label slow, check_heap_number; | 3480 Label slow, check_heap_number; |
| 3561 | 3481 |
| 3562 // Check that the object isn't a smi. | 3482 // Check that the object isn't a smi. |
| 3563 __ test(edx, Immediate(kSmiTagMask)); | 3483 __ test(edx, Immediate(kSmiTagMask)); |
| 3564 __ j(zero, &slow); | 3484 __ j(zero, &slow); |
| 3565 // Get the map from the receiver. | 3485 |
| 3566 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 3486 // Check that the map matches. |
| 3567 // Check that the receiver does not require access checks. We need | 3487 __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false); |
| 3568 // to do this because this generic stub does not perform map checks. | 3488 |
| 3569 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), | |
| 3570 1 << Map::kIsAccessCheckNeeded); | |
| 3571 __ j(not_zero, &slow); | |
| 3572 // Check that the key is a smi. | 3489 // Check that the key is a smi. |
| 3573 __ test(ecx, Immediate(kSmiTagMask)); | 3490 __ test(ecx, Immediate(kSmiTagMask)); |
| 3574 __ j(not_zero, &slow); | 3491 __ j(not_zero, &slow); |
| 3575 // Get the instance type from the map of the receiver. | |
| 3576 __ CmpInstanceType(edi, JS_OBJECT_TYPE); | |
| 3577 __ j(not_equal, &slow); | |
| 3578 | |
| 3579 // Check that the elements array is the appropriate type of | |
| 3580 // ExternalArray. | |
| 3581 // eax: value | |
| 3582 // edx: receiver, a JSObject | |
| 3583 // ecx: key, a smi | |
| 3584 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 3585 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)), | |
| 3586 &slow, true); | |
| 3587 | 3492 |
| 3588 // Check that the index is in range. | 3493 // Check that the index is in range. |
| 3494 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3589 __ mov(ebx, ecx); | 3495 __ mov(ebx, ecx); |
| 3590 __ SmiUntag(ebx); | 3496 __ SmiUntag(ebx); |
| 3591 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); | 3497 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); |
| 3592 // Unsigned comparison catches both negative and too-large values. | 3498 // Unsigned comparison catches both negative and too-large values. |
| 3593 __ j(above_equal, &slow); | 3499 __ j(above_equal, &slow); |
| 3594 | 3500 |
| 3595 // Handle both smis and HeapNumbers in the fast path. Go to the | 3501 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3596 // runtime for all other kinds of values. | 3502 // runtime for all other kinds of values. |
| 3597 // eax: value | 3503 // eax: value |
| 3598 // edx: receiver | 3504 // edx: receiver |
| 3599 // ecx: key | 3505 // ecx: key |
| 3600 // edi: elements array | 3506 // edi: elements array |
| 3601 // ebx: untagged index | 3507 // ebx: untagged index |
| 3602 __ test(eax, Immediate(kSmiTagMask)); | 3508 __ test(eax, Immediate(kSmiTagMask)); |
| 3603 __ j(not_equal, &check_heap_number); | 3509 if (array_type == kExternalPixelArray) |
| 3510 __ j(not_equal, &slow); |
| 3511 else |
| 3512 __ j(not_equal, &check_heap_number); |
| 3513 |
| 3604 // smi case | 3514 // smi case |
| 3605 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. | 3515 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. |
| 3606 __ SmiUntag(ecx); | 3516 __ SmiUntag(ecx); |
| 3607 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3517 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3608 // ecx: base pointer of external storage | 3518 // ecx: base pointer of external storage |
| 3609 switch (array_type) { | 3519 switch (array_type) { |
| 3520 case kExternalPixelArray: |
| 3521 { // Clamp the value to [0..255]. |
| 3522 NearLabel done; |
| 3523 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3524 __ j(zero, &done); |
| 3525 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3526 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3527 __ bind(&done); |
| 3528 } |
| 3529 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3530 break; |
| 3610 case kExternalByteArray: | 3531 case kExternalByteArray: |
| 3611 case kExternalUnsignedByteArray: | 3532 case kExternalUnsignedByteArray: |
| 3612 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3533 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3613 break; | 3534 break; |
| 3614 case kExternalShortArray: | 3535 case kExternalShortArray: |
| 3615 case kExternalUnsignedShortArray: | 3536 case kExternalUnsignedShortArray: |
| 3616 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | 3537 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3617 break; | 3538 break; |
| 3618 case kExternalIntArray: | 3539 case kExternalIntArray: |
| 3619 case kExternalUnsignedIntArray: | 3540 case kExternalUnsignedIntArray: |
| 3620 __ mov(Operand(edi, ebx, times_4, 0), ecx); | 3541 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3621 break; | 3542 break; |
| 3622 case kExternalFloatArray: | 3543 case kExternalFloatArray: |
| 3623 // Need to perform int-to-float conversion. | 3544 // Need to perform int-to-float conversion. |
| 3624 __ push(ecx); | 3545 __ push(ecx); |
| 3625 __ fild_s(Operand(esp, 0)); | 3546 __ fild_s(Operand(esp, 0)); |
| 3626 __ pop(ecx); | 3547 __ pop(ecx); |
| 3627 __ fstp_s(Operand(edi, ebx, times_4, 0)); | 3548 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3628 break; | 3549 break; |
| 3629 default: | 3550 default: |
| 3630 UNREACHABLE(); | 3551 UNREACHABLE(); |
| 3631 break; | 3552 break; |
| 3632 } | 3553 } |
| 3633 __ ret(0); // Return the original value. | 3554 __ ret(0); // Return the original value. |
| 3634 | 3555 |
| 3635 __ bind(&check_heap_number); | 3556 // TODO(danno): handle heap number -> pixel array conversion |
| 3636 // eax: value | 3557 if (array_type != kExternalPixelArray) { |
| 3637 // edx: receiver | 3558 __ bind(&check_heap_number); |
| 3638 // ecx: key | 3559 // eax: value |
| 3639 // edi: elements array | 3560 // edx: receiver |
| 3640 // ebx: untagged index | 3561 // ecx: key |
| 3641 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3562 // edi: elements array |
| 3642 Immediate(Factory::heap_number_map())); | 3563 // ebx: untagged index |
| 3643 __ j(not_equal, &slow); | 3564 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3565 Immediate(Factory::heap_number_map())); |
| 3566 __ j(not_equal, &slow); |
| 3644 | 3567 |
| 3645 // The WebGL specification leaves the behavior of storing NaN and | 3568 // The WebGL specification leaves the behavior of storing NaN and |
| 3646 // +/-Infinity into integer arrays basically undefined. For more | 3569 // +/-Infinity into integer arrays basically undefined. For more |
| 3647 // reproducible behavior, convert these to zero. | 3570 // reproducible behavior, convert these to zero. |
| 3648 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3571 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3649 // ebx: untagged index | 3572 // ebx: untagged index |
| 3650 // edi: base pointer of external storage | 3573 // edi: base pointer of external storage |
| 3651 if (array_type == kExternalFloatArray) { | 3574 if (array_type == kExternalFloatArray) { |
| 3652 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3575 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3653 __ fstp_s(Operand(edi, ebx, times_4, 0)); | 3576 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3654 __ ret(0); | 3577 __ ret(0); |
| 3655 } else { | 3578 } else { |
| 3656 // Perform float-to-int conversion with truncation (round-to-zero) | 3579 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3657 // behavior. | 3580 // behavior. |
| 3658 | 3581 |
| 3659 // For the moment we make the slow call to the runtime on | 3582 // For the moment we make the slow call to the runtime on |
| 3660 // processors that don't support SSE2. The code in IntegerConvert | 3583 // processors that don't support SSE2. The code in IntegerConvert |
| 3661 // (code-stubs-ia32.cc) is roughly what is needed here though the | 3584 // (code-stubs-ia32.cc) is roughly what is needed here though the |
| 3662 // conversion failure case does not need to be handled. | 3585 // conversion failure case does not need to be handled. |
| 3663 if (CpuFeatures::IsSupported(SSE2)) { | 3586 if (CpuFeatures::IsSupported(SSE2)) { |
| 3664 if (array_type != kExternalIntArray && | 3587 if (array_type != kExternalIntArray && |
| 3665 array_type != kExternalUnsignedIntArray) { | 3588 array_type != kExternalUnsignedIntArray) { |
| 3666 ASSERT(CpuFeatures::IsSupported(SSE2)); | |
| 3667 CpuFeatures::Scope scope(SSE2); | |
| 3668 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 3669 // ecx: untagged integer value | |
| 3670 switch (array_type) { | |
| 3671 case kExternalByteArray: | |
| 3672 case kExternalUnsignedByteArray: | |
| 3673 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | |
| 3674 break; | |
| 3675 case kExternalShortArray: | |
| 3676 case kExternalUnsignedShortArray: | |
| 3677 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | |
| 3678 break; | |
| 3679 default: | |
| 3680 UNREACHABLE(); | |
| 3681 break; | |
| 3682 } | |
| 3683 } else { | |
| 3684 if (CpuFeatures::IsSupported(SSE3)) { | |
| 3685 CpuFeatures::Scope scope(SSE3); | |
| 3686 // fisttp stores values as signed integers. To represent the | |
| 3687 // entire range of int and unsigned int arrays, store as a | |
| 3688 // 64-bit int and discard the high 32 bits. | |
| 3689 // If the value is NaN or +/-infinity, the result is 0x80000000, | |
| 3690 // which is automatically zero when taken mod 2^n, n < 32. | |
| 3691 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 3692 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | |
| 3693 __ fisttp_d(Operand(esp, 0)); | |
| 3694 __ pop(ecx); | |
| 3695 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 3696 } else { | |
| 3697 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3589 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3698 CpuFeatures::Scope scope(SSE2); | 3590 CpuFeatures::Scope scope(SSE2); |
| 3699 // We can easily implement the correct rounding behavior for the | 3591 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3700 // range [0, 2^31-1]. For the time being, to keep this code simple, | 3592 // ecx: untagged integer value |
| 3701 // make the slow runtime call for values outside this range. | 3593 switch (array_type) { |
| 3702 // Note: we could do better for signed int arrays. | 3594 case kExternalPixelArray: |
| 3703 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 3595 { // Clamp the value to [0..255]. |
| 3704 // We will need the key if we have to make the slow runtime call. | 3596 NearLabel done; |
| 3705 __ push(ecx); | 3597 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3706 __ LoadPowerOf2(xmm1, ecx, 31); | 3598 __ j(zero, &done); |
| 3707 __ pop(ecx); | 3599 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3708 __ ucomisd(xmm1, xmm0); | 3600 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3709 __ j(above_equal, &slow); | 3601 __ bind(&done); |
| 3710 __ cvttsd2si(ecx, Operand(xmm0)); | 3602 } |
| 3603 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3604 case kExternalByteArray: |
| 3605 case kExternalUnsignedByteArray: |
| 3606 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3607 break; |
| 3608 case kExternalShortArray: |
| 3609 case kExternalUnsignedShortArray: |
| 3610 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3611 break; |
| 3612 default: |
| 3613 UNREACHABLE(); |
| 3614 break; |
| 3615 } |
| 3616 } else { |
| 3617 if (CpuFeatures::IsSupported(SSE3)) { |
| 3618 CpuFeatures::Scope scope(SSE3); |
| 3619 // fisttp stores values as signed integers. To represent the |
| 3620 // entire range of int and unsigned int arrays, store as a |
| 3621 // 64-bit int and discard the high 32 bits. |
| 3622 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3623 // which is automatically zero when taken mod 2^n, n < 32. |
| 3624 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3625 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 3626 __ fisttp_d(Operand(esp, 0)); |
| 3627 __ pop(ecx); |
| 3628 __ add(Operand(esp), Immediate(kPointerSize)); |
| 3629 } else { |
| 3630 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3631 CpuFeatures::Scope scope(SSE2); |
| 3632 // We can easily implement the correct rounding behavior for the |
| 3633 // range [0, 2^31-1]. For the time being, to keep this code simple, |
| 3634 // make the slow runtime call for values outside this range. |
| 3635 // Note: we could do better for signed int arrays. |
| 3636 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3637 // We will need the key if we have to make the slow runtime call. |
| 3638 __ push(ecx); |
| 3639 __ LoadPowerOf2(xmm1, ecx, 31); |
| 3640 __ pop(ecx); |
| 3641 __ ucomisd(xmm1, xmm0); |
| 3642 __ j(above_equal, &slow); |
| 3643 __ cvttsd2si(ecx, Operand(xmm0)); |
| 3644 } |
| 3645 // ecx: untagged integer value |
| 3646 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3711 } | 3647 } |
| 3712 // ecx: untagged integer value | 3648 __ ret(0); // Return original value. |
| 3713 __ mov(Operand(edi, ebx, times_4, 0), ecx); | |
| 3714 } | 3649 } |
| 3715 __ ret(0); // Return original value. | |
| 3716 } | 3650 } |
| 3717 } | 3651 } |
| 3718 | 3652 |
| 3719 // Slow case: call runtime. | 3653 // Slow case: call runtime. |
| 3720 __ bind(&slow); | 3654 __ bind(&slow); |
| 3721 // ----------- S t a t e ------------- | 3655 // ----------- S t a t e ------------- |
| 3722 // -- eax : value | 3656 // -- eax : value |
| 3723 // -- ecx : key | 3657 // -- ecx : key |
| 3724 // -- edx : receiver | 3658 // -- edx : receiver |
| 3725 // -- esp[0] : return address | 3659 // -- esp[0] : return address |
| 3726 // ----------------------------------- | 3660 // ----------------------------------- |
| 3727 | 3661 |
| 3728 __ pop(ebx); | 3662 __ pop(ebx); |
| 3729 __ push(edx); | 3663 __ push(edx); |
| 3730 __ push(ecx); | 3664 __ push(ecx); |
| 3731 __ push(eax); | 3665 __ push(eax); |
| 3732 __ push(ebx); | 3666 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes |
| 3667 __ push(Immediate(Smi::FromInt( |
| 3668 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); |
| 3669 __ push(ebx); // return address |
| 3733 | 3670 |
| 3734 // Do tail-call to runtime routine. | 3671 // Do tail-call to runtime routine. |
| 3735 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); | 3672 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); |
| 3736 | 3673 |
| 3737 return GetCode(flags); | 3674 return GetCode(flags); |
| 3738 } | 3675 } |
| 3739 | 3676 |
| 3740 | 3677 |
| 3741 #undef __ | 3678 #undef __ |
| 3742 | 3679 |
| 3743 } } // namespace v8::internal | 3680 } } // namespace v8::internal |
| 3744 | 3681 |
| 3745 #endif // V8_TARGET_ARCH_IA32 | 3682 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |