OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 3126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3137 __ bind(&generic_stub_call); | 3137 __ bind(&generic_stub_call); |
3138 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3138 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); |
3139 Handle<Code> generic_construct_stub(code); | 3139 Handle<Code> generic_construct_stub(code); |
3140 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | 3140 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); |
3141 | 3141 |
3142 // Return the generated code. | 3142 // Return the generated code. |
3143 return GetCode(); | 3143 return GetCode(); |
3144 } | 3144 } |
3145 | 3145 |
3146 | 3146 |
3147 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | |
3148 ExternalArrayType array_type, Code::Flags flags) { | |
3149 // ----------- S t a t e ------------- | |
3150 // -- rax : key | |
3151 // -- rdx : receiver | |
3152 // -- rsp[0] : return address | |
3153 // ----------------------------------- | |
3154 Label slow; | |
3155 | |
3156 // Check that the object isn't a smi. | |
3157 __ JumpIfSmi(rdx, &slow); | |
3158 | |
3159 // Check that the key is a smi. | |
3160 __ JumpIfNotSmi(rax, &slow); | |
3161 | |
3162 // Check that the object is a JS object. | |
3163 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | |
3164 __ j(not_equal, &slow); | |
3165 // Check that the receiver does not require access checks. We need | |
3166 // to check this explicitly since this generic stub does not perform | |
3167 // map checks. The map is already in rdx. | |
3168 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | |
3169 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
3170 __ j(not_zero, &slow); | |
3171 | |
3172 // Check that the elements array is the appropriate type of | |
3173 // ExternalArray. | |
3174 // rax: index (as a smi) | |
3175 // rdx: JSObject | |
3176 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3177 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
3178 Heap::RootIndexForExternalArrayType(array_type)); | |
3179 __ j(not_equal, &slow); | |
3180 | |
3181 // Check that the index is in range. | |
3182 __ SmiToInteger32(rcx, rax); | |
3183 __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); | |
3184 // Unsigned comparison catches both negative and too-large values. | |
3185 __ j(above_equal, &slow); | |
3186 | |
3187 // rax: index (as a smi) | |
3188 // rdx: receiver (JSObject) | |
3189 // rcx: untagged index | |
3190 // rbx: elements array | |
3191 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | |
3192 // rbx: base pointer of external storage | |
3193 switch (array_type) { | |
3194 case kExternalByteArray: | |
3195 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0)); | |
3196 break; | |
3197 case kExternalUnsignedByteArray: | |
3198 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0)); | |
3199 break; | |
3200 case kExternalShortArray: | |
3201 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0)); | |
3202 break; | |
3203 case kExternalUnsignedShortArray: | |
3204 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0)); | |
3205 break; | |
3206 case kExternalIntArray: | |
3207 __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0)); | |
3208 break; | |
3209 case kExternalUnsignedIntArray: | |
3210 __ movl(rcx, Operand(rbx, rcx, times_4, 0)); | |
3211 break; | |
3212 case kExternalFloatArray: | |
3213 __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0)); | |
3214 break; | |
3215 default: | |
3216 UNREACHABLE(); | |
3217 break; | |
3218 } | |
3219 | |
3220 // rax: index | |
3221 // rdx: receiver | |
3222 // For integer array types: | |
3223 // rcx: value | |
3224 // For floating-point array type: | |
3225 // xmm0: value as double. | |
3226 | |
3227 ASSERT(kSmiValueSize == 32); | |
3228 if (array_type == kExternalUnsignedIntArray) { | |
3229 // For the UnsignedInt array type, we need to see whether | |
3230 // the value can be represented in a Smi. If not, we need to convert | |
3231 // it to a HeapNumber. | |
3232 NearLabel box_int; | |
3233 | |
3234 __ JumpIfUIntNotValidSmiValue(rcx, &box_int); | |
3235 | |
3236 __ Integer32ToSmi(rax, rcx); | |
3237 __ ret(0); | |
3238 | |
3239 __ bind(&box_int); | |
3240 | |
3241 // Allocate a HeapNumber for the int and perform int-to-double | |
3242 // conversion. | |
3243 // The value is zero-extended since we loaded the value from memory | |
3244 // with movl. | |
3245 __ cvtqsi2sd(xmm0, rcx); | |
3246 | |
3247 __ AllocateHeapNumber(rcx, rbx, &slow); | |
3248 // Set the value. | |
3249 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); | |
3250 __ movq(rax, rcx); | |
3251 __ ret(0); | |
3252 } else if (array_type == kExternalFloatArray) { | |
3253 // For the floating-point array type, we need to always allocate a | |
3254 // HeapNumber. | |
3255 __ AllocateHeapNumber(rcx, rbx, &slow); | |
3256 // Set the value. | |
3257 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); | |
3258 __ movq(rax, rcx); | |
3259 __ ret(0); | |
3260 } else { | |
3261 __ Integer32ToSmi(rax, rcx); | |
3262 __ ret(0); | |
3263 } | |
3264 | |
3265 // Slow case: Jump to runtime. | |
3266 __ bind(&slow); | |
3267 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); | |
3268 | |
3269 // ----------- S t a t e ------------- | |
3270 // -- rax : key | |
3271 // -- rdx : receiver | |
3272 // -- rsp[0] : return address | |
3273 // ----------------------------------- | |
3274 | |
3275 __ pop(rbx); | |
3276 __ push(rdx); // receiver | |
3277 __ push(rax); // name | |
3278 __ push(rbx); // return address | |
3279 | |
3280 // Perform tail call to the entry. | |
3281 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | |
3282 | |
3283 // Return the generated code. | |
3284 return GetCode(flags); | |
3285 } | |
3286 | |
3287 | |
3288 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | |
3289 ExternalArrayType array_type, Code::Flags flags) { | |
3290 // ----------- S t a t e ------------- | |
3291 // -- rax : value | |
3292 // -- rcx : key | |
3293 // -- rdx : receiver | |
3294 // -- rsp[0] : return address | |
3295 // ----------------------------------- | |
3296 Label slow; | |
3297 | |
3298 // Check that the object isn't a smi. | |
3299 __ JumpIfSmi(rdx, &slow); | |
3300 // Get the map from the receiver. | |
3301 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
3302 // Check that the receiver does not require access checks. We need | |
3303 // to do this because this generic stub does not perform map checks. | |
3304 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | |
3305 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
3306 __ j(not_zero, &slow); | |
3307 // Check that the key is a smi. | |
3308 __ JumpIfNotSmi(rcx, &slow); | |
3309 | |
3310 // Check that the object is a JS object. | |
3311 __ CmpInstanceType(rbx, JS_OBJECT_TYPE); | |
3312 __ j(not_equal, &slow); | |
3313 | |
3314 // Check that the elements array is the appropriate type of | |
3315 // ExternalArray. | |
3316 // rax: value | |
3317 // rcx: key (a smi) | |
3318 // rdx: receiver (a JSObject) | |
3319 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3320 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
3321 Heap::RootIndexForExternalArrayType(array_type)); | |
3322 __ j(not_equal, &slow); | |
3323 | |
3324 // Check that the index is in range. | |
3325 __ SmiToInteger32(rdi, rcx); // Untag the index. | |
3326 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); | |
3327 // Unsigned comparison catches both negative and too-large values. | |
3328 __ j(above_equal, &slow); | |
3329 | |
3330 // Handle both smis and HeapNumbers in the fast path. Go to the | |
3331 // runtime for all other kinds of values. | |
3332 // rax: value | |
3333 // rcx: key (a smi) | |
3334 // rdx: receiver (a JSObject) | |
3335 // rbx: elements array | |
3336 // rdi: untagged key | |
3337 NearLabel check_heap_number; | |
3338 __ JumpIfNotSmi(rax, &check_heap_number); | |
3339 // No more branches to slow case on this path. Key and receiver not needed. | |
3340 __ SmiToInteger32(rdx, rax); | |
3341 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | |
3342 // rbx: base pointer of external storage | |
3343 switch (array_type) { | |
3344 case kExternalByteArray: | |
3345 case kExternalUnsignedByteArray: | |
3346 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | |
3347 break; | |
3348 case kExternalShortArray: | |
3349 case kExternalUnsignedShortArray: | |
3350 __ movw(Operand(rbx, rdi, times_2, 0), rdx); | |
3351 break; | |
3352 case kExternalIntArray: | |
3353 case kExternalUnsignedIntArray: | |
3354 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | |
3355 break; | |
3356 case kExternalFloatArray: | |
3357 // Need to perform int-to-float conversion. | |
3358 __ cvtlsi2ss(xmm0, rdx); | |
3359 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | |
3360 break; | |
3361 default: | |
3362 UNREACHABLE(); | |
3363 break; | |
3364 } | |
3365 __ ret(0); | |
3366 | |
3367 __ bind(&check_heap_number); | |
3368 // rax: value | |
3369 // rcx: key (a smi) | |
3370 // rdx: receiver (a JSObject) | |
3371 // rbx: elements array | |
3372 // rdi: untagged key | |
3373 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); | |
3374 __ j(not_equal, &slow); | |
3375 // No more branches to slow case on this path. | |
3376 | |
3377 // The WebGL specification leaves the behavior of storing NaN and | |
3378 // +/-Infinity into integer arrays basically undefined. For more | |
3379 // reproducible behavior, convert these to zero. | |
3380 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | |
3381 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | |
3382 // rdi: untagged index | |
3383 // rbx: base pointer of external storage | |
3384 // top of FPU stack: value | |
3385 if (array_type == kExternalFloatArray) { | |
3386 __ cvtsd2ss(xmm0, xmm0); | |
3387 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | |
3388 __ ret(0); | |
3389 } else { | |
3390 // Perform float-to-int conversion with truncation (round-to-zero) | |
3391 // behavior. | |
3392 | |
3393 // Convert to int32 and store the low byte/word. | |
3394 // If the value is NaN or +/-infinity, the result is 0x80000000, | |
3395 // which is automatically zero when taken mod 2^n, n < 32. | |
3396 // rdx: value (converted to an untagged integer) | |
3397 // rdi: untagged index | |
3398 // rbx: base pointer of external storage | |
3399 switch (array_type) { | |
3400 case kExternalByteArray: | |
3401 case kExternalUnsignedByteArray: | |
3402 __ cvttsd2si(rdx, xmm0); | |
3403 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | |
3404 break; | |
3405 case kExternalShortArray: | |
3406 case kExternalUnsignedShortArray: | |
3407 __ cvttsd2si(rdx, xmm0); | |
3408 __ movw(Operand(rbx, rdi, times_2, 0), rdx); | |
3409 break; | |
3410 case kExternalIntArray: | |
3411 case kExternalUnsignedIntArray: { | |
3412 // Convert to int64, so that NaN and infinities become | |
3413 // 0x8000000000000000, which is zero mod 2^32. | |
3414 __ cvttsd2siq(rdx, xmm0); | |
3415 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | |
3416 break; | |
3417 } | |
3418 default: | |
3419 UNREACHABLE(); | |
3420 break; | |
3421 } | |
3422 __ ret(0); | |
3423 } | |
3424 | |
3425 // Slow case: call runtime. | |
3426 __ bind(&slow); | |
3427 | |
3428 // ----------- S t a t e ------------- | |
3429 // -- rax : value | |
3430 // -- rcx : key | |
3431 // -- rdx : receiver | |
3432 // -- rsp[0] : return address | |
3433 // ----------------------------------- | |
3434 | |
3435 __ pop(rbx); | |
3436 __ push(rdx); // receiver | |
3437 __ push(rcx); // key | |
3438 __ push(rax); // value | |
3439 __ push(rbx); // return address | |
3440 | |
3441 // Do tail-call to runtime routine. | |
3442 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); | |
3443 | |
3444 return GetCode(flags); | |
3445 } | |
3446 | |
3447 #undef __ | 3147 #undef __ |
3448 | 3148 |
3449 } } // namespace v8::internal | 3149 } } // namespace v8::internal |
3450 | 3150 |
3451 #endif // V8_TARGET_ARCH_X64 | 3151 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |