V8 Project
ic-x87.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #if V8_TARGET_ARCH_X87
8 
9 #include "src/codegen.h"
10 #include "src/ic/ic.h"
11 #include "src/ic/ic-compiler.h"
12 #include "src/ic/stub-cache.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 // ----------------------------------------------------------------------------
18 // Static IC stub generators.
19 //
20 
21 #define __ ACCESS_MASM(masm)
22 
23 
24 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type,
25  Label* global_object) {
26  // Register usage:
27  // type: holds the receiver instance type on entry.
28  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
29  __ j(equal, global_object);
30  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
31  __ j(equal, global_object);
32  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
33  __ j(equal, global_object);
34 }
35 
36 
37 // Helper function used to load a property from a dictionary backing
38 // storage. This function may fail to load a property even though it is
39 // in the dictionary, so code at miss_label must always call a backup
40 // property load that is complete. This function is safe to call if
41 // name is not internalized, and will jump to the miss_label in that
42 // case. The generated code assumes that the receiver has slow
43 // properties, is not a global object and does not have interceptors.
44 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
45  Register elements, Register name,
46  Register r0, Register r1, Register result) {
47  // Register use:
48  //
49  // elements - holds the property dictionary on entry and is unchanged.
50  //
51  // name - holds the name of the property on entry and is unchanged.
52  //
53  // Scratch registers:
54  //
55  // r0 - used for the index into the property dictionary
56  //
57  // r1 - used to hold the capacity of the property dictionary.
58  //
59  // result - holds the result on exit.
60 
61  Label done;
62 
63  // Probe the dictionary.
65  elements, name, r0, r1);
66 
67  // If probing finds an entry in the dictionary, r0 contains the
68  // index into the dictionary. Check that the value is a normal
69  // property.
70  __ bind(&done);
71  const int kElementsStartOffset =
74  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
75  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
76  Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
77  __ j(not_zero, miss_label);
78 
79  // Get the value at the masked, scaled index.
80  const int kValueOffset = kElementsStartOffset + kPointerSize;
81  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
82 }
83 
84 
85 // Helper function used to store a property to a dictionary backing
86 // storage. This function may fail to store a property eventhough it
87 // is in the dictionary, so code at miss_label must always call a
88 // backup property store that is complete. This function is safe to
89 // call if name is not internalized, and will jump to the miss_label in
90 // that case. The generated code assumes that the receiver has slow
91 // properties, is not a global object and does not have interceptors.
92 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
93  Register elements, Register name,
94  Register value, Register r0, Register r1) {
95  // Register use:
96  //
97  // elements - holds the property dictionary on entry and is clobbered.
98  //
99  // name - holds the name of the property on entry and is unchanged.
100  //
101  // value - holds the value to store and is unchanged.
102  //
103  // r0 - used for index into the property dictionary and is clobbered.
104  //
105  // r1 - used to hold the capacity of the property dictionary and is clobbered.
106  Label done;
107 
108 
109  // Probe the dictionary.
110  NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
111  elements, name, r0, r1);
112 
113  // If probing finds an entry in the dictionary, r0 contains the
114  // index into the dictionary. Check that the value is a normal
115  // property that is not read only.
116  __ bind(&done);
117  const int kElementsStartOffset =
120  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
121  const int kTypeAndReadOnlyMask =
122  (PropertyDetails::TypeField::kMask |
123  PropertyDetails::AttributesField::encode(READ_ONLY))
124  << kSmiTagSize;
125  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
126  Immediate(kTypeAndReadOnlyMask));
127  __ j(not_zero, miss_label);
128 
129  // Store the value at the masked, scaled index.
130  const int kValueOffset = kElementsStartOffset + kPointerSize;
131  __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
132  __ mov(Operand(r0, 0), value);
133 
134  // Update write barrier. Make sure not to clobber the value.
135  __ mov(r1, value);
136  __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
137 }
138 
139 
140 // Checks the receiver for special cases (value type, slow case bits).
141 // Falls through for regular JS object.
142 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
143  Register receiver, Register map,
144  int interceptor_bit, Label* slow) {
145  // Register use:
146  // receiver - holds the receiver and is unchanged.
147  // Scratch registers:
148  // map - used to hold the map of the receiver.
149 
150  // Check that the object isn't a smi.
151  __ JumpIfSmi(receiver, slow);
152 
153  // Get the map of the receiver.
154  __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
155 
156  // Check bit field.
158  (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
159  __ j(not_zero, slow);
160  // Check that the object is some kind of JS object EXCEPT JS Value type.
161  // In the case that the object is a value-wrapper object,
162  // we enter the runtime system to make sure that indexing
163  // into string objects works as intended.
165 
166  __ CmpInstanceType(map, JS_OBJECT_TYPE);
167  __ j(below, slow);
168 }
169 
170 
171 // Loads an indexed element from a fast case array.
172 // If not_fast_array is NULL, doesn't perform the elements map check.
173 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
174  Register key, Register scratch,
175  Register result, Label* not_fast_array,
176  Label* out_of_range) {
177  // Register use:
178  // receiver - holds the receiver and is unchanged.
179  // key - holds the key and is unchanged (must be a smi).
180  // Scratch registers:
181  // scratch - used to hold elements of the receiver and the loaded value.
182  // result - holds the result on exit if the load succeeds and
183  // we fall through.
184 
185  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
186  if (not_fast_array != NULL) {
187  // Check that the object is in fast mode and writable.
188  __ CheckMap(scratch,
189  masm->isolate()->factory()->fixed_array_map(),
190  not_fast_array,
192  } else {
193  __ AssertFastElements(scratch);
194  }
195  // Check that the key (index) is within bounds.
196  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
197  __ j(above_equal, out_of_range);
198  // Fast case: Do the load.
199  STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
200  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
201  __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value()));
202  // In case the loaded value is the_hole we have to consult GetProperty
203  // to ensure the prototype chain is searched.
204  __ j(equal, out_of_range);
205  if (!result.is(scratch)) {
206  __ mov(result, scratch);
207  }
208 }
209 
210 
211 // Checks whether a key is an array index string or a unique name.
212 // Falls through if the key is a unique name.
213 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
214  Register map, Register hash,
215  Label* index_string, Label* not_unique) {
216  // Register use:
217  // key - holds the key and is unchanged. Assumed to be non-smi.
218  // Scratch registers:
219  // map - used to hold the map of the key.
220  // hash - used to hold the hash of the key.
221  Label unique;
222  __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
223  __ j(above, not_unique);
225  __ j(equal, &unique);
226 
227  // Is the string an array index, with cached numeric value?
228  __ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
229  __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
230  __ j(zero, index_string);
231 
232  // Is the string internalized? We already know it's a string so a single
233  // bit test is enough.
237  __ j(not_zero, not_unique);
238 
239  __ bind(&unique);
240 }
241 
242 
243 static Operand GenerateMappedArgumentsLookup(
244  MacroAssembler* masm, Register object, Register key, Register scratch1,
245  Register scratch2, Label* unmapped_case, Label* slow_case) {
246  Heap* heap = masm->isolate()->heap();
247  Factory* factory = masm->isolate()->factory();
248 
249  // Check that the receiver is a JSObject. Because of the elements
250  // map check later, we do not need to check for interceptors or
251  // whether it requires access checks.
252  __ JumpIfSmi(object, slow_case);
253  // Check that the object is some kind of JSObject.
254  __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
255  __ j(below, slow_case);
256 
257  // Check that the key is a positive smi.
258  __ test(key, Immediate(0x80000001));
259  __ j(not_zero, slow_case);
260 
261  // Load the elements into scratch1 and check its map.
262  Handle<Map> arguments_map(heap->sloppy_arguments_elements_map());
263  __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
264  __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
265 
266  // Check if element is in the range of mapped arguments. If not, jump
267  // to the unmapped lookup with the parameter map in scratch1.
268  __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
269  __ sub(scratch2, Immediate(Smi::FromInt(2)));
270  __ cmp(key, scratch2);
271  __ j(above_equal, unmapped_case);
272 
273  // Load element index and check whether it is the hole.
274  const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
275  __ mov(scratch2,
276  FieldOperand(scratch1, key, times_half_pointer_size, kHeaderSize));
277  __ cmp(scratch2, factory->the_hole_value());
278  __ j(equal, unmapped_case);
279 
280  // Load value from context and return it. We can reuse scratch1 because
281  // we do not jump to the unmapped lookup (which requires the parameter
282  // map in scratch1).
283  const int kContextOffset = FixedArray::kHeaderSize;
284  __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
285  return FieldOperand(scratch1, scratch2, times_half_pointer_size,
287 }
288 
289 
290 static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
291  Register key,
292  Register parameter_map,
293  Register scratch,
294  Label* slow_case) {
295  // Element is in arguments backing store, which is referenced by the
296  // second element of the parameter_map.
297  const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
298  Register backing_store = parameter_map;
299  __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
300  Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
301  __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
302  __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
303  __ cmp(key, scratch);
304  __ j(greater_equal, slow_case);
305  return FieldOperand(backing_store, key, times_half_pointer_size,
307 }
308 
309 
310 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
311  // The return address is on the stack.
312  Label slow, check_name, index_smi, index_name, property_array_property;
313  Label probe_dictionary, check_number_dictionary;
314 
315  Register receiver = LoadDescriptor::ReceiverRegister();
316  Register key = LoadDescriptor::NameRegister();
317  DCHECK(receiver.is(edx));
318  DCHECK(key.is(ecx));
319 
320  // Check that the key is a smi.
321  __ JumpIfNotSmi(key, &check_name);
322  __ bind(&index_smi);
323  // Now the key is known to be a smi. This place is also jumped to from
324  // where a numeric string is converted to a smi.
325 
326  GenerateKeyedLoadReceiverCheck(masm, receiver, eax,
328 
329  // Check the receiver's map to see if it has fast elements.
330  __ CheckFastElements(eax, &check_number_dictionary);
331 
332  GenerateFastArrayLoad(masm, receiver, key, eax, eax, NULL, &slow);
333  Isolate* isolate = masm->isolate();
334  Counters* counters = isolate->counters();
335  __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
336  __ ret(0);
337 
338  __ bind(&check_number_dictionary);
339  __ mov(ebx, key);
340  __ SmiUntag(ebx);
341  __ mov(eax, FieldOperand(receiver, JSObject::kElementsOffset));
342 
343  // Check whether the elements is a number dictionary.
344  // ebx: untagged index
345  // eax: elements
346  __ CheckMap(eax, isolate->factory()->hash_table_map(), &slow,
348  Label slow_pop_receiver;
349  // Push receiver on the stack to free up a register for the dictionary
350  // probing.
351  __ push(receiver);
352  __ LoadFromNumberDictionary(&slow_pop_receiver, eax, key, ebx, edx, edi, eax);
353  // Pop receiver before returning.
354  __ pop(receiver);
355  __ ret(0);
356 
357  __ bind(&slow_pop_receiver);
358  // Pop the receiver from the stack and jump to runtime.
359  __ pop(receiver);
360 
361  __ bind(&slow);
362  // Slow case: jump to runtime.
363  __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
365 
366  __ bind(&check_name);
367  GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow);
368 
369  GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor,
370  &slow);
371 
372  // If the receiver is a fast-case object, check the keyed lookup
373  // cache. Otherwise probe the dictionary.
376  Immediate(isolate->factory()->hash_table_map()));
377  __ j(equal, &probe_dictionary);
378 
379  // The receiver's map is still in eax, compute the keyed lookup cache hash
380  // based on 32 bits of the map pointer and the string hash.
381  if (FLAG_debug_code) {
382  __ cmp(eax, FieldOperand(receiver, HeapObject::kMapOffset));
383  __ Check(equal, kMapIsNoLongerInEax);
384  }
385  __ mov(ebx, eax); // Keep the map around for later.
388  __ shr(edi, String::kHashShift);
389  __ xor_(eax, edi);
391 
392  // Load the key (consisting of map and internalized string) from the cache and
393  // check for match.
394  Label load_in_object_property;
395  static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
396  Label hit_on_nth_entry[kEntriesPerBucket];
397  ExternalReference cache_keys =
398  ExternalReference::keyed_lookup_cache_keys(masm->isolate());
399 
400  for (int i = 0; i < kEntriesPerBucket - 1; i++) {
401  Label try_next_entry;
402  __ mov(edi, eax);
403  __ shl(edi, kPointerSizeLog2 + 1);
404  if (i != 0) {
405  __ add(edi, Immediate(kPointerSize * i * 2));
406  }
407  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
408  __ j(not_equal, &try_next_entry);
409  __ add(edi, Immediate(kPointerSize));
410  __ cmp(key, Operand::StaticArray(edi, times_1, cache_keys));
411  __ j(equal, &hit_on_nth_entry[i]);
412  __ bind(&try_next_entry);
413  }
414 
415  __ lea(edi, Operand(eax, 1));
416  __ shl(edi, kPointerSizeLog2 + 1);
417  __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
418  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
419  __ j(not_equal, &slow);
420  __ add(edi, Immediate(kPointerSize));
421  __ cmp(key, Operand::StaticArray(edi, times_1, cache_keys));
422  __ j(not_equal, &slow);
423 
424  // Get field offset.
425  // ebx : receiver's map
426  // eax : lookup cache index
427  ExternalReference cache_field_offsets =
428  ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
429 
430  // Hit on nth entry.
431  for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
432  __ bind(&hit_on_nth_entry[i]);
433  if (i != 0) {
434  __ add(eax, Immediate(i));
435  }
436  __ mov(edi,
437  Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
439  __ sub(edi, eax);
440  __ j(above_equal, &property_array_property);
441  if (i != 0) {
442  __ jmp(&load_in_object_property);
443  }
444  }
445 
446  // Load in-object property.
447  __ bind(&load_in_object_property);
449  __ add(eax, edi);
450  __ mov(eax, FieldOperand(receiver, eax, times_pointer_size, 0));
451  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
452  __ ret(0);
453 
454  // Load property array property.
455  __ bind(&property_array_property);
457  __ mov(eax,
459  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
460  __ ret(0);
461 
462  // Do a quick inline probe of the receiver's dictionary, if it
463  // exists.
464  __ bind(&probe_dictionary);
465 
466  __ mov(eax, FieldOperand(receiver, JSObject::kMapOffset));
468  GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
469 
470  GenerateDictionaryLoad(masm, &slow, ebx, key, eax, edi, eax);
471  __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
472  __ ret(0);
473 
474  __ bind(&index_name);
475  __ IndexFromHash(ebx, key);
476  // Now jump to the place where smi keys are handled.
477  __ jmp(&index_smi);
478 }
479 
480 
481 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
482  // Return address is on the stack.
483  Label miss;
484 
485  Register receiver = LoadDescriptor::ReceiverRegister();
486  Register index = LoadDescriptor::NameRegister();
487  Register scratch = ebx;
488  DCHECK(!scratch.is(receiver) && !scratch.is(index));
489  Register result = eax;
490  DCHECK(!result.is(scratch));
491 
492  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
493  &miss, // When not a string.
494  &miss, // When not a number.
495  &miss, // When index out of range.
497  char_at_generator.GenerateFast(masm);
498  __ ret(0);
499 
500  StubRuntimeCallHelper call_helper;
501  char_at_generator.GenerateSlow(masm, call_helper);
502 
503  __ bind(&miss);
504  GenerateMiss(masm);
505 }
506 
507 
508 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
509  // Return address is on the stack.
510  Label slow, notin;
511  Register receiver = StoreDescriptor::ReceiverRegister();
512  Register name = StoreDescriptor::NameRegister();
513  Register value = StoreDescriptor::ValueRegister();
514  DCHECK(receiver.is(edx));
515  DCHECK(name.is(ecx));
516  DCHECK(value.is(eax));
517 
518  Operand mapped_location = GenerateMappedArgumentsLookup(
519  masm, receiver, name, ebx, edi, &notin, &slow);
520  __ mov(mapped_location, value);
521  __ lea(ecx, mapped_location);
522  __ mov(edx, value);
523  __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
524  __ Ret();
525  __ bind(&notin);
526  // The unmapped lookup expects that the parameter map is in ebx.
527  Operand unmapped_location =
528  GenerateUnmappedArgumentsLookup(masm, name, ebx, edi, &slow);
529  __ mov(unmapped_location, value);
530  __ lea(edi, unmapped_location);
531  __ mov(edx, value);
532  __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
533  __ Ret();
534  __ bind(&slow);
535  GenerateMiss(masm);
536 }
537 
538 
539 static void KeyedStoreGenerateGenericHelper(
540  MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
541  KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
542  Label transition_smi_elements;
543  Label finish_object_store, non_double_value, transition_double_elements;
544  Label fast_double_without_map_check;
545  Register receiver = StoreDescriptor::ReceiverRegister();
546  Register key = StoreDescriptor::NameRegister();
547  Register value = StoreDescriptor::ValueRegister();
548  DCHECK(receiver.is(edx));
549  DCHECK(key.is(ecx));
550  DCHECK(value.is(eax));
551  // key is a smi.
552  // ebx: FixedArray receiver->elements
553  // edi: receiver map
554  // Fast case: Do the store, could either Object or double.
555  __ bind(fast_object);
556  if (check_map == kCheckMap) {
558  __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
559  __ j(not_equal, fast_double);
560  }
561 
562  // HOLECHECK: guards "A[i] = V"
563  // We have to go to the runtime if the current value is the hole because
564  // there may be a callback on the element
565  Label holecheck_passed1;
566  __ cmp(FixedArrayElementOperand(ebx, key),
567  masm->isolate()->factory()->the_hole_value());
568  __ j(not_equal, &holecheck_passed1);
569  __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
570  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
571 
572  __ bind(&holecheck_passed1);
573 
574  // Smi stores don't require further checks.
575  Label non_smi_value;
576  __ JumpIfNotSmi(value, &non_smi_value);
577  if (increment_length == kIncrementLength) {
578  // Add 1 to receiver->length.
579  __ add(FieldOperand(receiver, JSArray::kLengthOffset),
580  Immediate(Smi::FromInt(1)));
581  }
582  // It's irrelevant whether array is smi-only or not when writing a smi.
583  __ mov(FixedArrayElementOperand(ebx, key), value);
584  __ ret(0);
585 
586  __ bind(&non_smi_value);
587  // Escape to elements kind transition case.
588  __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
589  __ CheckFastObjectElements(edi, &transition_smi_elements);
590 
591  // Fast elements array, store the value to the elements backing store.
592  __ bind(&finish_object_store);
593  if (increment_length == kIncrementLength) {
594  // Add 1 to receiver->length.
595  __ add(FieldOperand(receiver, JSArray::kLengthOffset),
596  Immediate(Smi::FromInt(1)));
597  }
598  __ mov(FixedArrayElementOperand(ebx, key), value);
599  // Update write barrier for the elements array address.
600  __ mov(edx, value); // Preserve the value which is returned.
601  __ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
603  __ ret(0);
604 
605  __ bind(fast_double);
606  if (check_map == kCheckMap) {
607  // Check for fast double array case. If this fails, call through to the
608  // runtime.
609  __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
610  __ j(not_equal, slow);
611  // If the value is a number, store it as a double in the FastDoubleElements
612  // array.
613  }
614 
615  // HOLECHECK: guards "A[i] double hole?"
616  // We have to see if the double version of the hole is present. If so
617  // go to the runtime.
619  __ cmp(FieldOperand(ebx, key, times_4, offset), Immediate(kHoleNanUpper32));
620  __ j(not_equal, &fast_double_without_map_check);
621  __ JumpIfDictionaryInPrototypeChain(receiver, ebx, edi, slow);
622  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
623 
624  __ bind(&fast_double_without_map_check);
625  __ StoreNumberToDoubleElements(value, ebx, key, edi,
626  &transition_double_elements, false);
627  if (increment_length == kIncrementLength) {
628  // Add 1 to receiver->length.
629  __ add(FieldOperand(receiver, JSArray::kLengthOffset),
630  Immediate(Smi::FromInt(1)));
631  }
632  __ ret(0);
633 
634  __ bind(&transition_smi_elements);
635  __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
636 
637  // Transition the array appropriately depending on the value type.
638  __ CheckMap(value, masm->isolate()->factory()->heap_number_map(),
639  &non_double_value, DONT_DO_SMI_CHECK);
640 
641  // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
642  // and complete the store.
643  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
644  FAST_DOUBLE_ELEMENTS, ebx, edi, slow);
647  ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
648  ebx, mode, slow);
649  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
650  __ jmp(&fast_double_without_map_check);
651 
652  __ bind(&non_double_value);
653  // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
654  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, ebx,
655  edi, slow);
658  masm, receiver, key, value, ebx, mode, slow);
659  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
660  __ jmp(&finish_object_store);
661 
662  __ bind(&transition_double_elements);
663  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
664  // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
665  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
666  __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
667  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
668  ebx, edi, slow);
671  value, ebx, mode, slow);
672  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
673  __ jmp(&finish_object_store);
674 }
675 
676 
677 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
678  StrictMode strict_mode) {
679  // Return address is on the stack.
680  Label slow, fast_object, fast_object_grow;
681  Label fast_double, fast_double_grow;
682  Label array, extra, check_if_double_array;
683  Register receiver = StoreDescriptor::ReceiverRegister();
684  Register key = StoreDescriptor::NameRegister();
685  DCHECK(receiver.is(edx));
686  DCHECK(key.is(ecx));
687 
688  // Check that the object isn't a smi.
689  __ JumpIfSmi(receiver, &slow);
690  // Get the map from the receiver.
691  __ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
692  // Check that the receiver does not require access checks and is not observed.
693  // The generic stub does not perform map checks or handle observed objects.
696  __ j(not_zero, &slow);
697  // Check that the key is a smi.
698  __ JumpIfNotSmi(key, &slow);
699  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
700  __ j(equal, &array);
701  // Check that the object is some kind of JSObject.
702  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
703  __ j(below, &slow);
704 
705  // Object case: Check key against length in the elements array.
706  // Key is a smi.
707  // edi: receiver map
708  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
709  // Check array bounds. Both the key and the length of FixedArray are smis.
711  __ j(below, &fast_object);
712 
713  // Slow case: call runtime.
714  __ bind(&slow);
716 
717  // Extra capacity case: Check if there is extra capacity to
718  // perform the store and update the length. Used for adding one
719  // element to the array by writing to array[array.length].
720  __ bind(&extra);
721  // receiver is a JSArray.
722  // key is a smi.
723  // ebx: receiver->elements, a FixedArray
724  // edi: receiver map
725  // flags: compare (key, receiver.length())
726  // do not leave holes in the array:
727  __ j(not_equal, &slow);
729  __ j(above_equal, &slow);
731  __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
732  __ j(not_equal, &check_if_double_array);
733  __ jmp(&fast_object_grow);
734 
735  __ bind(&check_if_double_array);
736  __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
737  __ j(not_equal, &slow);
738  __ jmp(&fast_double_grow);
739 
740  // Array case: Get the length and the elements array from the JS
741  // array. Check that the array is in fast mode (and writable); if it
742  // is the length is always a smi.
743  __ bind(&array);
744  // receiver is a JSArray.
745  // key is a smi.
746  // edi: receiver map
747  __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset));
748 
749  // Check the key against the length in the array and fall through to the
750  // common store code.
751  __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset)); // Compare smis.
752  __ j(above_equal, &extra);
753 
754  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow,
756  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
758 }
759 
760 
761 void LoadIC::GenerateNormal(MacroAssembler* masm) {
762  Register dictionary = eax;
763  DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
764  DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
765 
766  Label slow;
767 
770  GenerateDictionaryLoad(masm, &slow, dictionary,
772  __ ret(0);
773 
774  // Dictionary load failed, go slow (but don't miss).
775  __ bind(&slow);
777 }
778 
779 
780 static void LoadIC_PushArgs(MacroAssembler* masm) {
781  Register receiver = LoadDescriptor::ReceiverRegister();
782  Register name = LoadDescriptor::NameRegister();
783  DCHECK(!ebx.is(receiver) && !ebx.is(name));
784 
785  __ pop(ebx);
786  __ push(receiver);
787  __ push(name);
788  __ push(ebx);
789 }
790 
791 
792 void LoadIC::GenerateMiss(MacroAssembler* masm) {
793  // Return address is on the stack.
794  __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
795 
796  LoadIC_PushArgs(masm);
797 
798  // Perform tail call to the entry.
799  ExternalReference ref =
800  ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
801  __ TailCallExternalReference(ref, 2, 1);
802 }
803 
804 
805 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
806  // Return address is on the stack.
807  LoadIC_PushArgs(masm);
808 
809  // Perform tail call to the entry.
810  __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
811 }
812 
813 
814 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
815  // Return address is on the stack.
816  __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
817 
818  LoadIC_PushArgs(masm);
819 
820  // Perform tail call to the entry.
821  ExternalReference ref =
822  ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
823  __ TailCallExternalReference(ref, 2, 1);
824 }
825 
826 
827 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
828  // Return address is on the stack.
829  LoadIC_PushArgs(masm);
830 
831  // Perform tail call to the entry.
832  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
833 }
834 
835 
836 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
837  // Return address is on the stack.
839  Code::ComputeHandlerFlags(Code::STORE_IC));
840  masm->isolate()->stub_cache()->GenerateProbe(
843 
844  // Cache miss: Jump to runtime.
845  GenerateMiss(masm);
846 }
847 
848 
849 static void StoreIC_PushArgs(MacroAssembler* masm) {
850  Register receiver = StoreDescriptor::ReceiverRegister();
851  Register name = StoreDescriptor::NameRegister();
852  Register value = StoreDescriptor::ValueRegister();
853 
854  DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
855 
856  __ pop(ebx);
857  __ push(receiver);
858  __ push(name);
859  __ push(value);
860  __ push(ebx);
861 }
862 
863 
864 void StoreIC::GenerateMiss(MacroAssembler* masm) {
865  // Return address is on the stack.
866  StoreIC_PushArgs(masm);
867 
868  // Perform tail call to the entry.
869  ExternalReference ref =
870  ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
871  __ TailCallExternalReference(ref, 3, 1);
872 }
873 
874 
875 void StoreIC::GenerateNormal(MacroAssembler* masm) {
876  Label restore_miss;
877  Register receiver = StoreDescriptor::ReceiverRegister();
878  Register name = StoreDescriptor::NameRegister();
879  Register value = StoreDescriptor::ValueRegister();
880  Register dictionary = ebx;
881 
882  __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
883 
884  // A lot of registers are needed for storing to slow case
885  // objects. Push and restore receiver but rely on
886  // GenerateDictionaryStore preserving the value and name.
887  __ push(receiver);
888  GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
889  receiver, edi);
890  __ Drop(1);
891  Counters* counters = masm->isolate()->counters();
892  __ IncrementCounter(counters->store_normal_hit(), 1);
893  __ ret(0);
894 
895  __ bind(&restore_miss);
896  __ pop(receiver);
897  __ IncrementCounter(counters->store_normal_miss(), 1);
898  GenerateMiss(masm);
899 }
900 
901 
902 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
903  // Return address is on the stack.
904  StoreIC_PushArgs(masm);
905 
906  // Do tail-call to runtime routine.
907  ExternalReference ref =
908  ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
909  __ TailCallExternalReference(ref, 3, 1);
910 }
911 
912 
913 #undef __
914 
915 
917  switch (op) {
918  case Token::EQ_STRICT:
919  case Token::EQ:
920  return equal;
921  case Token::LT:
922  return less;
923  case Token::GT:
924  return greater;
925  case Token::LTE:
926  return less_equal;
927  case Token::GTE:
928  return greater_equal;
929  default:
930  UNREACHABLE();
931  return no_condition;
932  }
933 }
934 
935 
937  // The address of the instruction following the call.
938  Address test_instruction_address =
940 
941  // If the instruction following the call is not a test al, nothing
942  // was inlined.
943  return *test_instruction_address == Assembler::kTestAlByte;
944 }
945 
946 
947 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
948  // The address of the instruction following the call.
949  Address test_instruction_address =
951 
952  // If the instruction following the call is not a test al, nothing
953  // was inlined.
954  if (*test_instruction_address != Assembler::kTestAlByte) {
955  DCHECK(*test_instruction_address == Assembler::kNopByte);
956  return;
957  }
958 
959  Address delta_address = test_instruction_address + 1;
960  // The delta to the start of the map check instruction and the
961  // condition code uses at the patched jump.
962  uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
963  if (FLAG_trace_ic) {
964  PrintF("[ patching ic at %p, test=%p, delta=%d\n", address,
965  test_instruction_address, delta);
966  }
967 
968  // Patch with a short conditional jump. Enabling means switching from a short
969  // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
970  // reverse operation of that.
971  Address jmp_address = test_instruction_address - delta;
973  ? (*jmp_address == Assembler::kJncShortOpcode ||
974  *jmp_address == Assembler::kJcShortOpcode)
975  : (*jmp_address == Assembler::kJnzShortOpcode ||
976  *jmp_address == Assembler::kJzShortOpcode));
977  Condition cc =
978  (check == ENABLE_INLINED_SMI_CHECK)
979  ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
980  : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
981  *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
982 }
983 }
984 } // namespace v8::internal
985 
986 #endif // V8_TARGET_ARCH_X87
static AllocationSiteMode GetMode(ElementsKind boilerplate_elements_kind)
Definition: objects-inl.h:1591
static const byte kJnzShortOpcode
static const byte kNopByte
static const byte kJccShortPrefix
static const byte kJncShortOpcode
static const byte kTestAlByte
static const int kCallTargetAddressOffset
static const byte kJcShortOpcode
static const byte kJzShortOpcode
static Flags ComputeHandlerFlags(Kind handler_kind, StubType type=NORMAL, CacheHolderFlag holder=kCacheOnReceiver)
Definition: objects-inl.h:4975
static Flags RemoveTypeAndHolderFromFlags(Flags flags)
Definition: objects-inl.h:5012
uint32_t Flags
Definition: objects.h:4929
static bool HasInlinedSmiCode(Address address)
static Condition ComputeCondition(Token::Value op)
static void GenerateSmiToDouble(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static void GenerateMapChangeElementsTransition(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *allocation_memento_found)
static void GenerateDoubleToObject(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static const int kLengthOffset
Definition: objects.h:2392
static const int kHeaderSize
Definition: objects.h:2393
static const int kElementsStartIndex
Definition: objects.h:3274
static const int kMapOffset
Definition: objects.h:1427
Isolate * isolate() const
Definition: ic.h:136
Address address() const
Definition: ic-inl.h:19
Counters * counters()
Definition: isolate.h:857
Factory * factory()
Definition: isolate.h:982
static const int kLengthOffset
Definition: objects.h:10072
static const int kPropertiesOffset
Definition: objects.h:2193
static const int kElementsOffset
Definition: objects.h:2194
static void GenerateMiss(MacroAssembler *masm)
static void GenerateString(MacroAssembler *masm)
static void GenerateRuntimeGetProperty(MacroAssembler *masm)
static void GenerateGeneric(MacroAssembler *masm)
static const int kHashMask
Definition: heap.h:2255
static const int kCapacityMask
Definition: heap.h:2253
static const int kMapHashShift
Definition: heap.h:2254
static const int kEntriesPerBucket
Definition: heap.h:2256
static void GenerateMiss(MacroAssembler *masm)
static void GenerateSloppyArguments(MacroAssembler *masm)
static void GenerateGeneric(MacroAssembler *masm, StrictMode strict_mode)
static const Register ReceiverRegister()
static const Register NameRegister()
static void GenerateNormal(MacroAssembler *masm)
static void GenerateRuntimeGetProperty(MacroAssembler *masm)
static void GenerateMiss(MacroAssembler *masm)
static const int kHasIndexedInterceptor
Definition: objects.h:6243
static const int kBitFieldOffset
Definition: objects.h:6228
static const int kIsAccessCheckNeeded
Definition: objects.h:6246
static const int kInstanceTypeOffset
Definition: objects.h:6229
static const int kInstanceSizeOffset
Definition: objects.h:6210
static const int kInObjectPropertiesOffset
Definition: objects.h:6212
static const int kIsObserved
Definition: objects.h:6245
static const int kHasNamedInterceptor
Definition: objects.h:6242
static void GeneratePositiveLookup(MacroAssembler *masm, Label *miss, Label *done, Register elements, Register name, Register r0, Register r1)
static const int kHashShift
Definition: objects.h:8499
static const int kHashFieldOffset
Definition: objects.h:8486
static const unsigned int kContainsCachedArrayIndexMask
Definition: objects.h:8528
static void GenerateRuntimeSetProperty(MacroAssembler *masm, StrictMode strict_mode)
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const Register ReceiverRegister()
static const Register NameRegister()
static const Register ValueRegister()
static void GenerateMiss(MacroAssembler *masm)
static void GenerateMegamorphic(MacroAssembler *masm)
StrictMode strict_mode() const
Definition: ic.h:465
static void GenerateNormal(MacroAssembler *masm)
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
const int kPointerSize
Definition: globals.h:129
const Register edx
const Register edi
@ DONT_DO_SMI_CHECK
Definition: globals.h:640
const Register r0
const int kSmiTagSize
Definition: v8.h:5743
InlinedSmiCheck
Definition: ic.h:672
@ ENABLE_INLINED_SMI_CHECK
Definition: ic.h:672
Operand FieldOperand(Register object, int offset)
const uint32_t kNotInternalizedTag
Definition: objects.h:550
const int kPointerSizeLog2
Definition: globals.h:147
@ JS_VALUE_TYPE
Definition: objects.h:728
@ JS_GLOBAL_PROXY_TYPE
Definition: objects.h:737
@ JS_ARRAY_TYPE
Definition: objects.h:738
@ JS_OBJECT_TYPE
Definition: objects.h:731
@ FIRST_NONSTRING_TYPE
Definition: objects.h:758
@ FIRST_JS_RECEIVER_TYPE
Definition: objects.h:772
@ LAST_UNIQUE_NAME_TYPE
Definition: objects.h:757
@ FIRST_JS_OBJECT_TYPE
Definition: objects.h:775
@ JS_GLOBAL_OBJECT_TYPE
Definition: objects.h:735
@ JS_BUILTINS_OBJECT_TYPE
Definition: objects.h:736
void PatchInlinedSmiCode(Address address, InlinedSmiCheck check)
const Register eax
const Register ebx
byte * Address
Definition: globals.h:101
const Register r1
void PrintF(const char *format,...)
Definition: utils.cc:80
const int kHeapObjectTag
Definition: v8.h:5737
Operand FixedArrayElementOperand(Register array, Register index_as_smi, int additional_offset=0)
const Register no_reg
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const uint32_t kIsNotInternalizedMask
Definition: objects.h:549
const int kSmiTag
Definition: v8.h:5742
KeyedStoreCheckMap
Definition: ic.h:524
@ kDontCheckMap
Definition: ic.h:524
@ kCheckMap
Definition: ic.h:524
const uint32_t kHoleNanLower32
Definition: globals.h:657
@ STRING_INDEX_IS_ARRAY_INDEX
Definition: code-stubs.h:1595
const uint32_t kHoleNanUpper32
Definition: globals.h:656
const Register ecx
KeyedStoreIncrementLength
Definition: ic.h:527
@ kDontIncrementLength
Definition: ic.h:527
@ kIncrementLength
Definition: ic.h:527
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ READ_ONLY
bool is(Register reg) const