OLD | NEW |
---|---|
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils-gen.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
8 #include "src/objects.h" | 8 #include "src/objects.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
13 using compiler::Node; | 13 using compiler::Node; |
14 | 14 |
15 class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler { | 15 class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler { |
16 public: | 16 public: |
17 explicit SharedArrayBufferBuiltinsAssembler( | 17 explicit SharedArrayBufferBuiltinsAssembler( |
18 compiler::CodeAssemblerState* state) | 18 compiler::CodeAssemblerState* state) |
19 : CodeStubAssembler(state) {} | 19 : CodeStubAssembler(state) {} |
20 | 20 |
21 protected: | 21 protected: |
22 typedef Node* (CodeAssembler::*AssemblerFunction)(MachineType type, | |
23 Node* base, Node* offset, | |
24 Node* value); | |
22 void ValidateSharedTypedArray(Node* tagged, Node* context, | 25 void ValidateSharedTypedArray(Node* tagged, Node* context, |
23 Node** out_instance_type, | 26 Node** out_instance_type, |
24 Node** out_backing_store); | 27 Node** out_backing_store); |
25 Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context, | 28 Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context, |
26 Node** number_index); | 29 Node** number_index); |
27 void ValidateAtomicIndex(Node* index_word, Node* array_length_word, | 30 void ValidateAtomicIndex(Node* index_word, Node* array_length_word, |
28 Node* context); | 31 Node* context); |
32 void AtomicBinopBuiltinCommon(Node* array, Node* index, Node* value, | |
33 Node* context, AssemblerFunction function, | |
34 Runtime::FunctionId runtime_function); | |
29 }; | 35 }; |
30 | 36 |
31 void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( | 37 void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( |
32 Node* tagged, Node* context, Node** out_instance_type, | 38 Node* tagged, Node* context, Node** out_instance_type, |
33 Node** out_backing_store) { | 39 Node** out_backing_store) { |
34 Label not_float_or_clamped(this), invalid(this); | 40 Label not_float_or_clamped(this), invalid(this); |
35 | 41 |
36 // Fail if it is not a heap object. | 42 // Fail if it is not a heap object. |
37 GotoIf(TaggedIsSmi(tagged), &invalid); | 43 GotoIf(TaggedIsSmi(tagged), &invalid); |
38 | 44 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 Unreachable(); | 143 Unreachable(); |
138 | 144 |
139 BIND(&check_passed); | 145 BIND(&check_passed); |
140 } | 146 } |
141 | 147 |
142 TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) { | 148 TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) { |
143 Node* array = Parameter(Descriptor::kArray); | 149 Node* array = Parameter(Descriptor::kArray); |
144 Node* index = Parameter(Descriptor::kIndex); | 150 Node* index = Parameter(Descriptor::kIndex); |
145 Node* context = Parameter(Descriptor::kContext); | 151 Node* context = Parameter(Descriptor::kContext); |
146 | 152 |
153 Node* index_integer; | |
154 Node* index_word32 = | |
155 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
156 | |
147 Node* instance_type; | 157 Node* instance_type; |
148 Node* backing_store; | 158 Node* backing_store; |
149 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); | 159 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); |
150 | 160 |
151 Node* index_integer; | |
152 Node* index_word32 = | |
153 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
154 Node* array_length_word32 = TruncateTaggedToWord32( | 161 Node* array_length_word32 = TruncateTaggedToWord32( |
155 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); | 162 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); |
156 ValidateAtomicIndex(index_word32, array_length_word32, context); | 163 ValidateAtomicIndex(index_word32, array_length_word32, context); |
157 Node* index_word = ChangeUint32ToWord(index_word32); | 164 Node* index_word = ChangeUint32ToWord(index_word32); |
158 | 165 |
159 Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this), | 166 Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this), |
160 other(this); | 167 other(this); |
161 int32_t case_values[] = { | 168 int32_t case_values[] = { |
162 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, | 169 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, |
163 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, | 170 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
196 BIND(&other); | 203 BIND(&other); |
197 Unreachable(); | 204 Unreachable(); |
198 } | 205 } |
199 | 206 |
200 TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { | 207 TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { |
201 Node* array = Parameter(Descriptor::kArray); | 208 Node* array = Parameter(Descriptor::kArray); |
202 Node* index = Parameter(Descriptor::kIndex); | 209 Node* index = Parameter(Descriptor::kIndex); |
203 Node* value = Parameter(Descriptor::kValue); | 210 Node* value = Parameter(Descriptor::kValue); |
204 Node* context = Parameter(Descriptor::kContext); | 211 Node* context = Parameter(Descriptor::kContext); |
205 | 212 |
213 // The value_integer needs to be computed before the validations as the | |
214 // ToInteger function can be potentially modified in JS to invalidate the | |
215 // conditions. This is just a no-cost safety measure as SABs can't be neutered | |
216 // or shrunk. | |
217 Node* value_integer = ToInteger(context, value); | |
Jarin
2017/04/11 08:23:16
I believe this is incorrect because the spec says
| |
218 Node* value_word32 = TruncateTaggedToWord32(context, value_integer); | |
219 | |
220 Node* index_integer; | |
221 Node* index_word32 = | |
222 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
223 | |
206 Node* instance_type; | 224 Node* instance_type; |
207 Node* backing_store; | 225 Node* backing_store; |
208 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); | 226 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); |
209 | 227 |
210 Node* index_integer; | |
211 Node* index_word32 = | |
212 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
213 Node* array_length_word32 = TruncateTaggedToWord32( | 228 Node* array_length_word32 = TruncateTaggedToWord32( |
214 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); | 229 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); |
215 ValidateAtomicIndex(index_word32, array_length_word32, context); | 230 ValidateAtomicIndex(index_word32, array_length_word32, context); |
216 Node* index_word = ChangeUint32ToWord(index_word32); | 231 Node* index_word = ChangeUint32ToWord(index_word32); |
217 | 232 |
218 Node* value_integer = ToInteger(context, value); | |
219 Node* value_word32 = TruncateTaggedToWord32(context, value_integer); | |
220 | |
221 Label u8(this), u16(this), u32(this), other(this); | 233 Label u8(this), u16(this), u32(this), other(this); |
222 int32_t case_values[] = { | 234 int32_t case_values[] = { |
223 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, | 235 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, |
224 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, | 236 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, |
225 }; | 237 }; |
226 Label* case_labels[] = { | 238 Label* case_labels[] = { |
227 &u8, &u8, &u16, &u16, &u32, &u32, | 239 &u8, &u8, &u16, &u16, &u32, &u32, |
228 }; | 240 }; |
229 Switch(instance_type, &other, case_values, case_labels, | 241 Switch(instance_type, &other, case_values, case_labels, |
230 arraysize(case_labels)); | 242 arraysize(case_labels)); |
(...skipping 17 matching lines...) Expand all Loading... | |
248 BIND(&other); | 260 BIND(&other); |
249 Unreachable(); | 261 Unreachable(); |
250 } | 262 } |
251 | 263 |
252 TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { | 264 TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { |
253 Node* array = Parameter(Descriptor::kArray); | 265 Node* array = Parameter(Descriptor::kArray); |
254 Node* index = Parameter(Descriptor::kIndex); | 266 Node* index = Parameter(Descriptor::kIndex); |
255 Node* value = Parameter(Descriptor::kValue); | 267 Node* value = Parameter(Descriptor::kValue); |
256 Node* context = Parameter(Descriptor::kContext); | 268 Node* context = Parameter(Descriptor::kContext); |
257 | 269 |
270 // The value_integer needs to be computed before the validations as the | |
271 // ToInteger function can be potentially modified in JS to invalidate the | |
272 // conditions. This is just a no-cost safety measure as SABs can't be neutered | |
273 // or shrunk. | |
274 Node* value_integer = ToInteger(context, value); | |
275 | |
276 Node* index_integer; | |
277 Node* index_word32 = | |
278 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
279 | |
258 Node* instance_type; | 280 Node* instance_type; |
259 Node* backing_store; | 281 Node* backing_store; |
260 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); | 282 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); |
261 | 283 |
262 Node* index_integer; | |
263 Node* index_word32 = | |
264 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
265 Node* array_length_word32 = TruncateTaggedToWord32( | 284 Node* array_length_word32 = TruncateTaggedToWord32( |
266 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); | 285 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); |
267 ValidateAtomicIndex(index_word32, array_length_word32, context); | 286 ValidateAtomicIndex(index_word32, array_length_word32, context); |
268 | 287 |
269 Node* value_integer = ToInteger(context, value); | |
270 | |
271 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 | 288 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
272 Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer, | 289 Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer, |
273 value_integer)); | 290 value_integer)); |
274 #else | 291 #else |
275 Node* index_word = ChangeUint32ToWord(index_word32); | 292 Node* index_word = ChangeUint32ToWord(index_word32); |
276 | 293 |
277 Node* value_word32 = TruncateTaggedToWord32(context, value_integer); | 294 Node* value_word32 = TruncateTaggedToWord32(context, value_integer); |
278 | 295 |
279 Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this), | 296 Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this), |
280 other(this); | 297 other(this); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 | 337 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
321 } | 338 } |
322 | 339 |
323 TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { | 340 TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { |
324 Node* array = Parameter(Descriptor::kArray); | 341 Node* array = Parameter(Descriptor::kArray); |
325 Node* index = Parameter(Descriptor::kIndex); | 342 Node* index = Parameter(Descriptor::kIndex); |
326 Node* old_value = Parameter(Descriptor::kOldValue); | 343 Node* old_value = Parameter(Descriptor::kOldValue); |
327 Node* new_value = Parameter(Descriptor::kNewValue); | 344 Node* new_value = Parameter(Descriptor::kNewValue); |
328 Node* context = Parameter(Descriptor::kContext); | 345 Node* context = Parameter(Descriptor::kContext); |
329 | 346 |
347 // The value_integers needs to be computed before the validations as the | |
348 // ToInteger function can be potentially modified in JS to invalidate the | |
349 // conditions. This is just a no-cost safety measure as SABs can't be neutered | |
350 // or shrunk. | |
351 Node* old_value_integer = ToInteger(context, old_value); | |
352 Node* new_value_integer = ToInteger(context, new_value); | |
353 | |
354 Node* index_integer; | |
355 Node* index_word32 = | |
356 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
357 | |
330 Node* instance_type; | 358 Node* instance_type; |
331 Node* backing_store; | 359 Node* backing_store; |
332 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); | 360 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); |
333 | 361 |
334 Node* index_integer; | |
335 Node* index_word32 = | |
336 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
337 Node* array_length_word32 = TruncateTaggedToWord32( | 362 Node* array_length_word32 = TruncateTaggedToWord32( |
338 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); | 363 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); |
339 ValidateAtomicIndex(index_word32, array_length_word32, context); | 364 ValidateAtomicIndex(index_word32, array_length_word32, context); |
340 | 365 |
341 Node* old_value_integer = ToInteger(context, old_value); | |
342 | |
343 Node* new_value_integer = ToInteger(context, new_value); | |
344 | |
345 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ | 366 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ |
346 V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X | 367 V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X |
347 Return(CallRuntime(Runtime::kAtomicsCompareExchange, context, array, | 368 Return(CallRuntime(Runtime::kAtomicsCompareExchange, context, array, |
348 index_integer, old_value_integer, new_value_integer)); | 369 index_integer, old_value_integer, new_value_integer)); |
349 #else | 370 #else |
350 Node* index_word = ChangeUint32ToWord(index_word32); | 371 Node* index_word = ChangeUint32ToWord(index_word32); |
351 | 372 |
352 Node* old_value_word32 = TruncateTaggedToWord32(context, old_value_integer); | 373 Node* old_value_word32 = TruncateTaggedToWord32(context, old_value_integer); |
353 | 374 |
354 Node* new_value_word32 = TruncateTaggedToWord32(context, new_value_integer); | 375 Node* new_value_word32 = TruncateTaggedToWord32(context, new_value_integer); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 MachineType::Uint32(), backing_store, WordShl(index_word, 2), | 416 MachineType::Uint32(), backing_store, WordShl(index_word, 2), |
396 old_value_word32, new_value_word32))); | 417 old_value_word32, new_value_word32))); |
397 | 418 |
398 // This shouldn't happen, we've already validated the type. | 419 // This shouldn't happen, we've already validated the type. |
399 BIND(&other); | 420 BIND(&other); |
400 Unreachable(); | 421 Unreachable(); |
401 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 | 422 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 |
402 // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X | 423 // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X |
403 } | 424 } |
404 | 425 |
426 #define BINOP_BUILTIN(op) \ | |
427 TF_BUILTIN(Atomics##op, SharedArrayBufferBuiltinsAssembler) { \ | |
428 Node* array = Parameter(Descriptor::kArray); \ | |
429 Node* index = Parameter(Descriptor::kIndex); \ | |
430 Node* value = Parameter(Descriptor::kValue); \ | |
431 Node* context = Parameter(Descriptor::kContext); \ | |
432 AtomicBinopBuiltinCommon(array, index, value, context, \ | |
433 &CodeAssembler::Atomic##op, \ | |
434 Runtime::kAtomics##op); \ | |
435 } | |
436 BINOP_BUILTIN(Add) | |
437 BINOP_BUILTIN(Sub) | |
438 BINOP_BUILTIN(And) | |
439 BINOP_BUILTIN(Or) | |
440 BINOP_BUILTIN(Xor) | |
441 #undef BINOP_BUILTIN | |
442 | |
443 void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon( | |
444 Node* array, Node* index, Node* value, Node* context, | |
445 AssemblerFunction function, Runtime::FunctionId runtime_function) { | |
446 // The value_integer needs to be computed before the validations as the | |
447 // ToInteger function can be potentially modified in JS to invalidate the | |
448 // conditions. This is just a no-cost safety measure as SABs can't be neutered | |
449 // or shrunk. | |
450 Node* value_integer = ToInteger(context, value); | |
451 | |
452 Node* index_integer; | |
453 Node* index_word32 = | |
454 ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); | |
455 | |
456 Node* instance_type; | |
457 Node* backing_store; | |
458 ValidateSharedTypedArray(array, context, &instance_type, &backing_store); | |
459 | |
460 Node* array_length_word32 = TruncateTaggedToWord32( | |
461 context, LoadObjectField(array, JSTypedArray::kLengthOffset)); | |
462 ValidateAtomicIndex(index_word32, array_length_word32, context); | |
463 | |
464 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ | |
465 V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X | |
466 Return(CallRuntime(runtime_function, context, array, index_integer, | |
467 value_integer)); | |
468 #else | |
469 Node* index_word = ChangeUint32ToWord(index_word32); | |
470 | |
471 Node* value_word32 = TruncateTaggedToWord32(context, value_integer); | |
472 | |
473 Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this), | |
474 other(this); | |
475 int32_t case_values[] = { | |
476 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, | |
477 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, | |
478 }; | |
479 Label* case_labels[] = { | |
480 &i8, &u8, &i16, &u16, &i32, &u32, | |
481 }; | |
482 Switch(instance_type, &other, case_values, case_labels, | |
483 arraysize(case_labels)); | |
484 | |
485 Bind(&i8); | |
486 Return(SmiFromWord32((this->*function)(MachineType::Int8(), backing_store, | |
487 index_word, value_word32))); | |
488 | |
489 Bind(&u8); | |
490 Return(SmiFromWord32((this->*function)(MachineType::Uint8(), backing_store, | |
491 index_word, value_word32))); | |
492 | |
493 Bind(&i16); | |
494 Return( | |
495 SmiFromWord32((this->*function)(MachineType::Int16(), backing_store, | |
496 WordShl(index_word, 1), value_word32))); | |
497 | |
498 Bind(&u16); | |
499 Return( | |
500 SmiFromWord32((this->*function)(MachineType::Uint16(), backing_store, | |
501 WordShl(index_word, 1), value_word32))); | |
502 | |
503 Bind(&i32); | |
504 Return(ChangeInt32ToTagged( | |
505 (this->*function)(MachineType::Int32(), backing_store, | |
506 WordShl(index_word, 2), value_word32))); | |
507 | |
508 Bind(&u32); | |
509 Return(ChangeUint32ToTagged( | |
510 (this->*function)(MachineType::Uint32(), backing_store, | |
511 WordShl(index_word, 2), value_word32))); | |
512 | |
513 // This shouldn't happen, we've already validated the type. | |
514 Bind(&other); | |
515 Unreachable(); | |
516 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 | |
517 // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X | |
518 } | |
519 | |
405 } // namespace internal | 520 } // namespace internal |
406 } // namespace v8 | 521 } // namespace v8 |
OLD | NEW |