v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
stub-cache-ia32.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #if defined(V8_TARGET_ARCH_IA32)
31 
32 #include "ic-inl.h"
33 #include "codegen.h"
34 #include "stub-cache.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 #define __ ACCESS_MASM(masm)
40 
41 
42 static void ProbeTable(Isolate* isolate,
43  MacroAssembler* masm,
45  StubCache::Table table,
46  Register name,
47  Register receiver,
48  // Number of the cache entry pointer-size scaled.
49  Register offset,
50  Register extra) {
51  ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
52  ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
53  ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
54 
55  Label miss;
56 
57  // Multiply by 3 because there are 3 fields per entry (name, code, map).
58  __ lea(offset, Operand(offset, offset, times_2, 0));
59 
60  if (extra.is_valid()) {
61  // Get the code entry from the cache.
62  __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
63 
64  // Check that the key in the entry matches the name.
65  __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
66  __ j(not_equal, &miss);
67 
68  // Check the map matches.
69  __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
70  __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
71  __ j(not_equal, &miss);
72 
73  // Check that the flags match what we're looking for.
74  __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
75  __ and_(offset, ~Code::kFlagsNotUsedInLookup);
76  __ cmp(offset, flags);
77  __ j(not_equal, &miss);
78 
79 #ifdef DEBUG
80  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
81  __ jmp(&miss);
82  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
83  __ jmp(&miss);
84  }
85 #endif
86 
87  // Jump to the first instruction in the code stub.
88  __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
89  __ jmp(extra);
90 
91  __ bind(&miss);
92  } else {
93  // Save the offset on the stack.
94  __ push(offset);
95 
96  // Check that the key in the entry matches the name.
97  __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
98  __ j(not_equal, &miss);
99 
100  // Check the map matches.
101  __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
102  __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
103  __ j(not_equal, &miss);
104 
105  // Restore offset register.
106  __ mov(offset, Operand(esp, 0));
107 
108  // Get the code entry from the cache.
109  __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
110 
111  // Check that the flags match what we're looking for.
112  __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
113  __ and_(offset, ~Code::kFlagsNotUsedInLookup);
114  __ cmp(offset, flags);
115  __ j(not_equal, &miss);
116 
117 #ifdef DEBUG
118  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
119  __ jmp(&miss);
120  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
121  __ jmp(&miss);
122  }
123 #endif
124 
125  // Restore offset and re-load code entry from cache.
126  __ pop(offset);
127  __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
128 
129  // Jump to the first instruction in the code stub.
130  __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
131  __ jmp(offset);
132 
133  // Pop at miss.
134  __ bind(&miss);
135  __ pop(offset);
136  }
137 }
138 
139 
140 // Helper function used to check that the dictionary doesn't contain
141 // the property. This function may return false negatives, so miss_label
142 // must always call a backup property check that is complete.
143 // This function is safe to call if the receiver has fast properties.
144 // Name must be a symbol and receiver must be a heap object.
145 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
146  Label* miss_label,
147  Register receiver,
148  Handle<String> name,
149  Register r0,
150  Register r1) {
151  ASSERT(name->IsSymbol());
152  Counters* counters = masm->isolate()->counters();
153  __ IncrementCounter(counters->negative_lookups(), 1);
154  __ IncrementCounter(counters->negative_lookups_miss(), 1);
155 
156  __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
157 
158  const int kInterceptorOrAccessCheckNeededMask =
160 
161  // Bail out if the receiver has a named interceptor or requires access checks.
163  kInterceptorOrAccessCheckNeededMask);
164  __ j(not_zero, miss_label);
165 
166  // Check that receiver is a JSObject.
167  __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
168  __ j(below, miss_label);
169 
170  // Load properties array.
171  Register properties = r0;
172  __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
173 
174  // Check that the properties array is a dictionary.
175  __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
176  Immediate(masm->isolate()->factory()->hash_table_map()));
177  __ j(not_equal, miss_label);
178 
179  Label done;
181  miss_label,
182  &done,
183  properties,
184  name,
185  r1);
186  __ bind(&done);
187  __ DecrementCounter(counters->negative_lookups_miss(), 1);
188 }
189 
190 
191 void StubCache::GenerateProbe(MacroAssembler* masm,
192  Code::Flags flags,
193  Register receiver,
194  Register name,
195  Register scratch,
196  Register extra,
197  Register extra2,
198  Register extra3) {
199  Label miss;
200 
201  // Assert that code is valid. The multiplying code relies on the entry size
202  // being 12.
203  ASSERT(sizeof(Entry) == 12);
204 
205  // Assert the flags do not name a specific type.
206  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
207 
208  // Assert that there are no register conflicts.
209  ASSERT(!scratch.is(receiver));
210  ASSERT(!scratch.is(name));
211  ASSERT(!extra.is(receiver));
212  ASSERT(!extra.is(name));
213  ASSERT(!extra.is(scratch));
214 
215  // Assert scratch and extra registers are valid, and extra2/3 are unused.
216  ASSERT(!scratch.is(no_reg));
217  ASSERT(extra2.is(no_reg));
218  ASSERT(extra3.is(no_reg));
219 
220  Register offset = scratch;
221  scratch = no_reg;
222 
223  Counters* counters = masm->isolate()->counters();
224  __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
225 
226  // Check that the receiver isn't a smi.
227  __ JumpIfSmi(receiver, &miss);
228 
229  // Get the map of the receiver and compute the hash.
230  __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
231  __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
232  __ xor_(offset, flags);
233  // We mask out the last two bits because they are not part of the hash and
234  // they are always 01 for maps. Also in the two 'and' instructions below.
235  __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
236  // ProbeTable expects the offset to be pointer scaled, which it is, because
237  // the heap object tag size is 2 and the pointer size log 2 is also 2.
239 
240  // Probe the primary table.
241  ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
242 
243  // Primary miss: Compute hash for secondary probe.
244  __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
245  __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
246  __ xor_(offset, flags);
247  __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
248  __ sub(offset, name);
249  __ add(offset, Immediate(flags));
250  __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
251 
252  // Probe the secondary table.
253  ProbeTable(
254  isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
255 
256  // Cache miss: Fall-through and let caller handle the miss by
257  // entering the runtime system.
258  __ bind(&miss);
259  __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
260 }
261 
262 
263 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
264  int index,
265  Register prototype) {
266  __ LoadGlobalFunction(index, prototype);
267  __ LoadGlobalFunctionInitialMap(prototype, prototype);
268  // Load the prototype from the initial map.
269  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
270 }
271 
272 
273 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
274  MacroAssembler* masm,
275  int index,
276  Register prototype,
277  Label* miss) {
278  // Check we're still in the same context.
280  masm->isolate()->global_object());
281  __ j(not_equal, miss);
282  // Get the global function with the given index.
283  Handle<JSFunction> function(
284  JSFunction::cast(masm->isolate()->native_context()->get(index)));
285  // Load its initial map. The global functions all have initial maps.
286  __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
287  // Load the prototype from the initial map.
288  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
289 }
290 
291 
292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
293  Register receiver,
294  Register scratch,
295  Label* miss_label) {
296  // Check that the receiver isn't a smi.
297  __ JumpIfSmi(receiver, miss_label);
298 
299  // Check that the object is a JS array.
300  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
301  __ j(not_equal, miss_label);
302 
303  // Load length directly from the JS array.
304  __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
305  __ ret(0);
306 }
307 
308 
309 // Generate code to check if an object is a string. If the object is
310 // a string, the map's instance type is left in the scratch register.
311 static void GenerateStringCheck(MacroAssembler* masm,
312  Register receiver,
313  Register scratch,
314  Label* smi,
315  Label* non_string_object) {
316  // Check that the object isn't a smi.
317  __ JumpIfSmi(receiver, smi);
318 
319  // Check that the object is a string.
320  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
321  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
323  __ test(scratch, Immediate(kNotStringTag));
324  __ j(not_zero, non_string_object);
325 }
326 
327 
328 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
329  Register receiver,
330  Register scratch1,
331  Register scratch2,
332  Label* miss,
333  bool support_wrappers) {
334  Label check_wrapper;
335 
336  // Check if the object is a string leaving the instance type in the
337  // scratch register.
338  GenerateStringCheck(masm, receiver, scratch1, miss,
339  support_wrappers ? &check_wrapper : miss);
340 
341  // Load length from the string and convert to a smi.
342  __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
343  __ ret(0);
344 
345  if (support_wrappers) {
346  // Check if the object is a JSValue wrapper.
347  __ bind(&check_wrapper);
348  __ cmp(scratch1, JS_VALUE_TYPE);
349  __ j(not_equal, miss);
350 
351  // Check if the wrapped value is a string and load the length
352  // directly if it is.
353  __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
354  GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
355  __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
356  __ ret(0);
357  }
358 }
359 
360 
361 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
362  Register receiver,
363  Register scratch1,
364  Register scratch2,
365  Label* miss_label) {
366  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
367  __ mov(eax, scratch1);
368  __ ret(0);
369 }
370 
371 
372 // Load a fast property out of a holder object (src). In-object properties
373 // are loaded directly otherwise the property is loaded from the properties
374 // fixed array.
375 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
376  Register dst,
377  Register src,
378  Handle<JSObject> holder,
379  int index) {
380  // Adjust for the number of properties stored in the holder.
381  index -= holder->map()->inobject_properties();
382  if (index < 0) {
383  // Get the property straight out of the holder.
384  int offset = holder->map()->instance_size() + (index * kPointerSize);
385  __ mov(dst, FieldOperand(src, offset));
386  } else {
387  // Calculate the offset into the properties array.
388  int offset = index * kPointerSize + FixedArray::kHeaderSize;
390  __ mov(dst, FieldOperand(dst, offset));
391  }
392 }
393 
394 
395 static void PushInterceptorArguments(MacroAssembler* masm,
396  Register receiver,
397  Register holder,
398  Register name,
399  Handle<JSObject> holder_obj) {
400  __ push(name);
401  Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
402  ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
403  Register scratch = name;
404  __ mov(scratch, Immediate(interceptor));
405  __ push(scratch);
406  __ push(receiver);
407  __ push(holder);
409  __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
410 }
411 
412 
413 static void CompileCallLoadPropertyWithInterceptor(
414  MacroAssembler* masm,
415  Register receiver,
416  Register holder,
417  Register name,
418  Handle<JSObject> holder_obj) {
419  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
420  __ CallExternalReference(
421  ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
422  masm->isolate()),
423  6);
424 }
425 
426 
427 // Number of pointers to be reserved on stack for fast API call.
428 static const int kFastApiCallArguments = 4;
429 
430 
431 // Reserves space for the extra arguments to API function in the
432 // caller's frame.
433 //
434 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
435 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
436  // ----------- S t a t e -------------
437  // -- esp[0] : return address
438  // -- esp[4] : last argument in the internal frame of the caller
439  // -----------------------------------
440  __ pop(scratch);
441  for (int i = 0; i < kFastApiCallArguments; i++) {
442  __ push(Immediate(Smi::FromInt(0)));
443  }
444  __ push(scratch);
445 }
446 
447 
448 // Undoes the effects of ReserveSpaceForFastApiCall.
449 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
450  // ----------- S t a t e -------------
451  // -- esp[0] : return address.
452  // -- esp[4] : last fast api call extra argument.
453  // -- ...
454  // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
455  // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
456  // frame.
457  // -----------------------------------
458  __ pop(scratch);
459  __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
460  __ push(scratch);
461 }
462 
463 
464 // Generates call to API function.
465 static void GenerateFastApiCall(MacroAssembler* masm,
466  const CallOptimization& optimization,
467  int argc) {
468  // ----------- S t a t e -------------
469  // -- esp[0] : return address
470  // -- esp[4] : object passing the type check
471  // (last fast api call extra argument,
472  // set by CheckPrototypes)
473  // -- esp[8] : api function
474  // (first fast api call extra argument)
475  // -- esp[12] : api call data
476  // -- esp[16] : isolate
477  // -- esp[20] : last argument
478  // -- ...
479  // -- esp[(argc + 4) * 4] : first argument
480  // -- esp[(argc + 5) * 4] : receiver
481  // -----------------------------------
482  // Get the function and setup the context.
483  Handle<JSFunction> function = optimization.constant_function();
484  __ LoadHeapObject(edi, function);
486 
487  // Pass the additional arguments.
488  __ mov(Operand(esp, 2 * kPointerSize), edi);
489  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
490  Handle<Object> call_data(api_call_info->data());
491  if (masm->isolate()->heap()->InNewSpace(*call_data)) {
492  __ mov(ecx, api_call_info);
494  __ mov(Operand(esp, 3 * kPointerSize), ebx);
495  } else {
496  __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
497  }
498  __ mov(Operand(esp, 4 * kPointerSize),
499  Immediate(reinterpret_cast<int>(masm->isolate())));
500 
501  // Prepare arguments.
502  __ lea(eax, Operand(esp, 4 * kPointerSize));
503 
504  const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
505 
506  // Allocate the v8::Arguments structure in the arguments' space since
507  // it's not controlled by GC.
508  const int kApiStackSpace = 4;
509 
510  __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
511 
512  __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
513  __ add(eax, Immediate(argc * kPointerSize));
514  __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
515  __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
516  // v8::Arguments::is_construct_call_.
517  __ Set(ApiParameterOperand(4), Immediate(0));
518 
519  // v8::InvocationCallback's argument.
520  __ lea(eax, ApiParameterOperand(1));
521  __ mov(ApiParameterOperand(0), eax);
522 
523  // Function address is a foreign pointer outside V8's heap.
524  Address function_address = v8::ToCData<Address>(api_call_info->callback());
525  __ CallApiFunctionAndReturn(function_address,
526  argc + kFastApiCallArguments + 1);
527 }
528 
529 
530 class CallInterceptorCompiler BASE_EMBEDDED {
531  public:
532  CallInterceptorCompiler(StubCompiler* stub_compiler,
533  const ParameterCount& arguments,
534  Register name,
535  Code::ExtraICState extra_state)
536  : stub_compiler_(stub_compiler),
537  arguments_(arguments),
538  name_(name),
539  extra_state_(extra_state) {}
540 
541  void Compile(MacroAssembler* masm,
542  Handle<JSObject> object,
543  Handle<JSObject> holder,
544  Handle<String> name,
545  LookupResult* lookup,
546  Register receiver,
547  Register scratch1,
548  Register scratch2,
549  Register scratch3,
550  Label* miss) {
551  ASSERT(holder->HasNamedInterceptor());
552  ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
553 
554  // Check that the receiver isn't a smi.
555  __ JumpIfSmi(receiver, miss);
556 
557  CallOptimization optimization(lookup);
558  if (optimization.is_constant_call()) {
559  CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
560  holder, lookup, name, optimization, miss);
561  } else {
562  CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
563  name, holder, miss);
564  }
565  }
566 
567  private:
568  void CompileCacheable(MacroAssembler* masm,
569  Handle<JSObject> object,
570  Register receiver,
571  Register scratch1,
572  Register scratch2,
573  Register scratch3,
574  Handle<JSObject> interceptor_holder,
575  LookupResult* lookup,
576  Handle<String> name,
577  const CallOptimization& optimization,
578  Label* miss_label) {
579  ASSERT(optimization.is_constant_call());
580  ASSERT(!lookup->holder()->IsGlobalObject());
581 
582  int depth1 = kInvalidProtoDepth;
583  int depth2 = kInvalidProtoDepth;
584  bool can_do_fast_api_call = false;
585  if (optimization.is_simple_api_call() &&
586  !lookup->holder()->IsGlobalObject()) {
587  depth1 = optimization.GetPrototypeDepthOfExpectedType(
588  object, interceptor_holder);
589  if (depth1 == kInvalidProtoDepth) {
590  depth2 = optimization.GetPrototypeDepthOfExpectedType(
591  interceptor_holder, Handle<JSObject>(lookup->holder()));
592  }
593  can_do_fast_api_call =
594  depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
595  }
596 
597  Counters* counters = masm->isolate()->counters();
598  __ IncrementCounter(counters->call_const_interceptor(), 1);
599 
600  if (can_do_fast_api_call) {
601  __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
602  ReserveSpaceForFastApiCall(masm, scratch1);
603  }
604 
605  // Check that the maps from receiver to interceptor's holder
606  // haven't changed and thus we can invoke interceptor.
607  Label miss_cleanup;
608  Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
609  Register holder =
610  stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
611  scratch1, scratch2, scratch3,
612  name, depth1, miss);
613 
614  // Invoke an interceptor and if it provides a value,
615  // branch to |regular_invoke|.
616  Label regular_invoke;
617  LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
618  &regular_invoke);
619 
620  // Interceptor returned nothing for this property. Try to use cached
621  // constant function.
622 
623  // Check that the maps from interceptor's holder to constant function's
624  // holder haven't changed and thus we can use cached constant function.
625  if (*interceptor_holder != lookup->holder()) {
626  stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
627  Handle<JSObject>(lookup->holder()),
628  scratch1, scratch2, scratch3,
629  name, depth2, miss);
630  } else {
631  // CheckPrototypes has a side effect of fetching a 'holder'
632  // for API (object which is instanceof for the signature). It's
633  // safe to omit it here, as if present, it should be fetched
634  // by the previous CheckPrototypes.
635  ASSERT(depth2 == kInvalidProtoDepth);
636  }
637 
638  // Invoke function.
639  if (can_do_fast_api_call) {
640  GenerateFastApiCall(masm, optimization, arguments_.immediate());
641  } else {
642  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
644  : CALL_AS_METHOD;
645  __ InvokeFunction(optimization.constant_function(), arguments_,
646  JUMP_FUNCTION, NullCallWrapper(), call_kind);
647  }
648 
649  // Deferred code for fast API call case---clean preallocated space.
650  if (can_do_fast_api_call) {
651  __ bind(&miss_cleanup);
652  FreeSpaceForFastApiCall(masm, scratch1);
653  __ jmp(miss_label);
654  }
655 
656  // Invoke a regular function.
657  __ bind(&regular_invoke);
658  if (can_do_fast_api_call) {
659  FreeSpaceForFastApiCall(masm, scratch1);
660  }
661  }
662 
663  void CompileRegular(MacroAssembler* masm,
664  Handle<JSObject> object,
665  Register receiver,
666  Register scratch1,
667  Register scratch2,
668  Register scratch3,
669  Handle<String> name,
670  Handle<JSObject> interceptor_holder,
671  Label* miss_label) {
672  Register holder =
673  stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
674  scratch1, scratch2, scratch3,
675  name, miss_label);
676 
677  FrameScope scope(masm, StackFrame::INTERNAL);
678  // Save the name_ register across the call.
679  __ push(name_);
680 
681  PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
682 
683  __ CallExternalReference(
684  ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
685  masm->isolate()),
686  6);
687 
688  // Restore the name_ register.
689  __ pop(name_);
690 
691  // Leave the internal frame.
692  }
693 
694  void LoadWithInterceptor(MacroAssembler* masm,
695  Register receiver,
696  Register holder,
697  Handle<JSObject> holder_obj,
698  Label* interceptor_succeeded) {
699  {
700  FrameScope scope(masm, StackFrame::INTERNAL);
701  __ push(holder); // Save the holder.
702  __ push(name_); // Save the name.
703 
704  CompileCallLoadPropertyWithInterceptor(masm,
705  receiver,
706  holder,
707  name_,
708  holder_obj);
709 
710  __ pop(name_); // Restore the name.
711  __ pop(receiver); // Restore the holder.
712  // Leave the internal frame.
713  }
714 
715  __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
716  __ j(not_equal, interceptor_succeeded);
717  }
718 
719  StubCompiler* stub_compiler_;
720  const ParameterCount& arguments_;
721  Register name_;
722  Code::ExtraICState extra_state_;
723 };
724 
725 
726 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
727  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
728  Handle<Code> code = (kind == Code::LOAD_IC)
729  ? masm->isolate()->builtins()->LoadIC_Miss()
730  : masm->isolate()->builtins()->KeyedLoadIC_Miss();
731  __ jmp(code, RelocInfo::CODE_TARGET);
732 }
733 
734 
735 void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
736  Handle<Code> code =
737  masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
738  __ jmp(code, RelocInfo::CODE_TARGET);
739 }
740 
741 
742 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
743 // but may be destroyed if store is successful.
744 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
745  Handle<JSObject> object,
746  int index,
747  Handle<Map> transition,
748  Handle<String> name,
749  Register receiver_reg,
750  Register name_reg,
751  Register scratch1,
752  Register scratch2,
753  Label* miss_label) {
754  LookupResult lookup(masm->isolate());
755  object->Lookup(*name, &lookup);
756  if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
757  // In sloppy mode, we could just return the value and be done. However, we
758  // might be in strict mode, where we have to throw. Since we cannot tell,
759  // go into slow case unconditionally.
760  __ jmp(miss_label);
761  return;
762  }
763 
764  // Check that the map of the object hasn't changed.
765  CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
767  __ CheckMap(receiver_reg, Handle<Map>(object->map()),
768  miss_label, DO_SMI_CHECK, mode);
769 
770  // Perform global security token check if needed.
771  if (object->IsJSGlobalProxy()) {
772  __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
773  }
774 
775  // Check that we are allowed to write this.
776  if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
777  JSObject* holder;
778  if (lookup.IsFound()) {
779  holder = lookup.holder();
780  } else {
781  // Find the top object.
782  holder = *object;
783  do {
784  holder = JSObject::cast(holder->GetPrototype());
785  } while (holder->GetPrototype()->IsJSObject());
786  }
787  // We need an extra register, push
788  __ push(name_reg);
789  Label miss_pop, done_check;
790  CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
791  scratch1, scratch2, name, &miss_pop);
792  __ jmp(&done_check);
793  __ bind(&miss_pop);
794  __ pop(name_reg);
795  __ jmp(miss_label);
796  __ bind(&done_check);
797  __ pop(name_reg);
798  }
799 
800  // Stub never generated for non-global objects that require access
801  // checks.
802  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
803 
804  // Perform map transition for the receiver if necessary.
805  if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
806  // The properties must be extended before we can store the value.
807  // We jump to a runtime call that extends the properties array.
808  __ pop(scratch1); // Return address.
809  __ push(receiver_reg);
810  __ push(Immediate(transition));
811  __ push(eax);
812  __ push(scratch1);
813  __ TailCallExternalReference(
814  ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
815  masm->isolate()),
816  3,
817  1);
818  return;
819  }
820 
821  if (!transition.is_null()) {
822  // Update the map of the object.
823  __ mov(scratch1, Immediate(transition));
824  __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
825 
826  // Update the write barrier for the map field and pass the now unused
827  // name_reg as scratch register.
828  __ RecordWriteField(receiver_reg,
830  scratch1,
831  name_reg,
835  }
836 
837  // Adjust for the number of properties stored in the object. Even in the
838  // face of a transition we can use the old map here because the size of the
839  // object and the number of in-object properties is not going to change.
840  index -= object->map()->inobject_properties();
841 
842  if (index < 0) {
843  // Set the property straight into the object.
844  int offset = object->map()->instance_size() + (index * kPointerSize);
845  __ mov(FieldOperand(receiver_reg, offset), eax);
846 
847  // Update the write barrier for the array address.
848  // Pass the value being stored in the now unused name_reg.
849  __ mov(name_reg, eax);
850  __ RecordWriteField(receiver_reg,
851  offset,
852  name_reg,
853  scratch1,
855  } else {
856  // Write to the properties array.
857  int offset = index * kPointerSize + FixedArray::kHeaderSize;
858  // Get the properties array (optimistically).
859  __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
860  __ mov(FieldOperand(scratch1, offset), eax);
861 
862  // Update the write barrier for the array address.
863  // Pass the value being stored in the now unused name_reg.
864  __ mov(name_reg, eax);
865  __ RecordWriteField(scratch1,
866  offset,
867  name_reg,
868  receiver_reg,
870  }
871 
872  // Return the value (register eax).
873  __ ret(0);
874 }
875 
876 
877 // Generate code to check that a global property cell is empty. Create
878 // the property cell at compilation time if no cell exists for the
879 // property.
880 static void GenerateCheckPropertyCell(MacroAssembler* masm,
881  Handle<GlobalObject> global,
882  Handle<String> name,
883  Register scratch,
884  Label* miss) {
885  Handle<JSGlobalPropertyCell> cell =
886  GlobalObject::EnsurePropertyCell(global, name);
887  ASSERT(cell->value()->IsTheHole());
888  Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
889  if (Serializer::enabled()) {
890  __ mov(scratch, Immediate(cell));
892  Immediate(the_hole));
893  } else {
894  __ cmp(Operand::Cell(cell), Immediate(the_hole));
895  }
896  __ j(not_equal, miss);
897 }
898 
899 
900 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
901 // from object to (but not including) holder.
902 static void GenerateCheckPropertyCells(MacroAssembler* masm,
903  Handle<JSObject> object,
904  Handle<JSObject> holder,
905  Handle<String> name,
906  Register scratch,
907  Label* miss) {
908  Handle<JSObject> current = object;
909  while (!current.is_identical_to(holder)) {
910  if (current->IsGlobalObject()) {
911  GenerateCheckPropertyCell(masm,
912  Handle<GlobalObject>::cast(current),
913  name,
914  scratch,
915  miss);
916  }
917  current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
918  }
919 }
920 
921 #undef __
922 #define __ ACCESS_MASM(masm())
923 
924 
925 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
926  Register object_reg,
927  Handle<JSObject> holder,
928  Register holder_reg,
929  Register scratch1,
930  Register scratch2,
931  Handle<String> name,
932  int save_at_depth,
933  Label* miss) {
934  // Make sure there's no overlap between holder and object registers.
935  ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
936  ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
937  && !scratch2.is(scratch1));
938 
939  // Keep track of the current object in register reg.
940  Register reg = object_reg;
941  Handle<JSObject> current = object;
942  int depth = 0;
943 
944  if (save_at_depth == depth) {
945  __ mov(Operand(esp, kPointerSize), reg);
946  }
947 
948  // Traverse the prototype chain and check the maps in the prototype chain for
949  // fast and global objects or do negative lookup for normal objects.
950  while (!current.is_identical_to(holder)) {
951  ++depth;
952 
953  // Only global objects and objects that do not require access
954  // checks are allowed in stubs.
955  ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
956 
957  Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
958  if (!current->HasFastProperties() &&
959  !current->IsJSGlobalObject() &&
960  !current->IsJSGlobalProxy()) {
961  if (!name->IsSymbol()) {
962  name = factory()->LookupSymbol(name);
963  }
964  ASSERT(current->property_dictionary()->FindEntry(*name) ==
966 
967  GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
968  scratch1, scratch2);
969 
970  __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
971  reg = holder_reg; // From now on the object will be in holder_reg.
972  __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
973  } else {
974  bool in_new_space = heap()->InNewSpace(*prototype);
975  Handle<Map> current_map(current->map());
976  if (in_new_space) {
977  // Save the map in scratch1 for later.
978  __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
979  }
980  __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
982 
983  // Check access rights to the global object. This has to happen after
984  // the map check so that we know that the object is actually a global
985  // object.
986  if (current->IsJSGlobalProxy()) {
987  __ CheckAccessGlobalProxy(reg, scratch2, miss);
988  }
989  reg = holder_reg; // From now on the object will be in holder_reg.
990 
991  if (in_new_space) {
992  // The prototype is in new space; we cannot store a reference to it
993  // in the code. Load it from the map.
994  __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
995  } else {
996  // The prototype is in old space; load it directly.
997  __ mov(reg, prototype);
998  }
999  }
1000 
1001  if (save_at_depth == depth) {
1002  __ mov(Operand(esp, kPointerSize), reg);
1003  }
1004 
1005  // Go to the next object in the prototype chain.
1006  current = prototype;
1007  }
1008  ASSERT(current.is_identical_to(holder));
1009 
1010  // Log the check depth.
1011  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1012 
1013  // Check the holder map.
1014  __ CheckMap(reg, Handle<Map>(holder->map()),
1016 
1017  // Perform security check for access to the global object.
1018  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1019  if (holder->IsJSGlobalProxy()) {
1020  __ CheckAccessGlobalProxy(reg, scratch1, miss);
1021  }
1022 
1023  // If we've skipped any global objects, it's not enough to verify that
1024  // their maps haven't changed. We also need to check that the property
1025  // cell for the property is still empty.
1026  GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1027 
1028  // Return the register containing the holder.
1029  return reg;
1030 }
1031 
1032 
1033 void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1034  Handle<JSObject> holder,
1035  Register receiver,
1036  Register scratch1,
1037  Register scratch2,
1038  Register scratch3,
1039  int index,
1040  Handle<String> name,
1041  Label* miss) {
1042  // Check that the receiver isn't a smi.
1043  __ JumpIfSmi(receiver, miss);
1044 
1045  // Check the prototype chain.
1046  Register reg = CheckPrototypes(
1047  object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
1048 
1049  // Get the value from the properties.
1050  GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1051  __ ret(0);
1052 }
1053 
1054 
1055 void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1056  Register name_reg,
1057  Register scratch1,
1058  Register scratch2,
1059  Register scratch3,
1060  Handle<AccessorInfo> callback,
1061  Handle<String> name,
1062  Label* miss) {
1063  ASSERT(!receiver.is(scratch2));
1064  ASSERT(!receiver.is(scratch3));
1065  Register dictionary = scratch1;
1066  bool must_preserve_dictionary_reg = receiver.is(dictionary);
1067 
1068  // Load the properties dictionary.
1069  if (must_preserve_dictionary_reg) {
1070  __ push(dictionary);
1071  }
1072  __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
1073 
1074  // Probe the dictionary.
1075  Label probe_done, pop_and_miss;
1077  &pop_and_miss,
1078  &probe_done,
1079  dictionary,
1080  name_reg,
1081  scratch2,
1082  scratch3);
1083  __ bind(&pop_and_miss);
1084  if (must_preserve_dictionary_reg) {
1085  __ pop(dictionary);
1086  }
1087  __ jmp(miss);
1088  __ bind(&probe_done);
1089 
1090  // If probing finds an entry in the dictionary, scratch2 contains the
1091  // index into the dictionary. Check that the value is the callback.
1092  Register index = scratch2;
1093  const int kElementsStartOffset =
1096  const int kValueOffset = kElementsStartOffset + kPointerSize;
1097  __ mov(scratch3,
1098  Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1099  if (must_preserve_dictionary_reg) {
1100  __ pop(dictionary);
1101  }
1102  __ cmp(scratch3, callback);
1103  __ j(not_equal, miss);
1104 }
1105 
1106 
1107 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1108  Handle<JSObject> holder,
1109  Register receiver,
1110  Register name_reg,
1111  Register scratch1,
1112  Register scratch2,
1113  Register scratch3,
1114  Register scratch4,
1115  Handle<AccessorInfo> callback,
1116  Handle<String> name,
1117  Label* miss) {
1118  // Check that the receiver isn't a smi.
1119  __ JumpIfSmi(receiver, miss);
1120 
1121  // Check that the maps haven't changed.
1122  Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1123  scratch2, scratch3, name, miss);
1124 
1125  if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1126  GenerateDictionaryLoadCallback(
1127  reg, name_reg, scratch1, scratch2, scratch3, callback, name, miss);
1128  }
1129 
1130  // Insert additional parameters into the stack frame above return address.
1131  ASSERT(!scratch3.is(reg));
1132  __ pop(scratch3); // Get return address to place it below.
1133 
1134  __ push(receiver); // receiver
1135  __ mov(scratch2, esp);
1136  ASSERT(!scratch2.is(reg));
1137  __ push(reg); // holder
1138  // Push data from AccessorInfo.
1139  if (isolate()->heap()->InNewSpace(callback->data())) {
1140  __ mov(scratch1, Immediate(callback));
1141  __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
1142  } else {
1143  __ push(Immediate(Handle<Object>(callback->data())));
1144  }
1145  __ push(Immediate(reinterpret_cast<int>(isolate())));
1146 
1147  // Save a pointer to where we pushed the arguments pointer.
1148  // This will be passed as the const AccessorInfo& to the C++ callback.
1149  __ push(scratch2);
1150 
1151  __ push(name_reg); // name
1152  __ mov(ebx, esp); // esp points to reference to name (handler).
1153 
1154  __ push(scratch3); // Restore return address.
1155 
1156  // 4 elements array for v8::Arguments::values_, handler for name and pointer
1157  // to the values (it considered as smi in GC).
1158  const int kStackSpace = 6;
1159  const int kApiArgc = 2;
1160 
1161  __ PrepareCallApiFunction(kApiArgc);
1162  __ mov(ApiParameterOperand(0), ebx); // name.
1163  __ add(ebx, Immediate(kPointerSize));
1164  __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
1165 
1166  // Emitting a stub call may try to allocate (if the code is not
1167  // already generated). Do not allow the assembler to perform a
1168  // garbage collection but instead return the allocation failure
1169  // object.
1170  Address getter_address = v8::ToCData<Address>(callback->getter());
1171  __ CallApiFunctionAndReturn(getter_address, kStackSpace);
1172 }
1173 
1174 
1175 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1176  Handle<JSObject> holder,
1177  Register receiver,
1178  Register scratch1,
1179  Register scratch2,
1180  Register scratch3,
1181  Handle<JSFunction> value,
1182  Handle<String> name,
1183  Label* miss) {
1184  // Check that the receiver isn't a smi.
1185  __ JumpIfSmi(receiver, miss);
1186 
1187  // Check that the maps haven't changed.
1188  CheckPrototypes(
1189  object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
1190 
1191  // Return the constant value.
1192  __ LoadHeapObject(eax, value);
1193  __ ret(0);
1194 }
1195 
1196 
1197 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1198  Handle<JSObject> interceptor_holder,
1199  LookupResult* lookup,
1200  Register receiver,
1201  Register name_reg,
1202  Register scratch1,
1203  Register scratch2,
1204  Register scratch3,
1205  Handle<String> name,
1206  Label* miss) {
1207  ASSERT(interceptor_holder->HasNamedInterceptor());
1208  ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1209 
1210  // Check that the receiver isn't a smi.
1211  __ JumpIfSmi(receiver, miss);
1212 
1213  // So far the most popular follow ups for interceptor loads are FIELD
1214  // and CALLBACKS, so inline only them, other cases may be added
1215  // later.
1216  bool compile_followup_inline = false;
1217  if (lookup->IsFound() && lookup->IsCacheable()) {
1218  if (lookup->IsField()) {
1219  compile_followup_inline = true;
1220  } else if (lookup->type() == CALLBACKS &&
1221  lookup->GetCallbackObject()->IsAccessorInfo()) {
1222  AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1223  compile_followup_inline = callback->getter() != NULL &&
1224  callback->IsCompatibleReceiver(*object);
1225  }
1226  }
1227 
1228  if (compile_followup_inline) {
1229  // Compile the interceptor call, followed by inline code to load the
1230  // property from further up the prototype chain if the call fails.
1231  // Check that the maps haven't changed.
1232  Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1233  scratch1, scratch2, scratch3,
1234  name, miss);
1235  ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1236 
1237  // Preserve the receiver register explicitly whenever it is different from
1238  // the holder and it is needed should the interceptor return without any
1239  // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1240  // the FIELD case might cause a miss during the prototype check.
1241  bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1242  bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1243  (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1244 
1245  // Save necessary data before invoking an interceptor.
1246  // Requires a frame to make GC aware of pushed pointers.
1247  {
1248  FrameScope frame_scope(masm(), StackFrame::INTERNAL);
1249 
1250  if (must_preserve_receiver_reg) {
1251  __ push(receiver);
1252  }
1253  __ push(holder_reg);
1254  __ push(name_reg);
1255 
1256  // Invoke an interceptor. Note: map checks from receiver to
1257  // interceptor's holder has been compiled before (see a caller
1258  // of this method.)
1259  CompileCallLoadPropertyWithInterceptor(masm(),
1260  receiver,
1261  holder_reg,
1262  name_reg,
1263  interceptor_holder);
1264 
1265  // Check if interceptor provided a value for property. If it's
1266  // the case, return immediately.
1267  Label interceptor_failed;
1268  __ cmp(eax, factory()->no_interceptor_result_sentinel());
1269  __ j(equal, &interceptor_failed);
1270  frame_scope.GenerateLeaveFrame();
1271  __ ret(0);
1272 
1273  // Clobber registers when generating debug-code to provoke errors.
1274  __ bind(&interceptor_failed);
1275  if (FLAG_debug_code) {
1276  __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue)));
1277  __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
1278  __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue)));
1279  }
1280 
1281  __ pop(name_reg);
1282  __ pop(holder_reg);
1283  if (must_preserve_receiver_reg) {
1284  __ pop(receiver);
1285  }
1286 
1287  // Leave the internal frame.
1288  }
1289 
1290  // Check that the maps from interceptor's holder to lookup's holder
1291  // haven't changed. And load lookup's holder into holder_reg.
1292  if (must_perfrom_prototype_check) {
1293  holder_reg = CheckPrototypes(interceptor_holder,
1294  holder_reg,
1295  Handle<JSObject>(lookup->holder()),
1296  scratch1,
1297  scratch2,
1298  scratch3,
1299  name,
1300  miss);
1301  }
1302 
1303  if (lookup->IsField()) {
1304  // We found FIELD property in prototype chain of interceptor's holder.
1305  // Retrieve a field from field's holder.
1306  GenerateFastPropertyLoad(masm(), eax, holder_reg,
1307  Handle<JSObject>(lookup->holder()),
1308  lookup->GetFieldIndex());
1309  __ ret(0);
1310  } else {
1311  // We found CALLBACKS property in prototype chain of interceptor's
1312  // holder.
1313  ASSERT(lookup->type() == CALLBACKS);
1314  Handle<AccessorInfo> callback(
1315  AccessorInfo::cast(lookup->GetCallbackObject()));
1316  ASSERT(callback->getter() != NULL);
1317 
1318  // Tail call to runtime.
1319  // Important invariant in CALLBACKS case: the code above must be
1320  // structured to never clobber |receiver| register.
1321  __ pop(scratch2); // return address
1322  __ push(receiver);
1323  __ push(holder_reg);
1324  __ mov(holder_reg, Immediate(callback));
1325  __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
1326  __ push(Immediate(reinterpret_cast<int>(isolate())));
1327  __ push(holder_reg);
1328  __ push(name_reg);
1329  __ push(scratch2); // restore return address
1330 
1331  ExternalReference ref =
1332  ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1333  masm()->isolate());
1334  __ TailCallExternalReference(ref, 6, 1);
1335  }
1336  } else { // !compile_followup_inline
1337  // Call the runtime system to load the interceptor.
1338  // Check that the maps haven't changed.
1339  Register holder_reg =
1340  CheckPrototypes(object, receiver, interceptor_holder,
1341  scratch1, scratch2, scratch3, name, miss);
1342  __ pop(scratch2); // save old return address
1343  PushInterceptorArguments(masm(), receiver, holder_reg,
1344  name_reg, interceptor_holder);
1345  __ push(scratch2); // restore old return address
1346 
1347  ExternalReference ref =
1348  ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
1349  isolate());
1350  __ TailCallExternalReference(ref, 6, 1);
1351  }
1352 }
1353 
1354 
1355 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
1356  if (kind_ == Code::KEYED_CALL_IC) {
1357  __ cmp(ecx, Immediate(name));
1358  __ j(not_equal, miss);
1359  }
1360 }
1361 
1362 
1363 void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1364  Handle<JSObject> holder,
1365  Handle<String> name,
1366  Label* miss) {
1367  ASSERT(holder->IsGlobalObject());
1368 
1369  // Get the number of arguments.
1370  const int argc = arguments().immediate();
1371 
1372  // Get the receiver from the stack.
1373  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1374 
1375 
1376  // Check that the maps haven't changed.
1377  __ JumpIfSmi(edx, miss);
1378  CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1379 }
1380 
1381 
1382 void CallStubCompiler::GenerateLoadFunctionFromCell(
1383  Handle<JSGlobalPropertyCell> cell,
1384  Handle<JSFunction> function,
1385  Label* miss) {
1386  // Get the value from the cell.
1387  if (Serializer::enabled()) {
1388  __ mov(edi, Immediate(cell));
1390  } else {
1391  __ mov(edi, Operand::Cell(cell));
1392  }
1393 
1394  // Check that the cell contains the same function.
1395  if (isolate()->heap()->InNewSpace(*function)) {
1396  // We can't embed a pointer to a function in new space so we have
1397  // to verify that the shared function info is unchanged. This has
1398  // the nice side effect that multiple closures based on the same
1399  // function can all use this call IC. Before we load through the
1400  // function, we have to verify that it still is a function.
1401  __ JumpIfSmi(edi, miss);
1402  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1403  __ j(not_equal, miss);
1404 
1405  // Check the shared function info. Make sure it hasn't changed.
1407  Immediate(Handle<SharedFunctionInfo>(function->shared())));
1408  } else {
1409  __ cmp(edi, Immediate(function));
1410  }
1411  __ j(not_equal, miss);
1412 }
1413 
1414 
1415 void CallStubCompiler::GenerateMissBranch() {
1416  Handle<Code> code =
1417  isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1418  kind_,
1419  extra_state_);
1420  __ jmp(code, RelocInfo::CODE_TARGET);
1421 }
1422 
1423 
1424 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1425  Handle<JSObject> holder,
1426  int index,
1427  Handle<String> name) {
1428  // ----------- S t a t e -------------
1429  // -- ecx : name
1430  // -- esp[0] : return address
1431  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1432  // -- ...
1433  // -- esp[(argc + 1) * 4] : receiver
1434  // -----------------------------------
1435  Label miss;
1436 
1437  GenerateNameCheck(name, &miss);
1438 
1439  // Get the receiver from the stack.
1440  const int argc = arguments().immediate();
1441  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1442 
1443  // Check that the receiver isn't a smi.
1444  __ JumpIfSmi(edx, &miss);
1445 
1446  // Do the right check and compute the holder register.
1447  Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1448  name, &miss);
1449 
1450  GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
1451 
1452  // Check that the function really is a function.
1453  __ JumpIfSmi(edi, &miss);
1454  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1455  __ j(not_equal, &miss);
1456 
1457  // Patch the receiver on the stack with the global proxy if
1458  // necessary.
1459  if (object->IsGlobalObject()) {
1461  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1462  }
1463 
1464  // Invoke the function.
1465  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
1467  : CALL_AS_METHOD;
1468  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1469  NullCallWrapper(), call_kind);
1470 
1471  // Handle call cache miss.
1472  __ bind(&miss);
1473  GenerateMissBranch();
1474 
1475  // Return the generated code.
1476  return GetCode(Code::FIELD, name);
1477 }
1478 
1479 
1480 Handle<Code> CallStubCompiler::CompileArrayPushCall(
1481  Handle<Object> object,
1482  Handle<JSObject> holder,
1483  Handle<JSGlobalPropertyCell> cell,
1484  Handle<JSFunction> function,
1485  Handle<String> name) {
1486  // ----------- S t a t e -------------
1487  // -- ecx : name
1488  // -- esp[0] : return address
1489  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1490  // -- ...
1491  // -- esp[(argc + 1) * 4] : receiver
1492  // -----------------------------------
1493 
1494  // If object is not an array, bail out to regular call.
1495  if (!object->IsJSArray() || !cell.is_null()) {
1496  return Handle<Code>::null();
1497  }
1498 
1499  Label miss;
1500 
1501  GenerateNameCheck(name, &miss);
1502 
1503  // Get the receiver from the stack.
1504  const int argc = arguments().immediate();
1505  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1506 
1507  // Check that the receiver isn't a smi.
1508  __ JumpIfSmi(edx, &miss);
1509 
1510  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1511  name, &miss);
1512 
1513  if (argc == 0) {
1514  // Noop, return the length.
1516  __ ret((argc + 1) * kPointerSize);
1517  } else {
1518  Label call_builtin;
1519 
1520  if (argc == 1) { // Otherwise fall through to call builtin.
1521  Label attempt_to_grow_elements, with_write_barrier;
1522 
1523  // Get the elements array of the object.
1525 
1526  // Check that the elements are in fast mode and writable.
1528  Immediate(factory()->fixed_array_map()));
1529  __ j(not_equal, &call_builtin);
1530 
1531  // Get the array's length into eax and calculate new length.
1533  STATIC_ASSERT(kSmiTagSize == 1);
1534  STATIC_ASSERT(kSmiTag == 0);
1535  __ add(eax, Immediate(Smi::FromInt(argc)));
1536 
1537  // Get the elements' length into ecx.
1539 
1540  // Check if we could survive without allocation.
1541  __ cmp(eax, ecx);
1542  __ j(greater, &attempt_to_grow_elements);
1543 
1544  // Check if value is a smi.
1545  __ mov(ecx, Operand(esp, argc * kPointerSize));
1546  __ JumpIfNotSmi(ecx, &with_write_barrier);
1547 
1548  // Save new length.
1550 
1551  // Store the value.
1552  __ mov(FieldOperand(edi,
1553  eax,
1555  FixedArray::kHeaderSize - argc * kPointerSize),
1556  ecx);
1557 
1558  __ ret((argc + 1) * kPointerSize);
1559 
1560  __ bind(&with_write_barrier);
1561 
1563 
1564  if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1565  Label fast_object, not_fast_object;
1566  __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1567  __ jmp(&fast_object);
1568  // In case of fast smi-only, convert to fast object, otherwise bail out.
1569  __ bind(&not_fast_object);
1570  __ CheckFastSmiElements(ebx, &call_builtin);
1571  // edi: elements array
1572  // edx: receiver
1573  // ebx: map
1574  Label try_holey_map;
1575  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1576  FAST_ELEMENTS,
1577  ebx,
1578  edi,
1579  &try_holey_map);
1580 
1583  // Restore edi.
1585  __ jmp(&fast_object);
1586 
1587  __ bind(&try_holey_map);
1588  __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1590  ebx,
1591  edi,
1592  &call_builtin);
1595  // Restore edi.
1597  __ bind(&fast_object);
1598  } else {
1599  __ CheckFastObjectElements(ebx, &call_builtin);
1600  }
1601 
1602  // Save new length.
1604 
1605  // Store the value.
1606  __ lea(edx, FieldOperand(edi,
1608  FixedArray::kHeaderSize - argc * kPointerSize));
1609  __ mov(Operand(edx, 0), ecx);
1610 
1611  __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
1612  OMIT_SMI_CHECK);
1613 
1614  __ ret((argc + 1) * kPointerSize);
1615 
1616  __ bind(&attempt_to_grow_elements);
1617  if (!FLAG_inline_new) {
1618  __ jmp(&call_builtin);
1619  }
1620 
1621  __ mov(ebx, Operand(esp, argc * kPointerSize));
1622  // Growing elements that are SMI-only requires special handling in case
1623  // the new element is non-Smi. For now, delegate to the builtin.
1624  Label no_fast_elements_check;
1625  __ JumpIfSmi(ebx, &no_fast_elements_check);
1627  __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
1628  __ bind(&no_fast_elements_check);
1629 
1630  // We could be lucky and the elements array could be at the top of
1631  // new-space. In this case we can just grow it in place by moving the
1632  // allocation pointer up.
1633 
1634  ExternalReference new_space_allocation_top =
1635  ExternalReference::new_space_allocation_top_address(isolate());
1636  ExternalReference new_space_allocation_limit =
1637  ExternalReference::new_space_allocation_limit_address(isolate());
1638 
1639  const int kAllocationDelta = 4;
1640  // Load top.
1641  __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1642 
1643  // Check if it's the end of elements.
1644  __ lea(edx, FieldOperand(edi,
1646  FixedArray::kHeaderSize - argc * kPointerSize));
1647  __ cmp(edx, ecx);
1648  __ j(not_equal, &call_builtin);
1649  __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
1650  __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
1651  __ j(above, &call_builtin);
1652 
1653  // We fit and could grow elements.
1654  __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
1655 
1656  // Push the argument...
1657  __ mov(Operand(edx, 0), ebx);
1658  // ... and fill the rest with holes.
1659  for (int i = 1; i < kAllocationDelta; i++) {
1660  __ mov(Operand(edx, i * kPointerSize),
1661  Immediate(factory()->the_hole_value()));
1662  }
1663 
1664  // We know the elements array is in new space so we don't need the
1665  // remembered set, but we just pushed a value onto it so we may have to
1666  // tell the incremental marker to rescan the object that we just grew. We
1667  // don't need to worry about the holes because they are in old space and
1668  // already marked black.
1669  __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
1670 
1671  // Restore receiver to edx as finish sequence assumes it's here.
1672  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1673 
1674  // Increment element's and array's sizes.
1676  Immediate(Smi::FromInt(kAllocationDelta)));
1677 
1678  // NOTE: This only happen in new-space, where we don't
1679  // care about the black-byte-count on pages. Otherwise we should
1680  // update that too if the object is black.
1681 
1683 
1684  __ ret((argc + 1) * kPointerSize);
1685  }
1686 
1687  __ bind(&call_builtin);
1688  __ TailCallExternalReference(
1689  ExternalReference(Builtins::c_ArrayPush, isolate()),
1690  argc + 1,
1691  1);
1692  }
1693 
1694  __ bind(&miss);
1695  GenerateMissBranch();
1696 
1697  // Return the generated code.
1698  return GetCode(function);
1699 }
1700 
1701 
1702 Handle<Code> CallStubCompiler::CompileArrayPopCall(
1703  Handle<Object> object,
1704  Handle<JSObject> holder,
1705  Handle<JSGlobalPropertyCell> cell,
1706  Handle<JSFunction> function,
1707  Handle<String> name) {
1708  // ----------- S t a t e -------------
1709  // -- ecx : name
1710  // -- esp[0] : return address
1711  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1712  // -- ...
1713  // -- esp[(argc + 1) * 4] : receiver
1714  // -----------------------------------
1715 
1716  // If object is not an array, bail out to regular call.
1717  if (!object->IsJSArray() || !cell.is_null()) {
1718  return Handle<Code>::null();
1719  }
1720 
1721  Label miss, return_undefined, call_builtin;
1722 
1723  GenerateNameCheck(name, &miss);
1724 
1725  // Get the receiver from the stack.
1726  const int argc = arguments().immediate();
1727  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1728 
1729  // Check that the receiver isn't a smi.
1730  __ JumpIfSmi(edx, &miss);
1731  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1732  name, &miss);
1733 
1734  // Get the elements array of the object.
1736 
1737  // Check that the elements are in fast mode and writable.
1739  Immediate(factory()->fixed_array_map()));
1740  __ j(not_equal, &call_builtin);
1741 
1742  // Get the array's length into ecx and calculate new length.
1744  __ sub(ecx, Immediate(Smi::FromInt(1)));
1745  __ j(negative, &return_undefined);
1746 
1747  // Get the last element.
1748  STATIC_ASSERT(kSmiTagSize == 1);
1749  STATIC_ASSERT(kSmiTag == 0);
1750  __ mov(eax, FieldOperand(ebx,
1752  FixedArray::kHeaderSize));
1753  __ cmp(eax, Immediate(factory()->the_hole_value()));
1754  __ j(equal, &call_builtin);
1755 
1756  // Set the array's length.
1758 
1759  // Fill with the hole.
1760  __ mov(FieldOperand(ebx,
1762  FixedArray::kHeaderSize),
1763  Immediate(factory()->the_hole_value()));
1764  __ ret((argc + 1) * kPointerSize);
1765 
1766  __ bind(&return_undefined);
1767  __ mov(eax, Immediate(factory()->undefined_value()));
1768  __ ret((argc + 1) * kPointerSize);
1769 
1770  __ bind(&call_builtin);
1771  __ TailCallExternalReference(
1772  ExternalReference(Builtins::c_ArrayPop, isolate()),
1773  argc + 1,
1774  1);
1775 
1776  __ bind(&miss);
1777  GenerateMissBranch();
1778 
1779  // Return the generated code.
1780  return GetCode(function);
1781 }
1782 
1783 
1784 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1785  Handle<Object> object,
1786  Handle<JSObject> holder,
1787  Handle<JSGlobalPropertyCell> cell,
1788  Handle<JSFunction> function,
1789  Handle<String> name) {
1790  // ----------- S t a t e -------------
1791  // -- ecx : function name
1792  // -- esp[0] : return address
1793  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1794  // -- ...
1795  // -- esp[(argc + 1) * 4] : receiver
1796  // -----------------------------------
1797 
1798  // If object is not a string, bail out to regular call.
1799  if (!object->IsString() || !cell.is_null()) {
1800  return Handle<Code>::null();
1801  }
1802 
1803  const int argc = arguments().immediate();
1804 
1805  Label miss;
1806  Label name_miss;
1807  Label index_out_of_range;
1808  Label* index_out_of_range_label = &index_out_of_range;
1809 
1810  if (kind_ == Code::CALL_IC &&
1811  (CallICBase::StringStubState::decode(extra_state_) ==
1813  index_out_of_range_label = &miss;
1814  }
1815 
1816  GenerateNameCheck(name, &name_miss);
1817 
1818  // Check that the maps starting from the prototype haven't changed.
1819  GenerateDirectLoadGlobalFunctionPrototype(masm(),
1821  eax,
1822  &miss);
1823  ASSERT(!object.is_identical_to(holder));
1824  CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1825  eax, holder, ebx, edx, edi, name, &miss);
1826 
1827  Register receiver = ebx;
1828  Register index = edi;
1829  Register result = eax;
1830  __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1831  if (argc > 0) {
1832  __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1833  } else {
1834  __ Set(index, Immediate(factory()->undefined_value()));
1835  }
1836 
1837  StringCharCodeAtGenerator generator(receiver,
1838  index,
1839  result,
1840  &miss, // When not a string.
1841  &miss, // When not a number.
1842  index_out_of_range_label,
1844  generator.GenerateFast(masm());
1845  __ ret((argc + 1) * kPointerSize);
1846 
1847  StubRuntimeCallHelper call_helper;
1848  generator.GenerateSlow(masm(), call_helper);
1849 
1850  if (index_out_of_range.is_linked()) {
1851  __ bind(&index_out_of_range);
1852  __ Set(eax, Immediate(factory()->nan_value()));
1853  __ ret((argc + 1) * kPointerSize);
1854  }
1855 
1856  __ bind(&miss);
1857  // Restore function name in ecx.
1858  __ Set(ecx, Immediate(name));
1859  __ bind(&name_miss);
1860  GenerateMissBranch();
1861 
1862  // Return the generated code.
1863  return GetCode(function);
1864 }
1865 
1866 
1867 Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1868  Handle<Object> object,
1869  Handle<JSObject> holder,
1870  Handle<JSGlobalPropertyCell> cell,
1871  Handle<JSFunction> function,
1872  Handle<String> name) {
1873  // ----------- S t a t e -------------
1874  // -- ecx : function name
1875  // -- esp[0] : return address
1876  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1877  // -- ...
1878  // -- esp[(argc + 1) * 4] : receiver
1879  // -----------------------------------
1880 
1881  // If object is not a string, bail out to regular call.
1882  if (!object->IsString() || !cell.is_null()) {
1883  return Handle<Code>::null();
1884  }
1885 
1886  const int argc = arguments().immediate();
1887 
1888  Label miss;
1889  Label name_miss;
1890  Label index_out_of_range;
1891  Label* index_out_of_range_label = &index_out_of_range;
1892 
1893  if (kind_ == Code::CALL_IC &&
1894  (CallICBase::StringStubState::decode(extra_state_) ==
1896  index_out_of_range_label = &miss;
1897  }
1898 
1899  GenerateNameCheck(name, &name_miss);
1900 
1901  // Check that the maps starting from the prototype haven't changed.
1902  GenerateDirectLoadGlobalFunctionPrototype(masm(),
1904  eax,
1905  &miss);
1906  ASSERT(!object.is_identical_to(holder));
1907  CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1908  eax, holder, ebx, edx, edi, name, &miss);
1909 
1910  Register receiver = eax;
1911  Register index = edi;
1912  Register scratch = edx;
1913  Register result = eax;
1914  __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1915  if (argc > 0) {
1916  __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1917  } else {
1918  __ Set(index, Immediate(factory()->undefined_value()));
1919  }
1920 
1921  StringCharAtGenerator generator(receiver,
1922  index,
1923  scratch,
1924  result,
1925  &miss, // When not a string.
1926  &miss, // When not a number.
1927  index_out_of_range_label,
1929  generator.GenerateFast(masm());
1930  __ ret((argc + 1) * kPointerSize);
1931 
1932  StubRuntimeCallHelper call_helper;
1933  generator.GenerateSlow(masm(), call_helper);
1934 
1935  if (index_out_of_range.is_linked()) {
1936  __ bind(&index_out_of_range);
1937  __ Set(eax, Immediate(factory()->empty_string()));
1938  __ ret((argc + 1) * kPointerSize);
1939  }
1940 
1941  __ bind(&miss);
1942  // Restore function name in ecx.
1943  __ Set(ecx, Immediate(name));
1944  __ bind(&name_miss);
1945  GenerateMissBranch();
1946 
1947  // Return the generated code.
1948  return GetCode(function);
1949 }
1950 
1951 
1952 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1953  Handle<Object> object,
1954  Handle<JSObject> holder,
1955  Handle<JSGlobalPropertyCell> cell,
1956  Handle<JSFunction> function,
1957  Handle<String> name) {
1958  // ----------- S t a t e -------------
1959  // -- ecx : function name
1960  // -- esp[0] : return address
1961  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1962  // -- ...
1963  // -- esp[(argc + 1) * 4] : receiver
1964  // -----------------------------------
1965 
1966  const int argc = arguments().immediate();
1967 
1968  // If the object is not a JSObject or we got an unexpected number of
1969  // arguments, bail out to the regular call.
1970  if (!object->IsJSObject() || argc != 1) {
1971  return Handle<Code>::null();
1972  }
1973 
1974  Label miss;
1975  GenerateNameCheck(name, &miss);
1976 
1977  if (cell.is_null()) {
1978  __ mov(edx, Operand(esp, 2 * kPointerSize));
1979  STATIC_ASSERT(kSmiTag == 0);
1980  __ JumpIfSmi(edx, &miss);
1981  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1982  name, &miss);
1983  } else {
1984  ASSERT(cell->value() == *function);
1985  GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1986  &miss);
1987  GenerateLoadFunctionFromCell(cell, function, &miss);
1988  }
1989 
1990  // Load the char code argument.
1991  Register code = ebx;
1992  __ mov(code, Operand(esp, 1 * kPointerSize));
1993 
1994  // Check the code is a smi.
1995  Label slow;
1996  STATIC_ASSERT(kSmiTag == 0);
1997  __ JumpIfNotSmi(code, &slow);
1998 
1999  // Convert the smi code to uint16.
2000  __ and_(code, Immediate(Smi::FromInt(0xffff)));
2001 
2002  StringCharFromCodeGenerator generator(code, eax);
2003  generator.GenerateFast(masm());
2004  __ ret(2 * kPointerSize);
2005 
2006  StubRuntimeCallHelper call_helper;
2007  generator.GenerateSlow(masm(), call_helper);
2008 
2009  // Tail call the full function. We do not have to patch the receiver
2010  // because the function makes no use of it.
2011  __ bind(&slow);
2012  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2014  : CALL_AS_METHOD;
2015  __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2016  NullCallWrapper(), call_kind);
2017 
2018  __ bind(&miss);
2019  // ecx: function name.
2020  GenerateMissBranch();
2021 
2022  // Return the generated code.
2023  return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
2024 }
2025 
2026 
2027 Handle<Code> CallStubCompiler::CompileMathFloorCall(
2028  Handle<Object> object,
2029  Handle<JSObject> holder,
2030  Handle<JSGlobalPropertyCell> cell,
2031  Handle<JSFunction> function,
2032  Handle<String> name) {
2033  // ----------- S t a t e -------------
2034  // -- ecx : name
2035  // -- esp[0] : return address
2036  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2037  // -- ...
2038  // -- esp[(argc + 1) * 4] : receiver
2039  // -----------------------------------
2040 
2042  return Handle<Code>::null();
2043  }
2044 
2045  CpuFeatures::Scope use_sse2(SSE2);
2046 
2047  const int argc = arguments().immediate();
2048 
2049  // If the object is not a JSObject or we got an unexpected number of
2050  // arguments, bail out to the regular call.
2051  if (!object->IsJSObject() || argc != 1) {
2052  return Handle<Code>::null();
2053  }
2054 
2055  Label miss;
2056  GenerateNameCheck(name, &miss);
2057 
2058  if (cell.is_null()) {
2059  __ mov(edx, Operand(esp, 2 * kPointerSize));
2060 
2061  STATIC_ASSERT(kSmiTag == 0);
2062  __ JumpIfSmi(edx, &miss);
2063 
2064  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2065  name, &miss);
2066  } else {
2067  ASSERT(cell->value() == *function);
2068  GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2069  &miss);
2070  GenerateLoadFunctionFromCell(cell, function, &miss);
2071  }
2072 
2073  // Load the (only) argument into eax.
2074  __ mov(eax, Operand(esp, 1 * kPointerSize));
2075 
2076  // Check if the argument is a smi.
2077  Label smi;
2078  STATIC_ASSERT(kSmiTag == 0);
2079  __ JumpIfSmi(eax, &smi);
2080 
2081  // Check if the argument is a heap number and load its value into xmm0.
2082  Label slow;
2083  __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2085 
2086  // Check if the argument is strictly positive. Note this also
2087  // discards NaN.
2088  __ xorpd(xmm1, xmm1);
2089  __ ucomisd(xmm0, xmm1);
2090  __ j(below_equal, &slow);
2091 
2092  // Do a truncating conversion.
2093  __ cvttsd2si(eax, Operand(xmm0));
2094 
2095  // Check if the result fits into a smi. Note this also checks for
2096  // 0x80000000 which signals a failed conversion.
2097  Label wont_fit_into_smi;
2098  __ test(eax, Immediate(0xc0000000));
2099  __ j(not_zero, &wont_fit_into_smi);
2100 
2101  // Smi tag and return.
2102  __ SmiTag(eax);
2103  __ bind(&smi);
2104  __ ret(2 * kPointerSize);
2105 
2106  // Check if the argument is < 2^kMantissaBits.
2107  Label already_round;
2108  __ bind(&wont_fit_into_smi);
2109  __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2110  __ ucomisd(xmm0, xmm1);
2111  __ j(above_equal, &already_round);
2112 
2113  // Save a copy of the argument.
2114  __ movaps(xmm2, xmm0);
2115 
2116  // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2117  __ addsd(xmm0, xmm1);
2118  __ subsd(xmm0, xmm1);
2119 
2120  // Compare the argument and the tentative result to get the right mask:
2121  // if xmm2 < xmm0:
2122  // xmm2 = 1...1
2123  // else:
2124  // xmm2 = 0...0
2125  __ cmpltsd(xmm2, xmm0);
2126 
2127  // Subtract 1 if the argument was less than the tentative result.
2128  __ LoadPowerOf2(xmm1, ebx, 0);
2129  __ andpd(xmm1, xmm2);
2130  __ subsd(xmm0, xmm1);
2131 
2132  // Return a new heap number.
2133  __ AllocateHeapNumber(eax, ebx, edx, &slow);
2135  __ ret(2 * kPointerSize);
2136 
2137  // Return the argument (when it's an already round heap number).
2138  __ bind(&already_round);
2139  __ mov(eax, Operand(esp, 1 * kPointerSize));
2140  __ ret(2 * kPointerSize);
2141 
2142  // Tail call the full function. We do not have to patch the receiver
2143  // because the function makes no use of it.
2144  __ bind(&slow);
2145  __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2146  NullCallWrapper(), CALL_AS_METHOD);
2147 
2148  __ bind(&miss);
2149  // ecx: function name.
2150  GenerateMissBranch();
2151 
2152  // Return the generated code.
2153  return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
2154 }
2155 
2156 
2157 Handle<Code> CallStubCompiler::CompileMathAbsCall(
2158  Handle<Object> object,
2159  Handle<JSObject> holder,
2160  Handle<JSGlobalPropertyCell> cell,
2161  Handle<JSFunction> function,
2162  Handle<String> name) {
2163  // ----------- S t a t e -------------
2164  // -- ecx : name
2165  // -- esp[0] : return address
2166  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2167  // -- ...
2168  // -- esp[(argc + 1) * 4] : receiver
2169  // -----------------------------------
2170 
2171  const int argc = arguments().immediate();
2172 
2173  // If the object is not a JSObject or we got an unexpected number of
2174  // arguments, bail out to the regular call.
2175  if (!object->IsJSObject() || argc != 1) {
2176  return Handle<Code>::null();
2177  }
2178 
2179  Label miss;
2180  GenerateNameCheck(name, &miss);
2181 
2182  if (cell.is_null()) {
2183  __ mov(edx, Operand(esp, 2 * kPointerSize));
2184 
2185  STATIC_ASSERT(kSmiTag == 0);
2186  __ JumpIfSmi(edx, &miss);
2187 
2188  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2189  name, &miss);
2190  } else {
2191  ASSERT(cell->value() == *function);
2192  GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2193  &miss);
2194  GenerateLoadFunctionFromCell(cell, function, &miss);
2195  }
2196 
2197  // Load the (only) argument into eax.
2198  __ mov(eax, Operand(esp, 1 * kPointerSize));
2199 
2200  // Check if the argument is a smi.
2201  Label not_smi;
2202  STATIC_ASSERT(kSmiTag == 0);
2203  __ JumpIfNotSmi(eax, &not_smi);
2204 
2205  // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2206  // otherwise.
2207  __ mov(ebx, eax);
2208  __ sar(ebx, kBitsPerInt - 1);
2209 
2210  // Do bitwise not or do nothing depending on ebx.
2211  __ xor_(eax, ebx);
2212 
2213  // Add 1 or do nothing depending on ebx.
2214  __ sub(eax, ebx);
2215 
2216  // If the result is still negative, go to the slow case.
2217  // This only happens for the most negative smi.
2218  Label slow;
2219  __ j(negative, &slow);
2220 
2221  // Smi case done.
2222  __ ret(2 * kPointerSize);
2223 
2224  // Check if the argument is a heap number and load its exponent and
2225  // sign into ebx.
2226  __ bind(&not_smi);
2227  __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2229 
2230  // Check the sign of the argument. If the argument is positive,
2231  // just return it.
2232  Label negative_sign;
2233  __ test(ebx, Immediate(HeapNumber::kSignMask));
2234  __ j(not_zero, &negative_sign);
2235  __ ret(2 * kPointerSize);
2236 
2237  // If the argument is negative, clear the sign, and return a new
2238  // number.
2239  __ bind(&negative_sign);
2240  __ and_(ebx, ~HeapNumber::kSignMask);
2242  __ AllocateHeapNumber(eax, edi, edx, &slow);
2245  __ ret(2 * kPointerSize);
2246 
2247  // Tail call the full function. We do not have to patch the receiver
2248  // because the function makes no use of it.
2249  __ bind(&slow);
2250  __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2251  NullCallWrapper(), CALL_AS_METHOD);
2252 
2253  __ bind(&miss);
2254  // ecx: function name.
2255  GenerateMissBranch();
2256 
2257  // Return the generated code.
2258  return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
2259 }
2260 
2261 
2262 Handle<Code> CallStubCompiler::CompileFastApiCall(
2263  const CallOptimization& optimization,
2264  Handle<Object> object,
2265  Handle<JSObject> holder,
2266  Handle<JSGlobalPropertyCell> cell,
2267  Handle<JSFunction> function,
2268  Handle<String> name) {
2269  ASSERT(optimization.is_simple_api_call());
2270  // Bail out if object is a global object as we don't want to
2271  // repatch it to global receiver.
2272  if (object->IsGlobalObject()) return Handle<Code>::null();
2273  if (!cell.is_null()) return Handle<Code>::null();
2274  if (!object->IsJSObject()) return Handle<Code>::null();
2275  int depth = optimization.GetPrototypeDepthOfExpectedType(
2276  Handle<JSObject>::cast(object), holder);
2277  if (depth == kInvalidProtoDepth) return Handle<Code>::null();
2278 
2279  Label miss, miss_before_stack_reserved;
2280 
2281  GenerateNameCheck(name, &miss_before_stack_reserved);
2282 
2283  // Get the receiver from the stack.
2284  const int argc = arguments().immediate();
2285  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2286 
2287  // Check that the receiver isn't a smi.
2288  __ JumpIfSmi(edx, &miss_before_stack_reserved);
2289 
2290  Counters* counters = isolate()->counters();
2291  __ IncrementCounter(counters->call_const(), 1);
2292  __ IncrementCounter(counters->call_const_fast_api(), 1);
2293 
2294  // Allocate space for v8::Arguments implicit values. Must be initialized
2295  // before calling any runtime function.
2296  __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
2297 
2298  // Check that the maps haven't changed and find a Holder as a side effect.
2299  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2300  name, depth, &miss);
2301 
2302  // Move the return address on top of the stack.
2303  __ mov(eax, Operand(esp, 4 * kPointerSize));
2304  __ mov(Operand(esp, 0 * kPointerSize), eax);
2305 
2306  // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2307  // duplicate of return address and will be overwritten.
2308  GenerateFastApiCall(masm(), optimization, argc);
2309 
2310  __ bind(&miss);
2311  __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
2312 
2313  __ bind(&miss_before_stack_reserved);
2314  GenerateMissBranch();
2315 
2316  // Return the generated code.
2317  return GetCode(function);
2318 }
2319 
2320 
2321 Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2322  Handle<JSObject> holder,
2323  Handle<JSFunction> function,
2324  Handle<String> name,
2325  CheckType check) {
2326  // ----------- S t a t e -------------
2327  // -- ecx : name
2328  // -- esp[0] : return address
2329  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2330  // -- ...
2331  // -- esp[(argc + 1) * 4] : receiver
2332  // -----------------------------------
2333 
2334  if (HasCustomCallGenerator(function)) {
2335  Handle<Code> code = CompileCustomCall(object, holder,
2336  Handle<JSGlobalPropertyCell>::null(),
2337  function, name);
2338  // A null handle means bail out to the regular compiler code below.
2339  if (!code.is_null()) return code;
2340  }
2341 
2342  Label miss;
2343  GenerateNameCheck(name, &miss);
2344 
2345  // Get the receiver from the stack.
2346  const int argc = arguments().immediate();
2347  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2348 
2349  // Check that the receiver isn't a smi.
2350  if (check != NUMBER_CHECK) {
2351  __ JumpIfSmi(edx, &miss);
2352  }
2353 
2354  // Make sure that it's okay not to patch the on stack receiver
2355  // unless we're doing a receiver map check.
2356  ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2357  switch (check) {
2358  case RECEIVER_MAP_CHECK:
2359  __ IncrementCounter(isolate()->counters()->call_const(), 1);
2360 
2361  // Check that the maps haven't changed.
2362  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2363  edi, name, &miss);
2364 
2365  // Patch the receiver on the stack with the global proxy if
2366  // necessary.
2367  if (object->IsGlobalObject()) {
2369  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2370  }
2371  break;
2372 
2373  case STRING_CHECK:
2374  if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2375  // Check that the object is a string or a symbol.
2376  __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2377  __ j(above_equal, &miss);
2378  // Check that the maps starting from the prototype haven't changed.
2379  GenerateDirectLoadGlobalFunctionPrototype(
2380  masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2381  CheckPrototypes(
2382  Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2383  eax, holder, ebx, edx, edi, name, &miss);
2384  } else {
2385  // Calling non-strict non-builtins with a value as the receiver
2386  // requires boxing.
2387  __ jmp(&miss);
2388  }
2389  break;
2390 
2391  case NUMBER_CHECK:
2392  if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2393  Label fast;
2394  // Check that the object is a smi or a heap number.
2395  __ JumpIfSmi(edx, &fast);
2396  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2397  __ j(not_equal, &miss);
2398  __ bind(&fast);
2399  // Check that the maps starting from the prototype haven't changed.
2400  GenerateDirectLoadGlobalFunctionPrototype(
2401  masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2402  CheckPrototypes(
2403  Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2404  eax, holder, ebx, edx, edi, name, &miss);
2405  } else {
2406  // Calling non-strict non-builtins with a value as the receiver
2407  // requires boxing.
2408  __ jmp(&miss);
2409  }
2410  break;
2411 
2412  case BOOLEAN_CHECK:
2413  if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
2414  Label fast;
2415  // Check that the object is a boolean.
2416  __ cmp(edx, factory()->true_value());
2417  __ j(equal, &fast);
2418  __ cmp(edx, factory()->false_value());
2419  __ j(not_equal, &miss);
2420  __ bind(&fast);
2421  // Check that the maps starting from the prototype haven't changed.
2422  GenerateDirectLoadGlobalFunctionPrototype(
2423  masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2424  CheckPrototypes(
2425  Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2426  eax, holder, ebx, edx, edi, name, &miss);
2427  } else {
2428  // Calling non-strict non-builtins with a value as the receiver
2429  // requires boxing.
2430  __ jmp(&miss);
2431  }
2432  break;
2433  }
2434 
2435  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2437  : CALL_AS_METHOD;
2438  __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2439  NullCallWrapper(), call_kind);
2440 
2441  // Handle call cache miss.
2442  __ bind(&miss);
2443  GenerateMissBranch();
2444 
2445  // Return the generated code.
2446  return GetCode(function);
2447 }
2448 
2449 
2450 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2451  Handle<JSObject> holder,
2452  Handle<String> name) {
2453  // ----------- S t a t e -------------
2454  // -- ecx : name
2455  // -- esp[0] : return address
2456  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2457  // -- ...
2458  // -- esp[(argc + 1) * 4] : receiver
2459  // -----------------------------------
2460  Label miss;
2461 
2462  GenerateNameCheck(name, &miss);
2463 
2464  // Get the number of arguments.
2465  const int argc = arguments().immediate();
2466 
2467  LookupResult lookup(isolate());
2468  LookupPostInterceptor(holder, name, &lookup);
2469 
2470  // Get the receiver from the stack.
2471  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2472 
2473  CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
2474  compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2475  &miss);
2476 
2477  // Restore receiver.
2478  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2479 
2480  // Check that the function really is a function.
2481  __ JumpIfSmi(eax, &miss);
2482  __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2483  __ j(not_equal, &miss);
2484 
2485  // Patch the receiver on the stack with the global proxy if
2486  // necessary.
2487  if (object->IsGlobalObject()) {
2489  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2490  }
2491 
2492  // Invoke the function.
2493  __ mov(edi, eax);
2494  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2496  : CALL_AS_METHOD;
2497  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2498  NullCallWrapper(), call_kind);
2499 
2500  // Handle load cache miss.
2501  __ bind(&miss);
2502  GenerateMissBranch();
2503 
2504  // Return the generated code.
2505  return GetCode(Code::INTERCEPTOR, name);
2506 }
2507 
2508 
2510  Handle<JSObject> object,
2511  Handle<GlobalObject> holder,
2512  Handle<JSGlobalPropertyCell> cell,
2513  Handle<JSFunction> function,
2514  Handle<String> name) {
2515  // ----------- S t a t e -------------
2516  // -- ecx : name
2517  // -- esp[0] : return address
2518  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2519  // -- ...
2520  // -- esp[(argc + 1) * 4] : receiver
2521  // -----------------------------------
2522 
2523  if (HasCustomCallGenerator(function)) {
2524  Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2525  // A null handle means bail out to the regular compiler code below.
2526  if (!code.is_null()) return code;
2527  }
2528 
2529  Label miss;
2530  GenerateNameCheck(name, &miss);
2531 
2532  // Get the number of arguments.
2533  const int argc = arguments().immediate();
2534  GenerateGlobalReceiverCheck(object, holder, name, &miss);
2535  GenerateLoadFunctionFromCell(cell, function, &miss);
2536 
2537  // Patch the receiver on the stack with the global proxy.
2538  if (object->IsGlobalObject()) {
2540  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2541  }
2542 
2543  // Set up the context (function already in edi).
2545 
2546  // Jump to the cached code (tail call).
2547  Counters* counters = isolate()->counters();
2548  __ IncrementCounter(counters->call_global_inline(), 1);
2549  ParameterCount expected(function->shared()->formal_parameter_count());
2550  CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2552  : CALL_AS_METHOD;
2553  // We call indirectly through the code field in the function to
2554  // allow recompilation to take effect without changing any of the
2555  // call sites.
2556  __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2557  expected, arguments(), JUMP_FUNCTION,
2558  NullCallWrapper(), call_kind);
2559 
2560  // Handle call cache miss.
2561  __ bind(&miss);
2562  __ IncrementCounter(counters->call_global_inline_miss(), 1);
2563  GenerateMissBranch();
2564 
2565  // Return the generated code.
2566  return GetCode(Code::NORMAL, name);
2567 }
2568 
2569 
2570 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
2571  int index,
2572  Handle<Map> transition,
2573  Handle<String> name) {
2574  // ----------- S t a t e -------------
2575  // -- eax : value
2576  // -- ecx : name
2577  // -- edx : receiver
2578  // -- esp[0] : return address
2579  // -----------------------------------
2580  Label miss;
2581 
2582  // Generate store field code. Trashes the name register.
2583  GenerateStoreField(masm(),
2584  object,
2585  index,
2586  transition,
2587  name,
2588  edx, ecx, ebx, edi,
2589  &miss);
2590  // Handle store cache miss.
2591  __ bind(&miss);
2592  __ mov(ecx, Immediate(name)); // restore name
2593  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2594  __ jmp(ic, RelocInfo::CODE_TARGET);
2595 
2596  // Return the generated code.
2597  return GetCode(transition.is_null()
2598  ? Code::FIELD
2599  : Code::MAP_TRANSITION, name);
2600 }
2601 
2602 
2604  Handle<String> name,
2605  Handle<JSObject> receiver,
2606  Handle<JSObject> holder,
2607  Handle<AccessorInfo> callback) {
2608  // ----------- S t a t e -------------
2609  // -- eax : value
2610  // -- ecx : name
2611  // -- edx : receiver
2612  // -- esp[0] : return address
2613  // -----------------------------------
2614  Label miss;
2615  // Check that the maps haven't changed, preserving the value register.
2616  __ push(eax);
2617  __ JumpIfSmi(edx, &miss);
2618  CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);
2619  __ pop(eax); // restore value
2620 
2621  // Stub never generated for non-global objects that require access checks.
2622  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
2623 
2624  __ pop(ebx); // remove the return address
2625  __ push(edx); // receiver
2626  __ push(Immediate(callback)); // callback info
2627  __ push(ecx); // name
2628  __ push(eax); // value
2629  __ push(ebx); // restore return address
2630 
2631  // Do tail-call to the runtime system.
2632  ExternalReference store_callback_property =
2633  ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
2634  __ TailCallExternalReference(store_callback_property, 4, 1);
2635 
2636  // Handle store cache miss.
2637  __ bind(&miss);
2638  __ pop(eax);
2639  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2640  __ jmp(ic, RelocInfo::CODE_TARGET);
2641 
2642  // Return the generated code.
2643  return GetCode(Code::CALLBACKS, name);
2644 }
2645 
2646 
2647 #undef __
2648 #define __ ACCESS_MASM(masm)
2649 
2650 
2652  MacroAssembler* masm,
2653  Handle<JSFunction> setter) {
2654  // ----------- S t a t e -------------
2655  // -- eax : value
2656  // -- ecx : name
2657  // -- edx : receiver
2658  // -- esp[0] : return address
2659  // -----------------------------------
2660  {
2661  FrameScope scope(masm, StackFrame::INTERNAL);
2662 
2663  // Save value register, so we can restore it later.
2664  __ push(eax);
2665 
2666  if (!setter.is_null()) {
2667  // Call the JavaScript setter with receiver and value on the stack.
2668  __ push(edx);
2669  __ push(eax);
2670  ParameterCount actual(1);
2671  __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2672  CALL_AS_METHOD);
2673  } else {
2674  // If we generate a global code snippet for deoptimization only, remember
2675  // the place to continue after deoptimization.
2676  masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2677  }
2678 
2679  // We have to return the passed value, not the return value of the setter.
2680  __ pop(eax);
2681 
2682  // Restore context register.
2684  }
2685  __ ret(0);
2686 }
2687 
2688 
2689 #undef __
2690 #define __ ACCESS_MASM(masm())
2691 
2692 
2694  Handle<String> name,
2695  Handle<JSObject> receiver,
2696  Handle<JSObject> holder,
2697  Handle<JSFunction> setter) {
2698  // ----------- S t a t e -------------
2699  // -- eax : value
2700  // -- ecx : name
2701  // -- edx : receiver
2702  // -- esp[0] : return address
2703  // -----------------------------------
2704  Label miss;
2705 
2706  // Check that the maps haven't changed, preserving the name register.
2707  __ push(ecx);
2708  __ JumpIfSmi(edx, &miss);
2709  CheckPrototypes(receiver, edx, holder, ebx, ecx, edi, name, &miss);
2710  __ pop(ecx);
2711 
2712  GenerateStoreViaSetter(masm(), setter);
2713 
2714  __ bind(&miss);
2715  __ pop(ecx);
2716  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2717  __ jmp(ic, RelocInfo::CODE_TARGET);
2718 
2719  // Return the generated code.
2720  return GetCode(Code::CALLBACKS, name);
2721 }
2722 
2723 
2725  Handle<JSObject> receiver,
2726  Handle<String> name) {
2727  // ----------- S t a t e -------------
2728  // -- eax : value
2729  // -- ecx : name
2730  // -- edx : receiver
2731  // -- esp[0] : return address
2732  // -----------------------------------
2733  Label miss;
2734 
2735  // Check that the map of the object hasn't changed.
2736  __ CheckMap(edx, Handle<Map>(receiver->map()),
2738 
2739  // Perform global security token check if needed.
2740  if (receiver->IsJSGlobalProxy()) {
2741  __ CheckAccessGlobalProxy(edx, ebx, &miss);
2742  }
2743 
2744  // Stub never generated for non-global objects that require access
2745  // checks.
2746  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2747 
2748  __ pop(ebx); // remove the return address
2749  __ push(edx); // receiver
2750  __ push(ecx); // name
2751  __ push(eax); // value
2752  __ push(Immediate(Smi::FromInt(strict_mode_)));
2753  __ push(ebx); // restore return address
2754 
2755  // Do tail-call to the runtime system.
2756  ExternalReference store_ic_property =
2757  ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
2758  __ TailCallExternalReference(store_ic_property, 4, 1);
2759 
2760  // Handle store cache miss.
2761  __ bind(&miss);
2762  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2763  __ jmp(ic, RelocInfo::CODE_TARGET);
2764 
2765  // Return the generated code.
2766  return GetCode(Code::INTERCEPTOR, name);
2767 }
2768 
2769 
2771  Handle<GlobalObject> object,
2772  Handle<JSGlobalPropertyCell> cell,
2773  Handle<String> name) {
2774  // ----------- S t a t e -------------
2775  // -- eax : value
2776  // -- ecx : name
2777  // -- edx : receiver
2778  // -- esp[0] : return address
2779  // -----------------------------------
2780  Label miss;
2781 
2782  // Check that the map of the global has not changed.
2784  Immediate(Handle<Map>(object->map())));
2785  __ j(not_equal, &miss);
2786 
2787  // Compute the cell operand to use.
2788  __ mov(ebx, Immediate(cell));
2789  Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
2790 
2791  // Check that the value in the cell is not the hole. If it is, this
2792  // cell could have been deleted and reintroducing the global needs
2793  // to update the property details in the property dictionary of the
2794  // global object. We bail out to the runtime system to do that.
2795  __ cmp(cell_operand, factory()->the_hole_value());
2796  __ j(equal, &miss);
2797 
2798  // Store the value in the cell.
2799  __ mov(cell_operand, eax);
2800  // No write barrier here, because cells are always rescanned.
2801 
2802  // Return the value (register eax).
2803  Counters* counters = isolate()->counters();
2804  __ IncrementCounter(counters->named_store_global_inline(), 1);
2805  __ ret(0);
2806 
2807  // Handle store cache miss.
2808  __ bind(&miss);
2809  __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
2810  Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2811  __ jmp(ic, RelocInfo::CODE_TARGET);
2812 
2813  // Return the generated code.
2814  return GetCode(Code::NORMAL, name);
2815 }
2816 
2817 
2818 Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
2819  int index,
2820  Handle<Map> transition,
2821  Handle<String> name) {
2822  // ----------- S t a t e -------------
2823  // -- eax : value
2824  // -- ecx : key
2825  // -- edx : receiver
2826  // -- esp[0] : return address
2827  // -----------------------------------
2828  Label miss;
2829 
2830  Counters* counters = isolate()->counters();
2831  __ IncrementCounter(counters->keyed_store_field(), 1);
2832 
2833  // Check that the name has not changed.
2834  __ cmp(ecx, Immediate(name));
2835  __ j(not_equal, &miss);
2836 
2837  // Generate store field code. Trashes the name register.
2838  GenerateStoreField(masm(),
2839  object,
2840  index,
2841  transition,
2842  name,
2843  edx, ecx, ebx, edi,
2844  &miss);
2845 
2846  // Handle store cache miss.
2847  __ bind(&miss);
2848  __ DecrementCounter(counters->keyed_store_field(), 1);
2849  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2850  __ jmp(ic, RelocInfo::CODE_TARGET);
2851 
2852  // Return the generated code.
2853  return GetCode(transition.is_null()
2854  ? Code::FIELD
2855  : Code::MAP_TRANSITION, name);
2856 }
2857 
2858 
2860  Handle<Map> receiver_map) {
2861  // ----------- S t a t e -------------
2862  // -- eax : value
2863  // -- ecx : key
2864  // -- edx : receiver
2865  // -- esp[0] : return address
2866  // -----------------------------------
2867  ElementsKind elements_kind = receiver_map->elements_kind();
2868  bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
2869  Handle<Code> stub =
2870  KeyedStoreElementStub(is_jsarray, elements_kind, grow_mode_).GetCode();
2871 
2872  __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
2873 
2874  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2875  __ jmp(ic, RelocInfo::CODE_TARGET);
2876 
2877  // Return the generated code.
2878  return GetCode(Code::NORMAL, factory()->empty_string());
2879 }
2880 
2881 
2883  MapHandleList* receiver_maps,
2884  CodeHandleList* handler_stubs,
2885  MapHandleList* transitioned_maps) {
2886  // ----------- S t a t e -------------
2887  // -- eax : value
2888  // -- ecx : key
2889  // -- edx : receiver
2890  // -- esp[0] : return address
2891  // -----------------------------------
2892  Label miss;
2893  __ JumpIfSmi(edx, &miss, Label::kNear);
2894  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
2895  // ebx: receiver->map().
2896  for (int i = 0; i < receiver_maps->length(); ++i) {
2897  __ cmp(edi, receiver_maps->at(i));
2898  if (transitioned_maps->at(i).is_null()) {
2899  __ j(equal, handler_stubs->at(i));
2900  } else {
2901  Label next_map;
2902  __ j(not_equal, &next_map, Label::kNear);
2903  __ mov(ebx, Immediate(transitioned_maps->at(i)));
2904  __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
2905  __ bind(&next_map);
2906  }
2907  }
2908  __ bind(&miss);
2909  Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
2910  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
2911 
2912  // Return the generated code.
2913  return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
2914 }
2915 
2916 
2917 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2918  Handle<JSObject> object,
2919  Handle<JSObject> last) {
2920  // ----------- S t a t e -------------
2921  // -- ecx : name
2922  // -- edx : receiver
2923  // -- esp[0] : return address
2924  // -----------------------------------
2925  Label miss;
2926 
2927  // Check that the receiver isn't a smi.
2928  __ JumpIfSmi(edx, &miss);
2929 
2930  ASSERT(last->IsGlobalObject() || last->HasFastProperties());
2931 
2932  // Check the maps of the full prototype chain. Also check that
2933  // global property cells up to (but not including) the last object
2934  // in the prototype chain are empty.
2935  CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss);
2936 
2937  // If the last object in the prototype chain is a global object,
2938  // check that the global property cell is empty.
2939  if (last->IsGlobalObject()) {
2940  GenerateCheckPropertyCell(
2941  masm(), Handle<GlobalObject>::cast(last), name, eax, &miss);
2942  }
2943 
2944  // Return undefined if maps of the full prototype chain are still the
2945  // same and no global property with this name contains a value.
2946  __ mov(eax, isolate()->factory()->undefined_value());
2947  __ ret(0);
2948 
2949  __ bind(&miss);
2950  GenerateLoadMiss(masm(), Code::LOAD_IC);
2951 
2952  // Return the generated code.
2953  return GetCode(Code::NONEXISTENT, factory()->empty_string());
2954 }
2955 
2956 
2957 Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2958  Handle<JSObject> holder,
2959  int index,
2960  Handle<String> name) {
2961  // ----------- S t a t e -------------
2962  // -- ecx : name
2963  // -- edx : receiver
2964  // -- esp[0] : return address
2965  // -----------------------------------
2966  Label miss;
2967 
2968  GenerateLoadField(object, holder, edx, ebx, eax, edi, index, name, &miss);
2969  __ bind(&miss);
2970  GenerateLoadMiss(masm(), Code::LOAD_IC);
2971 
2972  // Return the generated code.
2973  return GetCode(Code::FIELD, name);
2974 }
2975 
2976 
2978  Handle<String> name,
2979  Handle<JSObject> object,
2980  Handle<JSObject> holder,
2981  Handle<AccessorInfo> callback) {
2982  // ----------- S t a t e -------------
2983  // -- ecx : name
2984  // -- edx : receiver
2985  // -- esp[0] : return address
2986  // -----------------------------------
2987  Label miss;
2988 
2989  GenerateLoadCallback(object, holder, edx, ecx, ebx, eax, edi, no_reg,
2990  callback, name, &miss);
2991  __ bind(&miss);
2992  GenerateLoadMiss(masm(), Code::LOAD_IC);
2993 
2994  // Return the generated code.
2995  return GetCode(Code::CALLBACKS, name);
2996 }
2997 
2998 
2999 #undef __
3000 #define __ ACCESS_MASM(masm)
3001 
3002 
3003 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3004  Handle<JSFunction> getter) {
3005  // ----------- S t a t e -------------
3006  // -- ecx : name
3007  // -- edx : receiver
3008  // -- esp[0] : return address
3009  // -----------------------------------
3010  {
3011  FrameScope scope(masm, StackFrame::INTERNAL);
3012 
3013  if (!getter.is_null()) {
3014  // Call the JavaScript getter with the receiver on the stack.
3015  __ push(edx);
3016  ParameterCount actual(0);
3017  __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
3018  CALL_AS_METHOD);
3019  } else {
3020  // If we generate a global code snippet for deoptimization only, remember
3021  // the place to continue after deoptimization.
3022  masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3023  }
3024 
3025  // Restore context register.
3027  }
3028  __ ret(0);
3029 }
3030 
3031 
3032 #undef __
3033 #define __ ACCESS_MASM(masm())
3034 
3035 
3037  Handle<String> name,
3038  Handle<JSObject> receiver,
3039  Handle<JSObject> holder,
3040  Handle<JSFunction> getter) {
3041  // ----------- S t a t e -------------
3042  // -- ecx : name
3043  // -- edx : receiver
3044  // -- esp[0] : return address
3045  // -----------------------------------
3046  Label miss;
3047 
3048  // Check that the maps haven't changed.
3049  __ JumpIfSmi(edx, &miss);
3050  CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);
3051 
3052  GenerateLoadViaGetter(masm(), getter);
3053 
3054  __ bind(&miss);
3055  GenerateLoadMiss(masm(), Code::LOAD_IC);
3056 
3057  // Return the generated code.
3058  return GetCode(Code::CALLBACKS, name);
3059 }
3060 
3061 
3062 Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3063  Handle<JSObject> holder,
3064  Handle<JSFunction> value,
3065  Handle<String> name) {
3066  // ----------- S t a t e -------------
3067  // -- ecx : name
3068  // -- edx : receiver
3069  // -- esp[0] : return address
3070  // -----------------------------------
3071  Label miss;
3072 
3073  GenerateLoadConstant(object, holder, edx, ebx, eax, edi, value, name, &miss);
3074  __ bind(&miss);
3075  GenerateLoadMiss(masm(), Code::LOAD_IC);
3076 
3077  // Return the generated code.
3078  return GetCode(Code::CONSTANT_FUNCTION, name);
3079 }
3080 
3081 
3082 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
3083  Handle<JSObject> holder,
3084  Handle<String> name) {
3085  // ----------- S t a t e -------------
3086  // -- ecx : name
3087  // -- edx : receiver
3088  // -- esp[0] : return address
3089  // -----------------------------------
3090  Label miss;
3091 
3092  LookupResult lookup(isolate());
3093  LookupPostInterceptor(holder, name, &lookup);
3094 
3095  // TODO(368): Compile in the whole chain: all the interceptors in
3096  // prototypes and ultimate answer.
3097  GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
3098  name, &miss);
3099 
3100  __ bind(&miss);
3101  GenerateLoadMiss(masm(), Code::LOAD_IC);
3102 
3103  // Return the generated code.
3104  return GetCode(Code::INTERCEPTOR, name);
3105 }
3106 
3107 
3109  Handle<JSObject> object,
3110  Handle<GlobalObject> holder,
3111  Handle<JSGlobalPropertyCell> cell,
3112  Handle<String> name,
3113  bool is_dont_delete) {
3114  // ----------- S t a t e -------------
3115  // -- ecx : name
3116  // -- edx : receiver
3117  // -- esp[0] : return address
3118  // -----------------------------------
3119  Label miss;
3120 
3121  // Check that the maps haven't changed.
3122  __ JumpIfSmi(edx, &miss);
3123  CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss);
3124 
3125  // Get the value from the cell.
3126  if (Serializer::enabled()) {
3127  __ mov(ebx, Immediate(cell));
3129  } else {
3130  __ mov(ebx, Operand::Cell(cell));
3131  }
3132 
3133  // Check for deleted property if property can actually be deleted.
3134  if (!is_dont_delete) {
3135  __ cmp(ebx, factory()->the_hole_value());
3136  __ j(equal, &miss);
3137  } else if (FLAG_debug_code) {
3138  __ cmp(ebx, factory()->the_hole_value());
3139  __ Check(not_equal, "DontDelete cells can't contain the hole");
3140  }
3141 
3142  Counters* counters = isolate()->counters();
3143  __ IncrementCounter(counters->named_load_global_stub(), 1);
3144  __ mov(eax, ebx);
3145  __ ret(0);
3146 
3147  __ bind(&miss);
3148  __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
3149  GenerateLoadMiss(masm(), Code::LOAD_IC);
3150 
3151  // Return the generated code.
3152  return GetCode(Code::NORMAL, name);
3153 }
3154 
3155 
3156 Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3157  Handle<JSObject> receiver,
3158  Handle<JSObject> holder,
3159  int index) {
3160  // ----------- S t a t e -------------
3161  // -- ecx : key
3162  // -- edx : receiver
3163  // -- esp[0] : return address
3164  // -----------------------------------
3165  Label miss;
3166 
3167  Counters* counters = isolate()->counters();
3168  __ IncrementCounter(counters->keyed_load_field(), 1);
3169 
3170  // Check that the name has not changed.
3171  __ cmp(ecx, Immediate(name));
3172  __ j(not_equal, &miss);
3173 
3174  GenerateLoadField(receiver, holder, edx, ebx, eax, edi, index, name, &miss);
3175 
3176  __ bind(&miss);
3177  __ DecrementCounter(counters->keyed_load_field(), 1);
3178  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3179 
3180  // Return the generated code.
3181  return GetCode(Code::FIELD, name);
3182 }
3183 
3184 
3186  Handle<String> name,
3187  Handle<JSObject> receiver,
3188  Handle<JSObject> holder,
3189  Handle<AccessorInfo> callback) {
3190  // ----------- S t a t e -------------
3191  // -- ecx : key
3192  // -- edx : receiver
3193  // -- esp[0] : return address
3194  // -----------------------------------
3195  Label miss;
3196 
3197  Counters* counters = isolate()->counters();
3198  __ IncrementCounter(counters->keyed_load_callback(), 1);
3199 
3200  // Check that the name has not changed.
3201  __ cmp(ecx, Immediate(name));
3202  __ j(not_equal, &miss);
3203 
3204  GenerateLoadCallback(receiver, holder, edx, ecx, ebx, eax, edi, no_reg,
3205  callback, name, &miss);
3206 
3207  __ bind(&miss);
3208  __ DecrementCounter(counters->keyed_load_callback(), 1);
3209  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3210 
3211  // Return the generated code.
3212  return GetCode(Code::CALLBACKS, name);
3213 }
3214 
3215 
3217  Handle<String> name,
3218  Handle<JSObject> receiver,
3219  Handle<JSObject> holder,
3220  Handle<JSFunction> value) {
3221  // ----------- S t a t e -------------
3222  // -- ecx : key
3223  // -- edx : receiver
3224  // -- esp[0] : return address
3225  // -----------------------------------
3226  Label miss;
3227 
3228  Counters* counters = isolate()->counters();
3229  __ IncrementCounter(counters->keyed_load_constant_function(), 1);
3230 
3231  // Check that the name has not changed.
3232  __ cmp(ecx, Immediate(name));
3233  __ j(not_equal, &miss);
3234 
3235  GenerateLoadConstant(
3236  receiver, holder, edx, ebx, eax, edi, value, name, &miss);
3237  __ bind(&miss);
3238  __ DecrementCounter(counters->keyed_load_constant_function(), 1);
3239  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3240 
3241  // Return the generated code.
3242  return GetCode(Code::CONSTANT_FUNCTION, name);
3243 }
3244 
3245 
3247  Handle<JSObject> receiver,
3248  Handle<JSObject> holder,
3249  Handle<String> name) {
3250  // ----------- S t a t e -------------
3251  // -- ecx : key
3252  // -- edx : receiver
3253  // -- esp[0] : return address
3254  // -----------------------------------
3255  Label miss;
3256 
3257  Counters* counters = isolate()->counters();
3258  __ IncrementCounter(counters->keyed_load_interceptor(), 1);
3259 
3260  // Check that the name has not changed.
3261  __ cmp(ecx, Immediate(name));
3262  __ j(not_equal, &miss);
3263 
3264  LookupResult lookup(isolate());
3265  LookupPostInterceptor(holder, name, &lookup);
3266  GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
3267  name, &miss);
3268  __ bind(&miss);
3269  __ DecrementCounter(counters->keyed_load_interceptor(), 1);
3270  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3271 
3272  // Return the generated code.
3273  return GetCode(Code::INTERCEPTOR, name);
3274 }
3275 
3276 
3278  Handle<String> name) {
3279  // ----------- S t a t e -------------
3280  // -- ecx : key
3281  // -- edx : receiver
3282  // -- esp[0] : return address
3283  // -----------------------------------
3284  Label miss;
3285 
3286  Counters* counters = isolate()->counters();
3287  __ IncrementCounter(counters->keyed_load_array_length(), 1);
3288 
3289  // Check that the name has not changed.
3290  __ cmp(ecx, Immediate(name));
3291  __ j(not_equal, &miss);
3292 
3293  GenerateLoadArrayLength(masm(), edx, eax, &miss);
3294  __ bind(&miss);
3295  __ DecrementCounter(counters->keyed_load_array_length(), 1);
3296  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3297 
3298  // Return the generated code.
3299  return GetCode(Code::CALLBACKS, name);
3300 }
3301 
3302 
3304  Handle<String> name) {
3305  // ----------- S t a t e -------------
3306  // -- ecx : key
3307  // -- edx : receiver
3308  // -- esp[0] : return address
3309  // -----------------------------------
3310  Label miss;
3311 
3312  Counters* counters = isolate()->counters();
3313  __ IncrementCounter(counters->keyed_load_string_length(), 1);
3314 
3315  // Check that the name has not changed.
3316  __ cmp(ecx, Immediate(name));
3317  __ j(not_equal, &miss);
3318 
3319  GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true);
3320  __ bind(&miss);
3321  __ DecrementCounter(counters->keyed_load_string_length(), 1);
3322  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3323 
3324  // Return the generated code.
3325  return GetCode(Code::CALLBACKS, name);
3326 }
3327 
3328 
3330  Handle<String> name) {
3331  // ----------- S t a t e -------------
3332  // -- ecx : key
3333  // -- edx : receiver
3334  // -- esp[0] : return address
3335  // -----------------------------------
3336  Label miss;
3337 
3338  Counters* counters = isolate()->counters();
3339  __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
3340 
3341  // Check that the name has not changed.
3342  __ cmp(ecx, Immediate(name));
3343  __ j(not_equal, &miss);
3344 
3345  GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss);
3346  __ bind(&miss);
3347  __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
3348  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3349 
3350  // Return the generated code.
3351  return GetCode(Code::CALLBACKS, name);
3352 }
3353 
3354 
3356  Handle<Map> receiver_map) {
3357  // ----------- S t a t e -------------
3358  // -- ecx : key
3359  // -- edx : receiver
3360  // -- esp[0] : return address
3361  // -----------------------------------
3362 
3363  ElementsKind elements_kind = receiver_map->elements_kind();
3364  Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3365 
3366  __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
3367 
3368  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3369 
3370  // Return the generated code.
3371  return GetCode(Code::NORMAL, factory()->empty_string());
3372 }
3373 
3374 
3376  MapHandleList* receiver_maps,
3377  CodeHandleList* handler_ics) {
3378  // ----------- S t a t e -------------
3379  // -- ecx : key
3380  // -- edx : receiver
3381  // -- esp[0] : return address
3382  // -----------------------------------
3383  Label miss;
3384  __ JumpIfSmi(edx, &miss);
3385 
3386  Register map_reg = ebx;
3387  __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
3388  int receiver_count = receiver_maps->length();
3389  for (int current = 0; current < receiver_count; ++current) {
3390  __ cmp(map_reg, receiver_maps->at(current));
3391  __ j(equal, handler_ics->at(current));
3392  }
3393 
3394  __ bind(&miss);
3395  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3396 
3397  // Return the generated code.
3398  return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
3399 }
3400 
3401 
3402 // Specialized stub for constructing objects from functions which only have only
3403 // simple assignments of the form this.x = ...; in their body.
3405  Handle<JSFunction> function) {
3406  // ----------- S t a t e -------------
3407  // -- eax : argc
3408  // -- edi : constructor
3409  // -- esp[0] : return address
3410  // -- esp[4] : last argument
3411  // -----------------------------------
3412  Label generic_stub_call;
3413 #ifdef ENABLE_DEBUGGER_SUPPORT
3414  // Check to see whether there are any break points in the function code. If
3415  // there are jump to the generic constructor stub which calls the actual
3416  // code for the function thereby hitting the break points.
3419  __ cmp(ebx, factory()->undefined_value());
3420  __ j(not_equal, &generic_stub_call);
3421 #endif
3422 
3423  // Load the initial map and verify that it is in fact a map.
3425  // Will both indicate a NULL and a Smi.
3426  __ JumpIfSmi(ebx, &generic_stub_call);
3427  __ CmpObjectType(ebx, MAP_TYPE, ecx);
3428  __ j(not_equal, &generic_stub_call);
3429 
3430 #ifdef DEBUG
3431  // Cannot construct functions this way.
3432  // edi: constructor
3433  // ebx: initial map
3434  __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
3435  __ Assert(not_equal, "Function constructed by construct stub.");
3436 #endif
3437 
3438  // Now allocate the JSObject on the heap by moving the new space allocation
3439  // top forward.
3440  // edi: constructor
3441  // ebx: initial map
3442  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3443  __ shl(ecx, kPointerSizeLog2);
3444  __ AllocateInNewSpace(ecx, edx, ecx, no_reg,
3445  &generic_stub_call, NO_ALLOCATION_FLAGS);
3446 
3447  // Allocated the JSObject, now initialize the fields and add the heap tag.
3448  // ebx: initial map
3449  // edx: JSObject (untagged)
3450  __ mov(Operand(edx, JSObject::kMapOffset), ebx);
3451  __ mov(ebx, factory()->empty_fixed_array());
3452  __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3453  __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3454 
3455  // Push the allocated object to the stack. This is the object that will be
3456  // returned (after it is tagged).
3457  __ push(edx);
3458 
3459  // eax: argc
3460  // edx: JSObject (untagged)
3461  // Load the address of the first in-object property into edx.
3462  __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3463  // Calculate the location of the first argument. The stack contains the
3464  // allocated object and the return address on top of the argc arguments.
3465  __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3466 
3467  // Use edi for holding undefined which is used in several places below.
3468  __ mov(edi, factory()->undefined_value());
3469 
3470  // eax: argc
3471  // ecx: first argument
3472  // edx: first in-object property of the JSObject
3473  // edi: undefined
3474  // Fill the initialized properties with a constant value or a passed argument
3475  // depending on the this.x = ...; assignment in the function.
3476  Handle<SharedFunctionInfo> shared(function->shared());
3477  for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3478  if (shared->IsThisPropertyAssignmentArgument(i)) {
3479  // Check if the argument assigned to the property is actually passed.
3480  // If argument is not passed the property is set to undefined,
3481  // otherwise find it on the stack.
3482  int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3483  __ mov(ebx, edi);
3484  __ cmp(eax, arg_number);
3486  CpuFeatures::Scope use_cmov(CMOV);
3487  __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3488  } else {
3489  Label not_passed;
3490  __ j(below_equal, &not_passed);
3491  __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3492  __ bind(&not_passed);
3493  }
3494  // Store value in the property.
3495  __ mov(Operand(edx, i * kPointerSize), ebx);
3496  } else {
3497  // Set the property to the constant value.
3498  Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3499  __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3500  }
3501  }
3502 
3503  // Fill the unused in-object property fields with undefined.
3504  ASSERT(function->has_initial_map());
3505  for (int i = shared->this_property_assignments_count();
3506  i < function->initial_map()->inobject_properties();
3507  i++) {
3508  __ mov(Operand(edx, i * kPointerSize), edi);
3509  }
3510 
3511  // Move argc to ebx and retrieve and tag the JSObject to return.
3512  __ mov(ebx, eax);
3513  __ pop(eax);
3514  __ or_(eax, Immediate(kHeapObjectTag));
3515 
3516  // Remove caller arguments and receiver from the stack and return.
3517  __ pop(ecx);
3518  __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3519  __ push(ecx);
3520  Counters* counters = isolate()->counters();
3521  __ IncrementCounter(counters->constructed_objects(), 1);
3522  __ IncrementCounter(counters->constructed_objects_stub(), 1);
3523  __ ret(0);
3524 
3525  // Jump to the generic stub in case the specialized code cannot handle the
3526  // construction.
3527  __ bind(&generic_stub_call);
3528  Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3529  __ jmp(code, RelocInfo::CODE_TARGET);
3530 
3531  // Return the generated code.
3532  return GetCode();
3533 }
3534 
3535 
3536 #undef __
3537 #define __ ACCESS_MASM(masm)
3538 
3539 
3541  MacroAssembler* masm) {
3542  // ----------- S t a t e -------------
3543  // -- ecx : key
3544  // -- edx : receiver
3545  // -- esp[0] : return address
3546  // -----------------------------------
3547  Label slow, miss_force_generic;
3548 
3549  // This stub is meant to be tail-jumped to, the receiver must already
3550  // have been verified by the caller to not be a smi.
3551  __ JumpIfNotSmi(ecx, &miss_force_generic);
3552  __ mov(ebx, ecx);
3553  __ SmiUntag(ebx);
3555 
3556  // Push receiver on the stack to free up a register for the dictionary
3557  // probing.
3558  __ push(edx);
3559  __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
3560  // Pop receiver before returning.
3561  __ pop(edx);
3562  __ ret(0);
3563 
3564  __ bind(&slow);
3565  __ pop(edx);
3566 
3567  // ----------- S t a t e -------------
3568  // -- ecx : key
3569  // -- edx : receiver
3570  // -- esp[0] : return address
3571  // -----------------------------------
3572 
3573  Handle<Code> slow_ic =
3574  masm->isolate()->builtins()->KeyedLoadIC_Slow();
3575  __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3576 
3577  __ bind(&miss_force_generic);
3578  // ----------- S t a t e -------------
3579  // -- ecx : key
3580  // -- edx : receiver
3581  // -- esp[0] : return address
3582  // -----------------------------------
3583 
3584  Handle<Code> miss_force_generic_ic =
3585  masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3586  __ jmp(miss_force_generic_ic, RelocInfo::CODE_TARGET);
3587 }
3588 
3589 
3590 static void GenerateSmiKeyCheck(MacroAssembler* masm,
3591  Register key,
3592  Register scratch,
3593  XMMRegister xmm_scratch0,
3594  XMMRegister xmm_scratch1,
3595  Label* fail) {
3596  // Check that key is a smi and if SSE2 is available a heap number
3597  // containing a smi and branch if the check fails.
3599  CpuFeatures::Scope use_sse2(SSE2);
3600  Label key_ok;
3601  __ JumpIfSmi(key, &key_ok);
3603  Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3604  __ j(not_equal, fail);
3605  __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3606  __ cvttsd2si(scratch, Operand(xmm_scratch0));
3607  __ cvtsi2sd(xmm_scratch1, scratch);
3608  __ ucomisd(xmm_scratch1, xmm_scratch0);
3609  __ j(not_equal, fail);
3610  __ j(parity_even, fail); // NaN.
3611  // Check if the key fits in the smi range.
3612  __ cmp(scratch, 0xc0000000);
3613  __ j(sign, fail);
3614  __ SmiTag(scratch);
3615  __ mov(key, scratch);
3616  __ bind(&key_ok);
3617  } else {
3618  __ JumpIfNotSmi(key, fail);
3619  }
3620 }
3621 
3622 
3624  MacroAssembler* masm,
3625  ElementsKind elements_kind) {
3626  // ----------- S t a t e -------------
3627  // -- ecx : key
3628  // -- edx : receiver
3629  // -- esp[0] : return address
3630  // -----------------------------------
3631  Label miss_force_generic, failed_allocation, slow;
3632 
3633  // This stub is meant to be tail-jumped to, the receiver must already
3634  // have been verified by the caller to not be a smi.
3635 
3636  // Check that the key is a smi or a heap number convertible to a smi.
3637  GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
3638 
3639  // Check that the index is in range.
3640  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
3642  // Unsigned comparison catches both negative and too-large values.
3643  __ j(above_equal, &miss_force_generic);
3645  // ebx: base pointer of external storage
3646  switch (elements_kind) {
3648  __ SmiUntag(ecx); // Untag the index.
3649  __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
3650  break;
3653  __ SmiUntag(ecx); // Untag the index.
3654  __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
3655  break;
3657  __ movsx_w(eax, Operand(ebx, ecx, times_1, 0));
3658  break;
3660  __ movzx_w(eax, Operand(ebx, ecx, times_1, 0));
3661  break;
3663  case EXTERNAL_INT_ELEMENTS:
3664  __ mov(eax, Operand(ebx, ecx, times_2, 0));
3665  break;
3667  __ fld_s(Operand(ebx, ecx, times_2, 0));
3668  break;
3670  __ fld_d(Operand(ebx, ecx, times_4, 0));
3671  break;
3672  default:
3673  UNREACHABLE();
3674  break;
3675  }
3676 
3677  // For integer array types:
3678  // eax: value
3679  // For floating-point array type:
3680  // FP(0): value
3681 
3682  if (elements_kind == EXTERNAL_INT_ELEMENTS ||
3683  elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
3684  // For the Int and UnsignedInt array types, we need to see whether
3685  // the value can be represented in a Smi. If not, we need to convert
3686  // it to a HeapNumber.
3687  Label box_int;
3688  if (elements_kind == EXTERNAL_INT_ELEMENTS) {
3689  __ cmp(eax, 0xc0000000);
3690  __ j(sign, &box_int);
3691  } else {
3692  ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
3693  // The test is different for unsigned int values. Since we need
3694  // the value to be in the range of a positive smi, we can't
3695  // handle either of the top two bits being set in the value.
3696  __ test(eax, Immediate(0xc0000000));
3697  __ j(not_zero, &box_int);
3698  }
3699 
3700  __ SmiTag(eax);
3701  __ ret(0);
3702 
3703  __ bind(&box_int);
3704 
3705  // Allocate a HeapNumber for the int and perform int-to-double
3706  // conversion.
3707  if (elements_kind == EXTERNAL_INT_ELEMENTS) {
3708  __ push(eax);
3709  __ fild_s(Operand(esp, 0));
3710  __ pop(eax);
3711  } else {
3712  ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
3713  // Need to zero-extend the value.
3714  // There's no fild variant for unsigned values, so zero-extend
3715  // to a 64-bit int manually.
3716  __ push(Immediate(0));
3717  __ push(eax);
3718  __ fild_d(Operand(esp, 0));
3719  __ pop(eax);
3720  __ pop(eax);
3721  }
3722  // FP(0): value
3723  __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
3724  // Set the value.
3726  __ ret(0);
3727  } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3728  elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3729  // For the floating-point array type, we need to always allocate a
3730  // HeapNumber.
3731  __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
3732  // Set the value.
3734  __ ret(0);
3735  } else {
3736  __ SmiTag(eax);
3737  __ ret(0);
3738  }
3739 
3740  // If we fail allocation of the HeapNumber, we still have a value on
3741  // top of the FPU stack. Remove it.
3742  __ bind(&failed_allocation);
3743  __ fstp(0);
3744  // Fall through to slow case.
3745 
3746  // Slow case: Jump to runtime.
3747  __ bind(&slow);
3748  Counters* counters = masm->isolate()->counters();
3749  __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
3750 
3751  // ----------- S t a t e -------------
3752  // -- ecx : key
3753  // -- edx : receiver
3754  // -- esp[0] : return address
3755  // -----------------------------------
3756 
3757  Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
3758  __ jmp(ic, RelocInfo::CODE_TARGET);
3759 
3760  // ----------- S t a t e -------------
3761  // -- ecx : key
3762  // -- edx : receiver
3763  // -- esp[0] : return address
3764  // -----------------------------------
3765 
3766  // Miss case: Jump to runtime.
3767  __ bind(&miss_force_generic);
3768  Handle<Code> miss_ic =
3769  masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3770  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3771 }
3772 
3773 
3775  MacroAssembler* masm,
3776  ElementsKind elements_kind) {
3777  // ----------- S t a t e -------------
3778  // -- eax : value
3779  // -- ecx : key
3780  // -- edx : receiver
3781  // -- esp[0] : return address
3782  // -----------------------------------
3783  Label miss_force_generic, slow, check_heap_number;
3784 
3785  // This stub is meant to be tail-jumped to, the receiver must already
3786  // have been verified by the caller to not be a smi.
3787 
3788  // Check that the key is a smi or a heap number convertible to a smi.
3789  GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
3790 
3791  // Check that the index is in range.
3792  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3794  // Unsigned comparison catches both negative and too-large values.
3795  __ j(above_equal, &slow);
3796 
3797  // Handle both smis and HeapNumbers in the fast path. Go to the
3798  // runtime for all other kinds of values.
3799  // eax: value
3800  // edx: receiver
3801  // ecx: key
3802  // edi: elements array
3803  if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
3804  __ JumpIfNotSmi(eax, &slow);
3805  } else {
3806  __ JumpIfNotSmi(eax, &check_heap_number);
3807  }
3808 
3809  // smi case
3810  __ mov(ebx, eax); // Preserve the value in eax as the return value.
3811  __ SmiUntag(ebx);
3813  // edi: base pointer of external storage
3814  switch (elements_kind) {
3816  __ ClampUint8(ebx);
3817  __ SmiUntag(ecx);
3818  __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3819  break;
3822  __ SmiUntag(ecx);
3823  __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3824  break;
3827  __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
3828  break;
3829  case EXTERNAL_INT_ELEMENTS:
3831  __ mov(Operand(edi, ecx, times_2, 0), ebx);
3832  break;
3835  // Need to perform int-to-float conversion.
3836  __ push(ebx);
3837  __ fild_s(Operand(esp, 0));
3838  __ pop(ebx);
3839  if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3840  __ fstp_s(Operand(edi, ecx, times_2, 0));
3841  } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
3842  __ fstp_d(Operand(edi, ecx, times_4, 0));
3843  }
3844  break;
3845  default:
3846  UNREACHABLE();
3847  break;
3848  }
3849  __ ret(0); // Return the original value.
3850 
3851  // TODO(danno): handle heap number -> pixel array conversion
3852  if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
3853  __ bind(&check_heap_number);
3854  // eax: value
3855  // edx: receiver
3856  // ecx: key
3857  // edi: elements array
3859  Immediate(masm->isolate()->factory()->heap_number_map()));
3860  __ j(not_equal, &slow);
3861 
3862  // The WebGL specification leaves the behavior of storing NaN and
3863  // +/-Infinity into integer arrays basically undefined. For more
3864  // reproducible behavior, convert these to zero.
3866  // edi: base pointer of external storage
3867  if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3869  __ fstp_s(Operand(edi, ecx, times_2, 0));
3870  __ ret(0);
3871  } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3873  __ fstp_d(Operand(edi, ecx, times_4, 0));
3874  __ ret(0);
3875  } else {
3876  // Perform float-to-int conversion with truncation (round-to-zero)
3877  // behavior.
3878 
3879  // For the moment we make the slow call to the runtime on
3880  // processors that don't support SSE2. The code in IntegerConvert
3881  // (code-stubs-ia32.cc) is roughly what is needed here though the
3882  // conversion failure case does not need to be handled.
3884  if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3885  elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3887  CpuFeatures::Scope scope(SSE3);
3888  // fisttp stores values as signed integers. To represent the
3889  // entire range of int and unsigned int arrays, store as a
3890  // 64-bit int and discard the high 32 bits.
3892  __ sub(esp, Immediate(2 * kPointerSize));
3893  __ fisttp_d(Operand(esp, 0));
3894 
3895  // If conversion failed (NaN, infinity, or a number outside
3896  // signed int64 range), the result is 0x8000000000000000, and
3897  // we must handle this case in the runtime.
3898  Label ok;
3899  __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3900  __ j(not_equal, &ok);
3901  __ cmp(Operand(esp, 0), Immediate(0));
3902  __ j(not_equal, &ok);
3903  __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3904  __ jmp(&slow);
3905 
3906  __ bind(&ok);
3907  __ pop(ebx);
3908  __ add(esp, Immediate(kPointerSize));
3909  __ mov(Operand(edi, ecx, times_2, 0), ebx);
3910  } else {
3912  CpuFeatures::Scope scope(SSE2);
3913  __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
3914  __ cmp(ebx, 0x80000000u);
3915  __ j(equal, &slow);
3916  // ebx: untagged integer value
3917  switch (elements_kind) {
3919  __ ClampUint8(ebx);
3920  // Fall through.
3923  __ SmiUntag(ecx);
3924  __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
3925  break;
3928  __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
3929  break;
3930  case EXTERNAL_INT_ELEMENTS:
3932  __ mov(Operand(edi, ecx, times_2, 0), ebx);
3933  break;
3934  default:
3935  UNREACHABLE();
3936  break;
3937  }
3938  }
3939  __ ret(0); // Return original value.
3940  }
3941  }
3942  }
3943 
3944  // Slow case: call runtime.
3945  __ bind(&slow);
3946  Counters* counters = masm->isolate()->counters();
3947  __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3948 
3949  // ----------- S t a t e -------------
3950  // -- eax : value
3951  // -- ecx : key
3952  // -- edx : receiver
3953  // -- esp[0] : return address
3954  // -----------------------------------
3955 
3956  Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3957  __ jmp(ic, RelocInfo::CODE_TARGET);
3958 
3959  // ----------- S t a t e -------------
3960  // -- eax : value
3961  // -- ecx : key
3962  // -- edx : receiver
3963  // -- esp[0] : return address
3964  // -----------------------------------
3965 
3966  __ bind(&miss_force_generic);
3967  Handle<Code> miss_ic =
3968  masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3969  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3970 }
3971 
3972 
3973 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
3974  // ----------- S t a t e -------------
3975  // -- ecx : key
3976  // -- edx : receiver
3977  // -- esp[0] : return address
3978  // -----------------------------------
3979  Label miss_force_generic;
3980 
3981  // This stub is meant to be tail-jumped to, the receiver must already
3982  // have been verified by the caller to not be a smi.
3983 
3984  // Check that the key is a smi or a heap number convertible to a smi.
3985  GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
3986 
3987  // Get the elements array.
3989  __ AssertFastElements(eax);
3990 
3991  // Check that the key is within bounds.
3993  __ j(above_equal, &miss_force_generic);
3994 
3995  // Load the result and make sure it's not the hole.
3996  __ mov(ebx, Operand(eax, ecx, times_2,
3997  FixedArray::kHeaderSize - kHeapObjectTag));
3998  __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
3999  __ j(equal, &miss_force_generic);
4000  __ mov(eax, ebx);
4001  __ ret(0);
4002 
4003  __ bind(&miss_force_generic);
4004  Handle<Code> miss_ic =
4005  masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4006  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
4007 }
4008 
4009 
4011  MacroAssembler* masm) {
4012  // ----------- S t a t e -------------
4013  // -- ecx : key
4014  // -- edx : receiver
4015  // -- esp[0] : return address
4016  // -----------------------------------
4017  Label miss_force_generic, slow_allocate_heapnumber;
4018 
4019  // This stub is meant to be tail-jumped to, the receiver must already
4020  // have been verified by the caller to not be a smi.
4021 
4022  // Check that the key is a smi or a heap number convertible to a smi.
4023  GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
4024 
4025  // Get the elements array.
4027  __ AssertFastElements(eax);
4028 
4029  // Check that the key is within bounds.
4031  __ j(above_equal, &miss_force_generic);
4032 
4033  // Check for the hole
4034  uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
4035  __ cmp(FieldOperand(eax, ecx, times_4, offset), Immediate(kHoleNanUpper32));
4036  __ j(equal, &miss_force_generic);
4037 
4038  // Always allocate a heap number for the result.
4040  CpuFeatures::Scope use_sse2(SSE2);
4041  __ movdbl(xmm0, FieldOperand(eax, ecx, times_4,
4043  } else {
4045  }
4046  __ AllocateHeapNumber(eax, ebx, edi, &slow_allocate_heapnumber);
4047  // Set the value.
4049  CpuFeatures::Scope use_sse2(SSE2);
4051  } else {
4053  }
4054  __ ret(0);
4055 
4056  __ bind(&slow_allocate_heapnumber);
4057  // A value was pushed on the floating point stack before the allocation, if
4058  // the allocation fails it needs to be removed.
4060  __ fstp(0);
4061  }
4062  Handle<Code> slow_ic =
4063  masm->isolate()->builtins()->KeyedLoadIC_Slow();
4064  __ jmp(slow_ic, RelocInfo::CODE_TARGET);
4065 
4066  __ bind(&miss_force_generic);
4067  Handle<Code> miss_ic =
4068  masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4069  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
4070 }
4071 
4072 
4074  MacroAssembler* masm,
4075  bool is_js_array,
4076  ElementsKind elements_kind,
4077  KeyedAccessGrowMode grow_mode) {
4078  // ----------- S t a t e -------------
4079  // -- eax : value
4080  // -- ecx : key
4081  // -- edx : receiver
4082  // -- esp[0] : return address
4083  // -----------------------------------
4084  Label miss_force_generic, grow, slow, transition_elements_kind;
4085  Label check_capacity, prepare_slow, finish_store, commit_backing_store;
4086 
4087  // This stub is meant to be tail-jumped to, the receiver must already
4088  // have been verified by the caller to not be a smi.
4089 
4090  // Check that the key is a smi or a heap number convertible to a smi.
4091  GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
4092 
4093  if (IsFastSmiElementsKind(elements_kind)) {
4094  __ JumpIfNotSmi(eax, &transition_elements_kind);
4095  }
4096 
4097  // Get the elements array and make sure it is a fast element array, not 'cow'.
4098  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4099  if (is_js_array) {
4100  // Check that the key is within bounds.
4101  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
4102  if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4103  __ j(above_equal, &grow);
4104  } else {
4105  __ j(above_equal, &miss_force_generic);
4106  }
4107  } else {
4108  // Check that the key is within bounds.
4109  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
4110  __ j(above_equal, &miss_force_generic);
4111  }
4112 
4114  Immediate(masm->isolate()->factory()->fixed_array_map()));
4115  __ j(not_equal, &miss_force_generic);
4116 
4117  __ bind(&finish_store);
4118  if (IsFastSmiElementsKind(elements_kind)) {
4119  // ecx is a smi, use times_half_pointer_size instead of
4120  // times_pointer_size
4121  __ mov(FieldOperand(edi,
4122  ecx,
4124  FixedArray::kHeaderSize), eax);
4125  } else {
4126  ASSERT(IsFastObjectElementsKind(elements_kind));
4127  // Do the store and update the write barrier.
4128  // ecx is a smi, use times_half_pointer_size instead of
4129  // times_pointer_size
4130  __ lea(ecx, FieldOperand(edi,
4131  ecx,
4133  FixedArray::kHeaderSize));
4134  __ mov(Operand(ecx, 0), eax);
4135  // Make sure to preserve the value in register eax.
4136  __ mov(ebx, eax);
4137  __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
4138  }
4139 
4140  // Done.
4141  __ ret(0);
4142 
4143  // Handle store cache miss, replacing the ic with the generic stub.
4144  __ bind(&miss_force_generic);
4145  Handle<Code> ic_force_generic =
4146  masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4147  __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
4148 
4149  // Handle transition to other elements kinds without using the generic stub.
4150  __ bind(&transition_elements_kind);
4151  Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4152  __ jmp(ic_miss, RelocInfo::CODE_TARGET);
4153 
4154  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4155  // Handle transition requiring the array to grow.
4156  __ bind(&grow);
4157 
4158  // Make sure the array is only growing by a single element, anything else
4159  // must be handled by the runtime. Flags are already set by previous
4160  // compare.
4161  __ j(not_equal, &miss_force_generic);
4162 
4163  // Check for the empty array, and preallocate a small backing store if
4164  // possible.
4165  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4166  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4167  __ j(not_equal, &check_capacity);
4168 
4170  __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
4171  // Restore the key, which is known to be the array length.
4172 
4173  // eax: value
4174  // ecx: key
4175  // edx: receiver
4176  // edi: elements
4177  // Make sure that the backing store can hold additional elements.
4179  Immediate(masm->isolate()->factory()->fixed_array_map()));
4182  __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
4183  for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4184  __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
4185  }
4186 
4187  // Store the element at index zero.
4188  __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
4189 
4190  // Install the new backing store in the JSArray.
4191  __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4192  __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4194 
4195  // Increment the length of the array.
4197  Immediate(Smi::FromInt(1)));
4198  __ ret(0);
4199 
4200  __ bind(&check_capacity);
4202  Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
4203  __ j(equal, &miss_force_generic);
4204 
4205  // eax: value
4206  // ecx: key
4207  // edx: receiver
4208  // edi: elements
4209  // Make sure that the backing store can hold additional elements.
4211  __ j(above_equal, &slow);
4212 
4213  // Grow the array and finish the store.
4215  Immediate(Smi::FromInt(1)));
4216  __ jmp(&finish_store);
4217 
4218  __ bind(&prepare_slow);
4219  // Restore the key, which is known to be the array length.
4220  __ mov(ecx, Immediate(0));
4221 
4222  __ bind(&slow);
4223  Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4224  __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4225  }
4226 }
4227 
4228 
4230  MacroAssembler* masm,
4231  bool is_js_array,
4232  KeyedAccessGrowMode grow_mode) {
4233  // ----------- S t a t e -------------
4234  // -- eax : value
4235  // -- ecx : key
4236  // -- edx : receiver
4237  // -- esp[0] : return address
4238  // -----------------------------------
4239  Label miss_force_generic, transition_elements_kind, grow, slow;
4240  Label check_capacity, prepare_slow, finish_store, commit_backing_store;
4241 
4242  // This stub is meant to be tail-jumped to, the receiver must already
4243  // have been verified by the caller to not be a smi.
4244 
4245  // Check that the key is a smi or a heap number convertible to a smi.
4246  GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
4247 
4248  // Get the elements array.
4249  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4250  __ AssertFastElements(edi);
4251 
4252  if (is_js_array) {
4253  // Check that the key is within bounds.
4254  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
4255  if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4256  __ j(above_equal, &grow);
4257  } else {
4258  __ j(above_equal, &miss_force_generic);
4259  }
4260  } else {
4261  // Check that the key is within bounds.
4262  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
4263  __ j(above_equal, &miss_force_generic);
4264  }
4265 
4266  __ bind(&finish_store);
4267  __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
4268  &transition_elements_kind, true);
4269  __ ret(0);
4270 
4271  // Handle store cache miss, replacing the ic with the generic stub.
4272  __ bind(&miss_force_generic);
4273  Handle<Code> ic_force_generic =
4274  masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4275  __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
4276 
4277  // Handle transition to other elements kinds without using the generic stub.
4278  __ bind(&transition_elements_kind);
4279  Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4280  __ jmp(ic_miss, RelocInfo::CODE_TARGET);
4281 
4282  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4283  // Handle transition requiring the array to grow.
4284  __ bind(&grow);
4285 
4286  // Make sure the array is only growing by a single element, anything else
4287  // must be handled by the runtime. Flags are already set by previous
4288  // compare.
4289  __ j(not_equal, &miss_force_generic);
4290 
4291  // Transition on values that can't be stored in a FixedDoubleArray.
4292  Label value_is_smi;
4293  __ JumpIfSmi(eax, &value_is_smi);
4295  Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
4296  __ j(not_equal, &transition_elements_kind);
4297  __ bind(&value_is_smi);
4298 
4299  // Check for the empty array, and preallocate a small backing store if
4300  // possible.
4301  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4302  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4303  __ j(not_equal, &check_capacity);
4304 
4305  int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4306  __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
4307 
4308  // Restore the key, which is known to be the array length.
4309  __ mov(ecx, Immediate(0));
4310 
4311  // eax: value
4312  // ecx: key
4313  // edx: receiver
4314  // edi: elements
4315  // Initialize the new FixedDoubleArray. Leave elements unitialized for
4316  // efficiency, they are guaranteed to be initialized before use.
4318  Immediate(masm->isolate()->factory()->fixed_double_array_map()));
4320  Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4321 
4322  // Install the new backing store in the JSArray.
4323  __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4324  __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4326 
4327  // Increment the length of the array.
4329  Immediate(Smi::FromInt(1)));
4330  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4331  __ jmp(&finish_store);
4332 
4333  __ bind(&check_capacity);
4334  // eax: value
4335  // ecx: key
4336  // edx: receiver
4337  // edi: elements
4338  // Make sure that the backing store can hold additional elements.
4340  __ j(above_equal, &slow);
4341 
4342  // Grow the array and finish the store.
4344  Immediate(Smi::FromInt(1)));
4345  __ jmp(&finish_store);
4346 
4347  __ bind(&prepare_slow);
4348  // Restore the key, which is known to be the array length.
4349  __ mov(ecx, Immediate(0));
4350 
4351  __ bind(&slow);
4352  Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4353  __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4354  }
4355 }
4356 
4357 
4358 #undef __
4359 
4360 } } // namespace v8::internal
4361 
4362 #endif // V8_TARGET_ARCH_IA32
byte * Address
Definition: globals.h:157
static const int kBitFieldOffset
Definition: objects.h:5160
Handle< Code > CompileLoadFunctionPrototype(Handle< String > name)
Handle< Code > CompileLoadCallback(Handle< String > name, Handle< JSObject > object, Handle< JSObject > holder, Handle< AccessorInfo > callback)
static void GenerateStoreViaSetter(MacroAssembler *masm, Handle< JSFunction > setter)
static const int kCodeEntryOffset
Definition: objects.h:6182
Handle< Code > CompileStoreField(Handle< JSObject > object, int index, Handle< Map > transition, Handle< String > name)
static const int kPrototypeOrInitialMapOffset
Definition: objects.h:6183
static int SlotOffset(int index)
Definition: contexts.h:425
static const int kDataOffset
Definition: objects.h:8409
Handle< Code > CompileLoadNonexistent(Handle< String > name, Handle< JSObject > object, Handle< JSObject > last)
Handle< Code > CompileStoreElement(Handle< Map > receiver_map)
void GenerateProbe(MacroAssembler *masm, Code::Flags flags, Register receiver, Register name, Register scratch, Register extra, Register extra2=no_reg, Register extra3=no_reg)
static const int kFlagsOffset
Definition: objects.h:4540
static Smi * FromInt(int value)
Definition: objects-inl.h:981
bool IsFastObjectElementsKind(ElementsKind kind)
#define LOG(isolate, Call)
Definition: log.h:81
static void GenerateStoreExternalArray(MacroAssembler *masm, ElementsKind elements_kind)
const Register esp
static const int kGlobalReceiverOffset
Definition: objects.h:6288
static void GenerateLoadFastDoubleElement(MacroAssembler *masm)
static StubType ExtractTypeFromFlags(Flags flags)
Definition: objects-inl.h:3538
static bool IsSupported(CpuFeature f)
static const int kExternalPointerOffset
Definition: objects.h:3741
static bool enabled()
Definition: serialize.h:481
static const int kHasNamedInterceptor
Definition: objects.h:5169
static const int kIsAccessCheckNeeded
Definition: objects.h:5173
List< Handle< Map > > MapHandleList
Definition: list.h:198
#define ASSERT(condition)
Definition: checks.h:270
const int kPointerSizeLog2
Definition: globals.h:232
static const int kInstanceSizeOffset
Definition: objects.h:5147
static const int kDebugInfoOffset
Definition: objects.h:5805
static const int kContextOffset
Definition: objects.h:6187
Handle< Code > CompileLoadField(Handle< JSObject > object, Handle< JSObject > holder, int index, Handle< String > name)
Handle< Code > CompileStoreInterceptor(Handle< JSObject > object, Handle< String > name)
static void GenerateNegativeLookup(MacroAssembler *masm, Label *miss, Label *done, Register receiver, Register properties, Handle< String > name, Register scratch0)
Handle< Code > CompileStoreField(Handle< JSObject > object, int index, Handle< Map > transition, Handle< String > name)
const Register edi
static const int kHashFieldOffset
Definition: objects.h:7319
const uint32_t kNotStringTag
Definition: objects.h:457
Handle< Code > CompileLoadInterceptor(Handle< JSObject > object, Handle< JSObject > holder, Handle< String > name)
const Register ebp
#define UNREACHABLE()
Definition: checks.h:50
STATIC_ASSERT((FixedDoubleArray::kHeaderSize &kDoubleAlignmentMask)==0)
static const int kLengthOffset
Definition: objects.h:7318
Handle< Code > CompileCallGlobal(Handle< JSObject > object, Handle< GlobalObject > holder, Handle< JSGlobalPropertyCell > cell, Handle< JSFunction > function, Handle< String > name)
const Register eax
Handle< Code > CompileLoadField(Handle< String > name, Handle< JSObject > object, Handle< JSObject > holder, int index)
static const int kValueOffset
Definition: objects.h:1342
static void GenerateLoadViaGetter(MacroAssembler *masm, Handle< JSFunction > getter)
const uint32_t kHoleNanUpper32
Definition: v8globals.h:469
Handle< Code > CompileStoreGlobal(Handle< GlobalObject > object, Handle< JSGlobalPropertyCell > holder, Handle< String > name)
Handle< Code > CompileLoadViaGetter(Handle< String > name, Handle< JSObject > receiver, Handle< JSObject > holder, Handle< JSFunction > getter)
Handle< Code > CompileLoadConstant(Handle< JSObject > object, Handle< JSObject > holder, Handle< JSFunction > value, Handle< String > name)
const XMMRegister xmm1
Handle< Code > CompileLoadConstant(Handle< String > name, Handle< JSObject > object, Handle< JSObject > holder, Handle< JSFunction > value)
Handle< Code > CompileCallField(Handle< JSObject > object, Handle< JSObject > holder, int index, Handle< String > name)
const int kPointerSize
Definition: globals.h:220
static void GenerateStoreFastElement(MacroAssembler *masm, bool is_js_array, ElementsKind element_kind, KeyedAccessGrowMode grow_mode)
Handle< Code > CompileLoadStringLength(Handle< String > name)
Operand FieldOperand(Register object, int offset)
const Register ecx
const Address kZapValue
Definition: v8globals.h:80
const int kHeapObjectTag
Definition: v8.h:4009
const uint32_t kHoleNanLower32
Definition: v8globals.h:470
#define __
static bool decode(uint32_t value)
Definition: utils.h:273
static const int kPropertiesOffset
Definition: objects.h:2171
Handle< Code > CompileLoadGlobal(Handle< JSObject > object, Handle< GlobalObject > holder, Handle< JSGlobalPropertyCell > cell, Handle< String > name, bool is_dont_delete)
Handle< Code > CompileStoreCallback(Handle< String > name, Handle< JSObject > receiver, Handle< JSObject > holder, Handle< AccessorInfo > callback)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random generator(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer
bool IsFastSmiElementsKind(ElementsKind kind)
static void GenerateMapChangeElementsTransition(MacroAssembler *masm)
static const int kDataOffset
Definition: objects.h:8539
static int SizeFor(int length)
Definition: objects.h:2434
const Register r0
static const int kElementsOffset
Definition: objects.h:2172
#define BASE_EMBEDDED
Definition: allocation.h:68
const int kBitsPerInt
Definition: globals.h:240
static void GenerateLoadDictionaryElement(MacroAssembler *masm)
static void GenerateLoadExternalArray(MacroAssembler *masm, ElementsKind elements_kind)
static const int kLengthOffset
Definition: objects.h:8332
static int SizeFor(int length)
Definition: objects.h:2353
static const int kHeaderSize
Definition: objects.h:2296
static const int kMapOffset
Definition: objects.h:1261
List< Handle< Code > > CodeHandleList
Definition: list.h:199
const Register r1
static const int kLengthOffset
Definition: objects.h:2295
const Register ebx
static void GeneratePositiveLookup(MacroAssembler *masm, Label *miss, Label *done, Register elements, Register name, Register r0, Register r1)
Handle< Code > CompileCallInterceptor(Handle< JSObject > object, Handle< JSObject > holder, Handle< String > name)
static const int kDataOffset
Definition: objects.h:8563
static void GenerateLoadFastElement(MacroAssembler *masm)
static const uint32_t kSignMask
Definition: objects.h:1351
Operand ApiParameterOperand(int index)
const int kSmiTagSize
Definition: v8.h:4015
static void GenerateStoreFastDoubleElement(MacroAssembler *masm, bool is_js_array, KeyedAccessGrowMode grow_mode)
static const int kHeaderSize
Definition: objects.h:4549
static Handle< T > null()
Definition: handles.h:86
#define ASSERT_EQ(v1, v2)
Definition: checks.h:271
const Register esi
Handle< Code > CompileLoadArrayLength(Handle< String > name)
const int kSmiTag
Definition: v8.h:4014
Handle< Code > CompileCallConstant(Handle< Object > object, Handle< JSObject > holder, Handle< JSFunction > function, Handle< String > name, CheckType check)
static AccessorInfo * cast(Object *obj)
static const int kHeaderSize
Definition: objects.h:2173
const int kHeapObjectTagSize
Definition: v8.h:4010
static Handle< JSGlobalPropertyCell > EnsurePropertyCell(Handle< GlobalObject > global, Handle< String > name)
Definition: objects.cc:12019
static bool HasCustomCallGenerator(Handle< JSFunction > function)
Definition: stub-cache.cc:1444
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
static const int kPreallocatedArrayElements
Definition: objects.h:8329
static const int kPrototypeOffset
Definition: objects.h:5126
static const int kFlagsNotUsedInLookup
Definition: objects.h:4649
const int kInvalidProtoDepth
const Register no_reg
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
static const int kValueOffset
Definition: objects.h:6385
Handle< Code > CompileLoadCallback(Handle< String > name, Handle< JSObject > object, Handle< JSObject > holder, Handle< AccessorInfo > callback)
const XMMRegister xmm2
const Register edx
Handle< Code > CompileLoadPolymorphic(MapHandleList *receiver_maps, CodeHandleList *handler_ics)
Handle< Code > CompileLoadInterceptor(Handle< JSObject > object, Handle< JSObject > holder, Handle< String > name)
Handle< Code > CompileStorePolymorphic(MapHandleList *receiver_maps, CodeHandleList *handler_stubs, MapHandleList *transitioned_maps)
static const int kSharedFunctionInfoOffset
Definition: objects.h:6185
KeyedAccessGrowMode
Definition: objects.h:142
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random allows verbose printing trace parsing and preparsing Check icache flushes in ARM and MIPS simulator Stack alingment in bytes in print stack trace when throwing exceptions randomize hashes to avoid predictable hash Fixed seed to use to hash property activate a timer that switches between V8 threads testing_bool_flag float flag Seed used for threading test randomness A filename with extra code to be included in the Print usage including flags
Definition: flags.cc:495
static const int kMantissaBits
Definition: objects.h:1354
void check(i::Vector< const char > string)
static const int kExponentOffset
Definition: objects.h:1348
Handle< Code > CompileLoadElement(Handle< Map > receiver_map)
Handle< Code > CompileConstructStub(Handle< JSFunction > function)
Handle< Code > CompileStoreViaSetter(Handle< String > name, Handle< JSObject > receiver, Handle< JSObject > holder, Handle< JSFunction > setter)
static JSObject * cast(Object *obj)
static const int kInstanceTypeOffset
Definition: objects.h:5158
static const int kMantissaOffset
Definition: objects.h:1347
const XMMRegister xmm0
static JSFunction * cast(Object *obj)