| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 2041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2053 // Patch the receiver on the stack with the global proxy if | 2053 // Patch the receiver on the stack with the global proxy if |
| 2054 // necessary. | 2054 // necessary. |
| 2055 if (object->IsGlobalObject()) { | 2055 if (object->IsGlobalObject()) { |
| 2056 ASSERT(depth == kInvalidProtoDepth); | 2056 ASSERT(depth == kInvalidProtoDepth); |
| 2057 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 2057 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
| 2058 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 2058 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
| 2059 } | 2059 } |
| 2060 break; | 2060 break; |
| 2061 | 2061 |
| 2062 case STRING_CHECK: | 2062 case STRING_CHECK: |
| 2063 if (!function->IsBuiltin()) { | 2063 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2064 // Calling non-builtins with a value as receiver requires boxing. | 2064 // Calling non-strict non-builtins with a value as the receiver |
| 2065 // requires boxing. |
| 2065 __ jmp(&miss); | 2066 __ jmp(&miss); |
| 2066 } else { | 2067 } else { |
| 2067 // Check that the object is a two-byte string or a symbol. | 2068 // Check that the object is a two-byte string or a symbol. |
| 2068 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); | 2069 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); |
| 2069 __ j(above_equal, &miss); | 2070 __ j(above_equal, &miss); |
| 2070 // Check that the maps starting from the prototype haven't changed. | 2071 // Check that the maps starting from the prototype haven't changed. |
| 2071 GenerateDirectLoadGlobalFunctionPrototype( | 2072 GenerateDirectLoadGlobalFunctionPrototype( |
| 2072 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); | 2073 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); |
| 2073 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, | 2074 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, |
| 2074 rbx, rdx, rdi, name, &miss); | 2075 rbx, rdx, rdi, name, &miss); |
| 2075 } | 2076 } |
| 2076 break; | 2077 break; |
| 2077 | 2078 |
| 2078 case NUMBER_CHECK: { | 2079 case NUMBER_CHECK: { |
| 2079 if (!function->IsBuiltin()) { | 2080 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2080 // Calling non-builtins with a value as receiver requires boxing. | 2081 // Calling non-strict non-builtins with a value as the receiver |
| 2082 // requires boxing. |
| 2081 __ jmp(&miss); | 2083 __ jmp(&miss); |
| 2082 } else { | 2084 } else { |
| 2083 Label fast; | 2085 Label fast; |
| 2084 // Check that the object is a smi or a heap number. | 2086 // Check that the object is a smi or a heap number. |
| 2085 __ JumpIfSmi(rdx, &fast); | 2087 __ JumpIfSmi(rdx, &fast); |
| 2086 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); | 2088 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); |
| 2087 __ j(not_equal, &miss); | 2089 __ j(not_equal, &miss); |
| 2088 __ bind(&fast); | 2090 __ bind(&fast); |
| 2089 // Check that the maps starting from the prototype haven't changed. | 2091 // Check that the maps starting from the prototype haven't changed. |
| 2090 GenerateDirectLoadGlobalFunctionPrototype( | 2092 GenerateDirectLoadGlobalFunctionPrototype( |
| 2091 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); | 2093 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); |
| 2092 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, | 2094 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, |
| 2093 rbx, rdx, rdi, name, &miss); | 2095 rbx, rdx, rdi, name, &miss); |
| 2094 } | 2096 } |
| 2095 break; | 2097 break; |
| 2096 } | 2098 } |
| 2097 | 2099 |
| 2098 case BOOLEAN_CHECK: { | 2100 case BOOLEAN_CHECK: { |
| 2099 if (!function->IsBuiltin()) { | 2101 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2100 // Calling non-builtins with a value as receiver requires boxing. | 2102 // Calling non-strict non-builtins with a value as the receiver |
| 2103 // requires boxing. |
| 2101 __ jmp(&miss); | 2104 __ jmp(&miss); |
| 2102 } else { | 2105 } else { |
| 2103 Label fast; | 2106 Label fast; |
| 2104 // Check that the object is a boolean. | 2107 // Check that the object is a boolean. |
| 2105 __ CompareRoot(rdx, Heap::kTrueValueRootIndex); | 2108 __ CompareRoot(rdx, Heap::kTrueValueRootIndex); |
| 2106 __ j(equal, &fast); | 2109 __ j(equal, &fast); |
| 2107 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); | 2110 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); |
| 2108 __ j(not_equal, &miss); | 2111 __ j(not_equal, &miss); |
| 2109 __ bind(&fast); | 2112 __ bind(&fast); |
| 2110 // Check that the maps starting from the prototype haven't changed. | 2113 // Check that the maps starting from the prototype haven't changed. |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2398 } | 2401 } |
| 2399 | 2402 |
| 2400 // Stub never generated for non-global objects that require access | 2403 // Stub never generated for non-global objects that require access |
| 2401 // checks. | 2404 // checks. |
| 2402 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); | 2405 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); |
| 2403 | 2406 |
| 2404 __ pop(rbx); // remove the return address | 2407 __ pop(rbx); // remove the return address |
| 2405 __ push(rdx); // receiver | 2408 __ push(rdx); // receiver |
| 2406 __ push(rcx); // name | 2409 __ push(rcx); // name |
| 2407 __ push(rax); // value | 2410 __ push(rax); // value |
| 2411 __ Push(Smi::FromInt(strict_mode_)); |
| 2408 __ push(rbx); // restore return address | 2412 __ push(rbx); // restore return address |
| 2409 | 2413 |
| 2410 // Do tail-call to the runtime system. | 2414 // Do tail-call to the runtime system. |
| 2411 ExternalReference store_ic_property = | 2415 ExternalReference store_ic_property = |
| 2412 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); | 2416 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); |
| 2413 __ TailCallExternalReference(store_ic_property, 3, 1); | 2417 __ TailCallExternalReference(store_ic_property, 4, 1); |
| 2414 | 2418 |
| 2415 // Handle store cache miss. | 2419 // Handle store cache miss. |
| 2416 __ bind(&miss); | 2420 __ bind(&miss); |
| 2417 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2421 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 2418 __ Jump(ic, RelocInfo::CODE_TARGET); | 2422 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 2419 | 2423 |
| 2420 // Return the generated code. | 2424 // Return the generated code. |
| 2421 return GetCode(INTERCEPTOR, name); | 2425 return GetCode(INTERCEPTOR, name); |
| 2422 } | 2426 } |
| 2423 | 2427 |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2552 // Handle store cache miss. | 2556 // Handle store cache miss. |
| 2553 __ bind(&miss); | 2557 __ bind(&miss); |
| 2554 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2558 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2555 __ jmp(ic, RelocInfo::CODE_TARGET); | 2559 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2556 | 2560 |
| 2557 // Return the generated code. | 2561 // Return the generated code. |
| 2558 return GetCode(NORMAL, NULL); | 2562 return GetCode(NORMAL, NULL); |
| 2559 } | 2563 } |
| 2560 | 2564 |
| 2561 | 2565 |
| 2562 MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray( | |
| 2563 JSObject* receiver) { | |
| 2564 // ----------- S t a t e ------------- | |
| 2565 // -- rax : value | |
| 2566 // -- rcx : key | |
| 2567 // -- rdx : receiver | |
| 2568 // -- rsp[0] : return address | |
| 2569 // ----------------------------------- | |
| 2570 Label miss; | |
| 2571 | |
| 2572 // Check that the map matches. | |
| 2573 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false); | |
| 2574 | |
| 2575 // Do the load. | |
| 2576 GenerateFastPixelArrayStore(masm(), | |
| 2577 rdx, | |
| 2578 rcx, | |
| 2579 rax, | |
| 2580 rdi, | |
| 2581 rbx, | |
| 2582 true, | |
| 2583 false, | |
| 2584 &miss, | |
| 2585 &miss, | |
| 2586 NULL, | |
| 2587 &miss); | |
| 2588 | |
| 2589 // Handle store cache miss. | |
| 2590 __ bind(&miss); | |
| 2591 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | |
| 2592 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 2593 | |
| 2594 // Return the generated code. | |
| 2595 return GetCode(NORMAL, NULL); | |
| 2596 } | |
| 2597 | |
| 2598 | |
| 2599 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2566 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2600 JSObject* object, | 2567 JSObject* object, |
| 2601 JSObject* last) { | 2568 JSObject* last) { |
| 2602 // ----------- S t a t e ------------- | 2569 // ----------- S t a t e ------------- |
| 2603 // -- rax : receiver | 2570 // -- rax : receiver |
| 2604 // -- rcx : name | 2571 // -- rcx : name |
| 2605 // -- rsp[0] : return address | 2572 // -- rsp[0] : return address |
| 2606 // ----------------------------------- | 2573 // ----------------------------------- |
| 2607 Label miss; | 2574 Label miss; |
| 2608 | 2575 |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3028 __ ret(0); | 2995 __ ret(0); |
| 3029 | 2996 |
| 3030 __ bind(&miss); | 2997 __ bind(&miss); |
| 3031 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2998 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3032 | 2999 |
| 3033 // Return the generated code. | 3000 // Return the generated code. |
| 3034 return GetCode(NORMAL, NULL); | 3001 return GetCode(NORMAL, NULL); |
| 3035 } | 3002 } |
| 3036 | 3003 |
| 3037 | 3004 |
| 3038 MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) { | |
| 3039 // ----------- S t a t e ------------- | |
| 3040 // -- rax : key | |
| 3041 // -- rdx : receiver | |
| 3042 // -- esp[0] : return address | |
| 3043 // ----------------------------------- | |
| 3044 Label miss; | |
| 3045 | |
| 3046 // Check that the map matches. | |
| 3047 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false); | |
| 3048 | |
| 3049 GenerateFastPixelArrayLoad(masm(), | |
| 3050 rdx, | |
| 3051 rax, | |
| 3052 rbx, | |
| 3053 rcx, | |
| 3054 rax, | |
| 3055 &miss, | |
| 3056 &miss, | |
| 3057 &miss); | |
| 3058 | |
| 3059 __ bind(&miss); | |
| 3060 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | |
| 3061 | |
| 3062 // Return the generated code. | |
| 3063 return GetCode(NORMAL, NULL); | |
| 3064 } | |
| 3065 | |
| 3066 | |
| 3067 // Specialized stub for constructing objects from functions which only have only | 3005 // Specialized stub for constructing objects from functions which only have only |
| 3068 // simple assignments of the form this.x = ...; in their body. | 3006 // simple assignments of the form this.x = ...; in their body. |
| 3069 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3007 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3070 // ----------- S t a t e ------------- | 3008 // ----------- S t a t e ------------- |
| 3071 // -- rax : argc | 3009 // -- rax : argc |
| 3072 // -- rdi : constructor | 3010 // -- rdi : constructor |
| 3073 // -- rsp[0] : return address | 3011 // -- rsp[0] : return address |
| 3074 // -- rsp[4] : last argument | 3012 // -- rsp[4] : last argument |
| 3075 // ----------------------------------- | 3013 // ----------------------------------- |
| 3076 Label generic_stub_call; | 3014 Label generic_stub_call; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3189 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3127 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); |
| 3190 Handle<Code> generic_construct_stub(code); | 3128 Handle<Code> generic_construct_stub(code); |
| 3191 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | 3129 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3192 | 3130 |
| 3193 // Return the generated code. | 3131 // Return the generated code. |
| 3194 return GetCode(); | 3132 return GetCode(); |
| 3195 } | 3133 } |
| 3196 | 3134 |
| 3197 | 3135 |
| 3198 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3136 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3199 ExternalArrayType array_type, Code::Flags flags) { | 3137 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { |
| 3200 // ----------- S t a t e ------------- | 3138 // ----------- S t a t e ------------- |
| 3201 // -- rax : key | 3139 // -- rax : key |
| 3202 // -- rdx : receiver | 3140 // -- rdx : receiver |
| 3203 // -- rsp[0] : return address | 3141 // -- rsp[0] : return address |
| 3204 // ----------------------------------- | 3142 // ----------------------------------- |
| 3205 Label slow; | 3143 Label slow; |
| 3206 | 3144 |
| 3207 // Check that the object isn't a smi. | 3145 // Check that the object isn't a smi. |
| 3208 __ JumpIfSmi(rdx, &slow); | 3146 __ JumpIfSmi(rdx, &slow); |
| 3209 | 3147 |
| 3210 // Check that the key is a smi. | 3148 // Check that the key is a smi. |
| 3211 __ JumpIfNotSmi(rax, &slow); | 3149 __ JumpIfNotSmi(rax, &slow); |
| 3212 | 3150 |
| 3213 // Check that the object is a JS object. | 3151 // Check that the map matches. |
| 3214 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | 3152 __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false); |
| 3215 __ j(not_equal, &slow); | |
| 3216 // Check that the receiver does not require access checks. We need | |
| 3217 // to check this explicitly since this generic stub does not perform | |
| 3218 // map checks. The map is already in rdx. | |
| 3219 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | |
| 3220 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
| 3221 __ j(not_zero, &slow); | |
| 3222 | |
| 3223 // Check that the elements array is the appropriate type of | |
| 3224 // ExternalArray. | |
| 3225 // rax: index (as a smi) | |
| 3226 // rdx: JSObject | |
| 3227 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 3153 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3228 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
| 3229 Heap::RootIndexForExternalArrayType(array_type)); | |
| 3230 __ j(not_equal, &slow); | |
| 3231 | 3154 |
| 3232 // Check that the index is in range. | 3155 // Check that the index is in range. |
| 3233 __ SmiToInteger32(rcx, rax); | 3156 __ SmiToInteger32(rcx, rax); |
| 3234 __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); | 3157 __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); |
| 3235 // Unsigned comparison catches both negative and too-large values. | 3158 // Unsigned comparison catches both negative and too-large values. |
| 3236 __ j(above_equal, &slow); | 3159 __ j(above_equal, &slow); |
| 3237 | 3160 |
| 3238 // rax: index (as a smi) | 3161 // rax: index (as a smi) |
| 3239 // rdx: receiver (JSObject) | 3162 // rdx: receiver (JSObject) |
| 3240 // rcx: untagged index | 3163 // rcx: untagged index |
| 3241 // rbx: elements array | 3164 // rbx: elements array |
| 3242 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | 3165 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3243 // rbx: base pointer of external storage | 3166 // rbx: base pointer of external storage |
| 3244 switch (array_type) { | 3167 switch (array_type) { |
| 3245 case kExternalByteArray: | 3168 case kExternalByteArray: |
| 3246 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0)); | 3169 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0)); |
| 3247 break; | 3170 break; |
| 3171 case kExternalPixelArray: |
| 3248 case kExternalUnsignedByteArray: | 3172 case kExternalUnsignedByteArray: |
| 3249 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0)); | 3173 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0)); |
| 3250 break; | 3174 break; |
| 3251 case kExternalShortArray: | 3175 case kExternalShortArray: |
| 3252 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0)); | 3176 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0)); |
| 3253 break; | 3177 break; |
| 3254 case kExternalUnsignedShortArray: | 3178 case kExternalUnsignedShortArray: |
| 3255 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0)); | 3179 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0)); |
| 3256 break; | 3180 break; |
| 3257 case kExternalIntArray: | 3181 case kExternalIntArray: |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3330 | 3254 |
| 3331 // Perform tail call to the entry. | 3255 // Perform tail call to the entry. |
| 3332 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 3256 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3333 | 3257 |
| 3334 // Return the generated code. | 3258 // Return the generated code. |
| 3335 return GetCode(flags); | 3259 return GetCode(flags); |
| 3336 } | 3260 } |
| 3337 | 3261 |
| 3338 | 3262 |
| 3339 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | 3263 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( |
| 3340 ExternalArrayType array_type, Code::Flags flags) { | 3264 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { |
| 3341 // ----------- S t a t e ------------- | 3265 // ----------- S t a t e ------------- |
| 3342 // -- rax : value | 3266 // -- rax : value |
| 3343 // -- rcx : key | 3267 // -- rcx : key |
| 3344 // -- rdx : receiver | 3268 // -- rdx : receiver |
| 3345 // -- rsp[0] : return address | 3269 // -- rsp[0] : return address |
| 3346 // ----------------------------------- | 3270 // ----------------------------------- |
| 3347 Label slow; | 3271 Label slow; |
| 3348 | 3272 |
| 3349 // Check that the object isn't a smi. | 3273 // Check that the object isn't a smi. |
| 3350 __ JumpIfSmi(rdx, &slow); | 3274 __ JumpIfSmi(rdx, &slow); |
| 3351 // Get the map from the receiver. | 3275 |
| 3352 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 3276 // Check that the map matches. |
| 3353 // Check that the receiver does not require access checks. We need | 3277 __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false); |
| 3354 // to do this because this generic stub does not perform map checks. | 3278 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3355 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 3279 |
| 3356 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
| 3357 __ j(not_zero, &slow); | |
| 3358 // Check that the key is a smi. | 3280 // Check that the key is a smi. |
| 3359 __ JumpIfNotSmi(rcx, &slow); | 3281 __ JumpIfNotSmi(rcx, &slow); |
| 3360 | 3282 |
| 3361 // Check that the object is a JS object. | |
| 3362 __ CmpInstanceType(rbx, JS_OBJECT_TYPE); | |
| 3363 __ j(not_equal, &slow); | |
| 3364 | |
| 3365 // Check that the elements array is the appropriate type of | |
| 3366 // ExternalArray. | |
| 3367 // rax: value | |
| 3368 // rcx: key (a smi) | |
| 3369 // rdx: receiver (a JSObject) | |
| 3370 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
| 3371 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
| 3372 Heap::RootIndexForExternalArrayType(array_type)); | |
| 3373 __ j(not_equal, &slow); | |
| 3374 | |
| 3375 // Check that the index is in range. | 3283 // Check that the index is in range. |
| 3376 __ SmiToInteger32(rdi, rcx); // Untag the index. | 3284 __ SmiToInteger32(rdi, rcx); // Untag the index. |
| 3377 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); | 3285 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); |
| 3378 // Unsigned comparison catches both negative and too-large values. | 3286 // Unsigned comparison catches both negative and too-large values. |
| 3379 __ j(above_equal, &slow); | 3287 __ j(above_equal, &slow); |
| 3380 | 3288 |
| 3381 // Handle both smis and HeapNumbers in the fast path. Go to the | 3289 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3382 // runtime for all other kinds of values. | 3290 // runtime for all other kinds of values. |
| 3383 // rax: value | 3291 // rax: value |
| 3384 // rcx: key (a smi) | 3292 // rcx: key (a smi) |
| 3385 // rdx: receiver (a JSObject) | 3293 // rdx: receiver (a JSObject) |
| 3386 // rbx: elements array | 3294 // rbx: elements array |
| 3387 // rdi: untagged key | 3295 // rdi: untagged key |
| 3388 NearLabel check_heap_number; | 3296 NearLabel check_heap_number; |
| 3389 __ JumpIfNotSmi(rax, &check_heap_number); | 3297 if (array_type == kExternalPixelArray) { |
| 3298 // Float to pixel conversion is only implemented in the runtime for now. |
| 3299 __ JumpIfNotSmi(rax, &slow); |
| 3300 } else { |
| 3301 __ JumpIfNotSmi(rax, &check_heap_number); |
| 3302 } |
| 3390 // No more branches to slow case on this path. Key and receiver not needed. | 3303 // No more branches to slow case on this path. Key and receiver not needed. |
| 3391 __ SmiToInteger32(rdx, rax); | 3304 __ SmiToInteger32(rdx, rax); |
| 3392 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | 3305 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3393 // rbx: base pointer of external storage | 3306 // rbx: base pointer of external storage |
| 3394 switch (array_type) { | 3307 switch (array_type) { |
| 3308 case kExternalPixelArray: |
| 3309 { // Clamp the value to [0..255]. |
| 3310 NearLabel done; |
| 3311 __ testl(rdx, Immediate(0xFFFFFF00)); |
| 3312 __ j(zero, &done); |
| 3313 __ setcc(negative, rdx); // 1 if negative, 0 if positive. |
| 3314 __ decb(rdx); // 0 if negative, 255 if positive. |
| 3315 __ bind(&done); |
| 3316 } |
| 3317 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 3318 break; |
| 3395 case kExternalByteArray: | 3319 case kExternalByteArray: |
| 3396 case kExternalUnsignedByteArray: | 3320 case kExternalUnsignedByteArray: |
| 3397 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | 3321 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 3398 break; | 3322 break; |
| 3399 case kExternalShortArray: | 3323 case kExternalShortArray: |
| 3400 case kExternalUnsignedShortArray: | 3324 case kExternalUnsignedShortArray: |
| 3401 __ movw(Operand(rbx, rdi, times_2, 0), rdx); | 3325 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 3402 break; | 3326 break; |
| 3403 case kExternalIntArray: | 3327 case kExternalIntArray: |
| 3404 case kExternalUnsignedIntArray: | 3328 case kExternalUnsignedIntArray: |
| 3405 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | 3329 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 3406 break; | 3330 break; |
| 3407 case kExternalFloatArray: | 3331 case kExternalFloatArray: |
| 3408 // Need to perform int-to-float conversion. | 3332 // Need to perform int-to-float conversion. |
| 3409 __ cvtlsi2ss(xmm0, rdx); | 3333 __ cvtlsi2ss(xmm0, rdx); |
| 3410 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | 3334 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); |
| 3411 break; | 3335 break; |
| 3412 default: | 3336 default: |
| 3413 UNREACHABLE(); | 3337 UNREACHABLE(); |
| 3414 break; | 3338 break; |
| 3415 } | 3339 } |
| 3416 __ ret(0); | 3340 __ ret(0); |
| 3417 | 3341 |
| 3418 __ bind(&check_heap_number); | 3342 // TODO(danno): handle heap number -> pixel array conversion |
| 3419 // rax: value | 3343 if (array_type != kExternalPixelArray) { |
| 3420 // rcx: key (a smi) | 3344 __ bind(&check_heap_number); |
| 3421 // rdx: receiver (a JSObject) | 3345 // rax: value |
| 3422 // rbx: elements array | 3346 // rcx: key (a smi) |
| 3423 // rdi: untagged key | 3347 // rdx: receiver (a JSObject) |
| 3424 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); | 3348 // rbx: elements array |
| 3425 __ j(not_equal, &slow); | 3349 // rdi: untagged key |
| 3426 // No more branches to slow case on this path. | 3350 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); |
| 3351 __ j(not_equal, &slow); |
| 3352 // No more branches to slow case on this path. |
| 3427 | 3353 |
| 3428 // The WebGL specification leaves the behavior of storing NaN and | 3354 // The WebGL specification leaves the behavior of storing NaN and |
| 3429 // +/-Infinity into integer arrays basically undefined. For more | 3355 // +/-Infinity into integer arrays basically undefined. For more |
| 3430 // reproducible behavior, convert these to zero. | 3356 // reproducible behavior, convert these to zero. |
| 3431 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | 3357 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 3432 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | 3358 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3433 // rdi: untagged index | |
| 3434 // rbx: base pointer of external storage | |
| 3435 // top of FPU stack: value | |
| 3436 if (array_type == kExternalFloatArray) { | |
| 3437 __ cvtsd2ss(xmm0, xmm0); | |
| 3438 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | |
| 3439 __ ret(0); | |
| 3440 } else { | |
| 3441 // Perform float-to-int conversion with truncation (round-to-zero) | |
| 3442 // behavior. | |
| 3443 | |
| 3444 // Convert to int32 and store the low byte/word. | |
| 3445 // If the value is NaN or +/-infinity, the result is 0x80000000, | |
| 3446 // which is automatically zero when taken mod 2^n, n < 32. | |
| 3447 // rdx: value (converted to an untagged integer) | |
| 3448 // rdi: untagged index | 3359 // rdi: untagged index |
| 3449 // rbx: base pointer of external storage | 3360 // rbx: base pointer of external storage |
| 3450 switch (array_type) { | 3361 // top of FPU stack: value |
| 3451 case kExternalByteArray: | 3362 if (array_type == kExternalFloatArray) { |
| 3452 case kExternalUnsignedByteArray: | 3363 __ cvtsd2ss(xmm0, xmm0); |
| 3453 __ cvttsd2si(rdx, xmm0); | 3364 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); |
| 3454 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | 3365 __ ret(0); |
| 3455 break; | 3366 } else { |
| 3456 case kExternalShortArray: | 3367 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3457 case kExternalUnsignedShortArray: | 3368 // behavior. |
| 3458 __ cvttsd2si(rdx, xmm0); | 3369 |
| 3459 __ movw(Operand(rbx, rdi, times_2, 0), rdx); | 3370 // Convert to int32 and store the low byte/word. |
| 3460 break; | 3371 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3461 case kExternalIntArray: | 3372 // which is automatically zero when taken mod 2^n, n < 32. |
| 3462 case kExternalUnsignedIntArray: { | 3373 // rdx: value (converted to an untagged integer) |
| 3463 // Convert to int64, so that NaN and infinities become | 3374 // rdi: untagged index |
| 3464 // 0x8000000000000000, which is zero mod 2^32. | 3375 // rbx: base pointer of external storage |
| 3465 __ cvttsd2siq(rdx, xmm0); | 3376 switch (array_type) { |
| 3466 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | 3377 case kExternalByteArray: |
| 3467 break; | 3378 case kExternalUnsignedByteArray: |
| 3379 __ cvttsd2si(rdx, xmm0); |
| 3380 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 3381 break; |
| 3382 case kExternalShortArray: |
| 3383 case kExternalUnsignedShortArray: |
| 3384 __ cvttsd2si(rdx, xmm0); |
| 3385 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 3386 break; |
| 3387 case kExternalIntArray: |
| 3388 case kExternalUnsignedIntArray: { |
| 3389 // Convert to int64, so that NaN and infinities become |
| 3390 // 0x8000000000000000, which is zero mod 2^32. |
| 3391 __ cvttsd2siq(rdx, xmm0); |
| 3392 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 3393 break; |
| 3394 } |
| 3395 default: |
| 3396 UNREACHABLE(); |
| 3397 break; |
| 3468 } | 3398 } |
| 3469 default: | 3399 __ ret(0); |
| 3470 UNREACHABLE(); | |
| 3471 break; | |
| 3472 } | 3400 } |
| 3473 __ ret(0); | |
| 3474 } | 3401 } |
| 3475 | 3402 |
| 3476 // Slow case: call runtime. | 3403 // Slow case: call runtime. |
| 3477 __ bind(&slow); | 3404 __ bind(&slow); |
| 3478 | 3405 |
| 3479 // ----------- S t a t e ------------- | 3406 // ----------- S t a t e ------------- |
| 3480 // -- rax : value | 3407 // -- rax : value |
| 3481 // -- rcx : key | 3408 // -- rcx : key |
| 3482 // -- rdx : receiver | 3409 // -- rdx : receiver |
| 3483 // -- rsp[0] : return address | 3410 // -- rsp[0] : return address |
| 3484 // ----------------------------------- | 3411 // ----------------------------------- |
| 3485 | 3412 |
| 3486 __ pop(rbx); | 3413 __ pop(rbx); |
| 3487 __ push(rdx); // receiver | 3414 __ push(rdx); // receiver |
| 3488 __ push(rcx); // key | 3415 __ push(rcx); // key |
| 3489 __ push(rax); // value | 3416 __ push(rax); // value |
| 3417 __ Push(Smi::FromInt(NONE)); // PropertyAttributes |
| 3418 __ Push(Smi::FromInt( |
| 3419 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)); |
| 3490 __ push(rbx); // return address | 3420 __ push(rbx); // return address |
| 3491 | 3421 |
| 3492 // Do tail-call to runtime routine. | 3422 // Do tail-call to runtime routine. |
| 3493 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); | 3423 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); |
| 3494 | 3424 |
| 3495 return GetCode(flags); | 3425 return GetCode(flags); |
| 3496 } | 3426 } |
| 3497 | 3427 |
| 3498 #undef __ | 3428 #undef __ |
| 3499 | 3429 |
| 3500 } } // namespace v8::internal | 3430 } } // namespace v8::internal |
| 3501 | 3431 |
| 3502 #endif // V8_TARGET_ARCH_X64 | 3432 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |