Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: src/x64/stub-cache-x64.cc

Issue 143633007: A64: Synchronize with r18764. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/regexp-macro-assembler-x64.cc ('k') | test/cctest/cctest.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 68
69 // Check that the key in the entry matches the name. 69 // Check that the key in the entry matches the name.
70 // Multiply entry offset by 16 to get the entry address. Since the 70 // Multiply entry offset by 16 to get the entry address. Since the
71 // offset register already holds the entry offset times four, multiply 71 // offset register already holds the entry offset times four, multiply
72 // by a further four. 72 // by a further four.
73 __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0)); 73 __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0));
74 __ j(not_equal, &miss); 74 __ j(not_equal, &miss);
75 75
76 // Get the map entry from the cache. 76 // Get the map entry from the cache.
77 // Use key_offset + kPointerSize * 2, rather than loading map_offset. 77 // Use key_offset + kPointerSize * 2, rather than loading map_offset.
78 __ movq(kScratchRegister, 78 __ movp(kScratchRegister,
79 Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2)); 79 Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
80 __ cmpq(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset)); 80 __ cmpq(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
81 __ j(not_equal, &miss); 81 __ j(not_equal, &miss);
82 82
83 // Get the code entry from the cache. 83 // Get the code entry from the cache.
84 __ LoadAddress(kScratchRegister, value_offset); 84 __ LoadAddress(kScratchRegister, value_offset);
85 __ movq(kScratchRegister, 85 __ movp(kScratchRegister,
86 Operand(kScratchRegister, offset, scale_factor, 0)); 86 Operand(kScratchRegister, offset, scale_factor, 0));
87 87
88 // Check that the flags match what we're looking for. 88 // Check that the flags match what we're looking for.
89 __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset)); 89 __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
90 __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup)); 90 __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
91 __ cmpl(offset, Immediate(flags)); 91 __ cmpl(offset, Immediate(flags));
92 __ j(not_equal, &miss); 92 __ j(not_equal, &miss);
93 93
94 #ifdef DEBUG 94 #ifdef DEBUG
95 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { 95 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
(...skipping 16 matching lines...) Expand all
112 Register receiver, 112 Register receiver,
113 Handle<Name> name, 113 Handle<Name> name,
114 Register scratch0, 114 Register scratch0,
115 Register scratch1) { 115 Register scratch1) {
116 ASSERT(name->IsUniqueName()); 116 ASSERT(name->IsUniqueName());
117 ASSERT(!receiver.is(scratch0)); 117 ASSERT(!receiver.is(scratch0));
118 Counters* counters = masm->isolate()->counters(); 118 Counters* counters = masm->isolate()->counters();
119 __ IncrementCounter(counters->negative_lookups(), 1); 119 __ IncrementCounter(counters->negative_lookups(), 1);
120 __ IncrementCounter(counters->negative_lookups_miss(), 1); 120 __ IncrementCounter(counters->negative_lookups_miss(), 1);
121 121
122 __ movq(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); 122 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
123 123
124 const int kInterceptorOrAccessCheckNeededMask = 124 const int kInterceptorOrAccessCheckNeededMask =
125 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); 125 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
126 126
127 // Bail out if the receiver has a named interceptor or requires access checks. 127 // Bail out if the receiver has a named interceptor or requires access checks.
128 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset), 128 __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
129 Immediate(kInterceptorOrAccessCheckNeededMask)); 129 Immediate(kInterceptorOrAccessCheckNeededMask));
130 __ j(not_zero, miss_label); 130 __ j(not_zero, miss_label);
131 131
132 // Check that receiver is a JSObject. 132 // Check that receiver is a JSObject.
133 __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE); 133 __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
134 __ j(below, miss_label); 134 __ j(below, miss_label);
135 135
136 // Load properties array. 136 // Load properties array.
137 Register properties = scratch0; 137 Register properties = scratch0;
138 __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); 138 __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
139 139
140 // Check that the properties array is a dictionary. 140 // Check that the properties array is a dictionary.
141 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset), 141 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
142 Heap::kHashTableMapRootIndex); 142 Heap::kHashTableMapRootIndex);
143 __ j(not_equal, miss_label); 143 __ j(not_equal, miss_label);
144 144
145 Label done; 145 Label done;
146 NameDictionaryLookupStub::GenerateNegativeLookup(masm, 146 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
147 miss_label, 147 miss_label,
148 &done, 148 &done,
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 // entering the runtime system. 217 // entering the runtime system.
218 __ bind(&miss); 218 __ bind(&miss);
219 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 219 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
220 } 220 }
221 221
222 222
223 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 223 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
224 int index, 224 int index,
225 Register prototype) { 225 Register prototype) {
226 // Load the global or builtins object from the current context. 226 // Load the global or builtins object from the current context.
227 __ movq(prototype, 227 __ movp(prototype,
228 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); 228 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
229 // Load the native context from the global or builtins object. 229 // Load the native context from the global or builtins object.
230 __ movq(prototype, 230 __ movp(prototype,
231 FieldOperand(prototype, GlobalObject::kNativeContextOffset)); 231 FieldOperand(prototype, GlobalObject::kNativeContextOffset));
232 // Load the function from the native context. 232 // Load the function from the native context.
233 __ movq(prototype, Operand(prototype, Context::SlotOffset(index))); 233 __ movp(prototype, Operand(prototype, Context::SlotOffset(index)));
234 // Load the initial map. The global functions all have initial maps. 234 // Load the initial map. The global functions all have initial maps.
235 __ movq(prototype, 235 __ movp(prototype,
236 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset)); 236 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
237 // Load the prototype from the initial map. 237 // Load the prototype from the initial map.
238 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 238 __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
239 } 239 }
240 240
241 241
242 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 242 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
243 MacroAssembler* masm, 243 MacroAssembler* masm,
244 int index, 244 int index,
245 Register prototype, 245 Register prototype,
246 Label* miss) { 246 Label* miss) {
247 Isolate* isolate = masm->isolate(); 247 Isolate* isolate = masm->isolate();
248 // Check we're still in the same context. 248 // Check we're still in the same context.
249 __ Move(prototype, isolate->global_object()); 249 __ Move(prototype, isolate->global_object());
250 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), 250 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
251 prototype); 251 prototype);
252 __ j(not_equal, miss); 252 __ j(not_equal, miss);
253 // Get the global function with the given index. 253 // Get the global function with the given index.
254 Handle<JSFunction> function( 254 Handle<JSFunction> function(
255 JSFunction::cast(isolate->native_context()->get(index))); 255 JSFunction::cast(isolate->native_context()->get(index)));
256 // Load its initial map. The global functions all have initial maps. 256 // Load its initial map. The global functions all have initial maps.
257 __ Move(prototype, Handle<Map>(function->initial_map())); 257 __ Move(prototype, Handle<Map>(function->initial_map()));
258 // Load the prototype from the initial map. 258 // Load the prototype from the initial map.
259 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); 259 __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
260 } 260 }
261 261
262 262
263 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, 263 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
264 Register receiver, 264 Register receiver,
265 Register scratch, 265 Register scratch,
266 Label* miss_label) { 266 Label* miss_label) {
267 // Check that the receiver isn't a smi. 267 // Check that the receiver isn't a smi.
268 __ JumpIfSmi(receiver, miss_label); 268 __ JumpIfSmi(receiver, miss_label);
269 269
270 // Check that the object is a JS array. 270 // Check that the object is a JS array.
271 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 271 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
272 __ j(not_equal, miss_label); 272 __ j(not_equal, miss_label);
273 273
274 // Load length directly from the JS array. 274 // Load length directly from the JS array.
275 __ movq(rax, FieldOperand(receiver, JSArray::kLengthOffset)); 275 __ movp(rax, FieldOperand(receiver, JSArray::kLengthOffset));
276 __ ret(0); 276 __ ret(0);
277 } 277 }
278 278
279 279
280 // Generate code to check if an object is a string. If the object is 280 // Generate code to check if an object is a string. If the object is
281 // a string, the map's instance type is left in the scratch register. 281 // a string, the map's instance type is left in the scratch register.
282 static void GenerateStringCheck(MacroAssembler* masm, 282 static void GenerateStringCheck(MacroAssembler* masm,
283 Register receiver, 283 Register receiver,
284 Register scratch, 284 Register scratch,
285 Label* smi, 285 Label* smi,
286 Label* non_string_object) { 286 Label* non_string_object) {
287 // Check that the object isn't a smi. 287 // Check that the object isn't a smi.
288 __ JumpIfSmi(receiver, smi); 288 __ JumpIfSmi(receiver, smi);
289 289
290 // Check that the object is a string. 290 // Check that the object is a string.
291 __ movq(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); 291 __ movp(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
292 __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 292 __ movzxbq(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
293 STATIC_ASSERT(kNotStringTag != 0); 293 STATIC_ASSERT(kNotStringTag != 0);
294 __ testl(scratch, Immediate(kNotStringTag)); 294 __ testl(scratch, Immediate(kNotStringTag));
295 __ j(not_zero, non_string_object); 295 __ j(not_zero, non_string_object);
296 } 296 }
297 297
298 298
299 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 299 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
300 Register receiver, 300 Register receiver,
301 Register scratch1, 301 Register scratch1,
302 Register scratch2, 302 Register scratch2,
303 Label* miss) { 303 Label* miss) {
304 Label check_wrapper; 304 Label check_wrapper;
305 305
306 // Check if the object is a string leaving the instance type in the 306 // Check if the object is a string leaving the instance type in the
307 // scratch register. 307 // scratch register.
308 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); 308 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
309 309
310 // Load length directly from the string. 310 // Load length directly from the string.
311 __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); 311 __ movp(rax, FieldOperand(receiver, String::kLengthOffset));
312 __ ret(0); 312 __ ret(0);
313 313
314 // Check if the object is a JSValue wrapper. 314 // Check if the object is a JSValue wrapper.
315 __ bind(&check_wrapper); 315 __ bind(&check_wrapper);
316 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); 316 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
317 __ j(not_equal, miss); 317 __ j(not_equal, miss);
318 318
319 // Check if the wrapped value is a string and load the length 319 // Check if the wrapped value is a string and load the length
320 // directly if it is. 320 // directly if it is.
321 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 321 __ movp(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
322 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 322 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
323 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); 323 __ movp(rax, FieldOperand(scratch2, String::kLengthOffset));
324 __ ret(0); 324 __ ret(0);
325 } 325 }
326 326
327 327
328 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 328 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
329 Register receiver, 329 Register receiver,
330 Register result, 330 Register result,
331 Register scratch, 331 Register scratch,
332 Label* miss_label) { 332 Label* miss_label) {
333 __ TryGetFunctionPrototype(receiver, result, miss_label); 333 __ TryGetFunctionPrototype(receiver, result, miss_label);
334 if (!result.is(rax)) __ movq(rax, result); 334 if (!result.is(rax)) __ movp(rax, result);
335 __ ret(0); 335 __ ret(0);
336 } 336 }
337 337
338 338
339 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, 339 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
340 Register dst, 340 Register dst,
341 Register src, 341 Register src,
342 bool inobject, 342 bool inobject,
343 int index, 343 int index,
344 Representation representation) { 344 Representation representation) {
345 ASSERT(!FLAG_track_double_fields || !representation.IsDouble()); 345 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
346 int offset = index * kPointerSize; 346 int offset = index * kPointerSize;
347 if (!inobject) { 347 if (!inobject) {
348 // Calculate the offset into the properties array. 348 // Calculate the offset into the properties array.
349 offset = offset + FixedArray::kHeaderSize; 349 offset = offset + FixedArray::kHeaderSize;
350 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); 350 __ movp(dst, FieldOperand(src, JSObject::kPropertiesOffset));
351 src = dst; 351 src = dst;
352 } 352 }
353 __ movq(dst, FieldOperand(src, offset)); 353 __ movp(dst, FieldOperand(src, offset));
354 } 354 }
355 355
356 356
357 static void PushInterceptorArguments(MacroAssembler* masm, 357 static void PushInterceptorArguments(MacroAssembler* masm,
358 Register receiver, 358 Register receiver,
359 Register holder, 359 Register holder,
360 Register name, 360 Register name,
361 Handle<JSObject> holder_obj) { 361 Handle<JSObject> holder_obj) {
362 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0); 362 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
363 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1); 363 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
(...skipping 21 matching lines...) Expand all
385 __ CallExternalReference( 385 __ CallExternalReference(
386 ExternalReference(IC_Utility(id), masm->isolate()), 386 ExternalReference(IC_Utility(id), masm->isolate()),
387 StubCache::kInterceptorArgsLength); 387 StubCache::kInterceptorArgsLength);
388 } 388 }
389 389
390 390
391 // Number of pointers to be reserved on stack for fast API call. 391 // Number of pointers to be reserved on stack for fast API call.
392 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; 392 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
393 393
394 394
395 // Reserves space for the extra arguments to API function in the
396 // caller's frame.
397 //
398 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
399 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
400 // ----------- S t a t e -------------
401 // -- rsp[0] : return address
402 // -- rsp[8] : last argument in the internal frame of the caller
403 // -----------------------------------
404 __ movq(scratch, StackOperandForReturnAddress(0));
405 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
406 __ movq(StackOperandForReturnAddress(0), scratch);
407 __ Move(scratch, Smi::FromInt(0));
408 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
409 ARGUMENTS_DONT_CONTAIN_RECEIVER);
410 for (int i = 0; i < kFastApiCallArguments; i++) {
411 __ movq(args.GetArgumentOperand(i), scratch);
412 }
413 }
414
415
416 // Undoes the effects of ReserveSpaceForFastApiCall.
417 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
418 // ----------- S t a t e -------------
419 // -- rsp[0] : return address.
420 // -- rsp[8] : last fast api call extra argument.
421 // -- ...
422 // -- rsp[kFastApiCallArguments * 8] : first fast api call extra
423 // argument.
424 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
425 // frame.
426 // -----------------------------------
427 __ movq(scratch, StackOperandForReturnAddress(0));
428 __ movq(StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize),
429 scratch);
430 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
431 }
432
433
434 static void GenerateFastApiCallBody(MacroAssembler* masm, 395 static void GenerateFastApiCallBody(MacroAssembler* masm,
435 const CallOptimization& optimization, 396 const CallOptimization& optimization,
436 int argc, 397 int argc,
398 Register holder,
399 Register scratch1,
400 Register scratch2,
401 Register scratch3,
437 bool restore_context); 402 bool restore_context);
438 403
439 404
440 // Generates call to API function. 405 // Generates call to API function.
441 static void GenerateFastApiCall(MacroAssembler* masm, 406 static void GenerateFastApiCall(MacroAssembler* masm,
442 const CallOptimization& optimization, 407 const CallOptimization& optimization,
443 int argc) { 408 int argc,
444 typedef FunctionCallbackArguments FCA; 409 Handle<Map> map_to_holder,
445 StackArgumentsAccessor args(rsp, argc + kFastApiCallArguments); 410 CallOptimization::HolderLookup holder_lookup) {
411 Counters* counters = masm->isolate()->counters();
412 __ IncrementCounter(counters->call_const_fast_api(), 1);
446 413
447 // Save calling context. 414 // Move holder to a register
448 int offset = argc + kFastApiCallArguments; 415 Register holder_reg = rax;
449 __ movq(args.GetArgumentOperand(offset - FCA::kContextSaveIndex), rsi); 416 switch (holder_lookup) {
450 417 case CallOptimization::kHolderIsReceiver:
451 // Get the function and setup the context. 418 {
452 Handle<JSFunction> function = optimization.constant_function(); 419 ASSERT(map_to_holder.is_null());
453 __ Move(rdi, function); 420 StackArgumentsAccessor args(rsp, argc);
454 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 421 __ movp(holder_reg, args.GetReceiverOperand());
455 // Construct the FunctionCallbackInfo on the stack. 422 }
456 __ movq(args.GetArgumentOperand(offset - FCA::kCalleeIndex), rdi); 423 break;
457 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 424 case CallOptimization::kHolderIsPrototypeOfMap:
458 Handle<Object> call_data(api_call_info->data(), masm->isolate()); 425 {
459 if (masm->isolate()->heap()->InNewSpace(*call_data)) { 426 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype()));
460 __ Move(rcx, api_call_info); 427 if (!masm->isolate()->heap()->InNewSpace(*holder)) {
461 __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); 428 __ Move(holder_reg, holder);
462 __ movq(args.GetArgumentOperand(offset - FCA::kDataIndex), rbx); 429 } else {
463 } else { 430 __ Move(holder_reg, map_to_holder);
464 __ Move(args.GetArgumentOperand(offset - FCA::kDataIndex), call_data); 431 __ movp(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset));
432 }
433 }
434 break;
435 case CallOptimization::kHolderNotFound:
436 UNREACHABLE();
465 } 437 }
466 __ Move(kScratchRegister, 438 GenerateFastApiCallBody(masm,
467 ExternalReference::isolate_address(masm->isolate())); 439 optimization,
468 __ movq(args.GetArgumentOperand(offset - FCA::kIsolateIndex), 440 argc,
469 kScratchRegister); 441 holder_reg,
470 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); 442 rbx,
471 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueDefaultValueIndex), 443 rcx,
472 kScratchRegister); 444 rdx,
473 __ movq(args.GetArgumentOperand(offset - FCA::kReturnValueOffset), 445 false);
474 kScratchRegister);
475
476 // Prepare arguments.
477 STATIC_ASSERT(kFastApiCallArguments == 7);
478 __ lea(rax, args.GetArgumentOperand(offset - FCA::kHolderIndex));
479
480 GenerateFastApiCallBody(masm, optimization, argc, false);
481 } 446 }
482 447
483 448
484 // Generate call to api function. 449 // Generate call to api function.
485 // This function uses push() to generate smaller, faster code than 450 // This function uses push() to generate smaller, faster code than
486 // the version above. It is an optimization that should will be removed 451 // the version above. It is an optimization that should will be removed
487 // when api call ICs are generated in hydrogen. 452 // when api call ICs are generated in hydrogen.
488 static void GenerateFastApiCall(MacroAssembler* masm, 453 static void GenerateFastApiCall(MacroAssembler* masm,
489 const CallOptimization& optimization, 454 const CallOptimization& optimization,
490 Register receiver, 455 Register receiver,
491 Register scratch1, 456 Register scratch1,
492 Register scratch2, 457 Register scratch2,
493 Register scratch3, 458 Register scratch3,
494 int argc, 459 int argc,
495 Register* values) { 460 Register* values) {
496 ASSERT(optimization.is_simple_api_call());
497
498 __ PopReturnAddressTo(scratch1); 461 __ PopReturnAddressTo(scratch1);
499
500 // receiver 462 // receiver
501 __ push(receiver); 463 __ push(receiver);
502
503 // Write the arguments to stack frame. 464 // Write the arguments to stack frame.
504 for (int i = 0; i < argc; i++) { 465 for (int i = 0; i < argc; i++) {
505 Register arg = values[argc-1-i]; 466 Register arg = values[argc-1-i];
506 ASSERT(!receiver.is(arg)); 467 ASSERT(!receiver.is(arg));
507 ASSERT(!scratch1.is(arg)); 468 ASSERT(!scratch1.is(arg));
508 ASSERT(!scratch2.is(arg)); 469 ASSERT(!scratch2.is(arg));
509 ASSERT(!scratch3.is(arg)); 470 ASSERT(!scratch3.is(arg));
510 __ push(arg); 471 __ push(arg);
511 } 472 }
473 __ PushReturnAddressFrom(scratch1);
474 // Stack now matches JSFunction abi.
475 GenerateFastApiCallBody(masm,
476 optimization,
477 argc,
478 receiver,
479 scratch1,
480 scratch2,
481 scratch3,
482 true);
483 }
484
485
486 static void GenerateFastApiCallBody(MacroAssembler* masm,
487 const CallOptimization& optimization,
488 int argc,
489 Register holder,
490 Register scratch1,
491 Register scratch2,
492 Register scratch3,
493 bool restore_context) {
494 // ----------- S t a t e -------------
495 // -- rsp[0] : return address
496 // -- rsp[8] : last argument
497 // -- ...
498 // -- rsp[argc * 8] : first argument
499 // -- rsp[(argc + 1) * 8] : receiver
500 // -----------------------------------
501 ASSERT(optimization.is_simple_api_call());
512 502
513 typedef FunctionCallbackArguments FCA; 503 typedef FunctionCallbackArguments FCA;
514 504
515 STATIC_ASSERT(FCA::kHolderIndex == 0); 505 STATIC_ASSERT(FCA::kHolderIndex == 0);
516 STATIC_ASSERT(FCA::kIsolateIndex == 1); 506 STATIC_ASSERT(FCA::kIsolateIndex == 1);
517 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); 507 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
518 STATIC_ASSERT(FCA::kReturnValueOffset == 3); 508 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
519 STATIC_ASSERT(FCA::kDataIndex == 4); 509 STATIC_ASSERT(FCA::kDataIndex == 4);
520 STATIC_ASSERT(FCA::kCalleeIndex == 5); 510 STATIC_ASSERT(FCA::kCalleeIndex == 5);
521 STATIC_ASSERT(FCA::kContextSaveIndex == 6); 511 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
522 STATIC_ASSERT(FCA::kArgsLength == 7); 512 STATIC_ASSERT(FCA::kArgsLength == 7);
523 513
514 __ PopReturnAddressTo(scratch1);
515
516 ASSERT(!holder.is(rsi));
524 // context save 517 // context save
525 __ push(rsi); 518 __ push(rsi);
526 519
527 // Get the function and setup the context. 520 // Get the function and setup the context.
528 Handle<JSFunction> function = optimization.constant_function(); 521 Handle<JSFunction> function = optimization.constant_function();
529 __ Move(scratch2, function); 522 __ Move(scratch2, function);
530 __ push(scratch2); 523 __ push(scratch2);
531 524
532 Isolate* isolate = masm->isolate(); 525 Isolate* isolate = masm->isolate();
533 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 526 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
534 Handle<Object> call_data(api_call_info->data(), isolate); 527 Handle<Object> call_data(api_call_info->data(), isolate);
535 // Push data from ExecutableAccessorInfo. 528 // Push data from ExecutableAccessorInfo.
536 bool call_data_undefined = false; 529 bool call_data_undefined = false;
537 if (isolate->heap()->InNewSpace(*call_data)) { 530 if (isolate->heap()->InNewSpace(*call_data)) {
538 __ Move(scratch2, api_call_info); 531 __ Move(scratch2, api_call_info);
539 __ movq(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset)); 532 __ movp(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset));
540 } else if (call_data->IsUndefined()) { 533 } else if (call_data->IsUndefined()) {
541 call_data_undefined = true; 534 call_data_undefined = true;
542 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); 535 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
543 } else { 536 } else {
544 __ Move(scratch3, call_data); 537 __ Move(scratch3, call_data);
545 } 538 }
546 // call data 539 // call data
547 __ push(scratch3); 540 __ push(scratch3);
548 if (!call_data_undefined) { 541 if (!call_data_undefined) {
549 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); 542 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
550 } 543 }
551 // return value 544 // return value
552 __ push(scratch3); 545 __ push(scratch3);
553 // return value default 546 // return value default
554 __ push(scratch3); 547 __ push(scratch3);
555 // isolate 548 // isolate
556 __ Move(scratch3, 549 __ Move(scratch3,
557 ExternalReference::isolate_address(masm->isolate())); 550 ExternalReference::isolate_address(masm->isolate()));
558 __ push(scratch3); 551 __ push(scratch3);
559 // holder 552 // holder
560 __ push(receiver); 553 __ push(holder);
561 554
562 ASSERT(!scratch1.is(rax)); 555 ASSERT(!scratch1.is(rax));
563 // store receiver address for GenerateFastApiCallBody 556 __ movp(rax, rsp);
564 __ movq(rax, rsp); 557 // Push return address back on stack.
565 __ PushReturnAddressFrom(scratch1); 558 __ PushReturnAddressFrom(scratch1);
566 559
567 GenerateFastApiCallBody(masm, optimization, argc, true);
568 }
569
570
571 static void GenerateFastApiCallBody(MacroAssembler* masm,
572 const CallOptimization& optimization,
573 int argc,
574 bool restore_context) {
575 // ----------- S t a t e -------------
576 // -- rsp[0] : return address
577 // -- rsp[8] - rsp[56] : FunctionCallbackInfo, incl.
578 // : object passing the type check
579 // (set by CheckPrototypes)
580 // -- rsp[64] : last argument
581 // -- ...
582 // -- rsp[(argc + 7) * 8] : first argument
583 // -- rsp[(argc + 8) * 8] : receiver
584 //
585 // rax : receiver address
586 // -----------------------------------
587 typedef FunctionCallbackArguments FCA;
588
589 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
590 // Function address is a foreign pointer outside V8's heap. 560 // Function address is a foreign pointer outside V8's heap.
591 Address function_address = v8::ToCData<Address>(api_call_info->callback()); 561 Address function_address = v8::ToCData<Address>(api_call_info->callback());
592 562
593 // Allocate the v8::Arguments structure in the arguments' space since 563 // Allocate the v8::Arguments structure in the arguments' space since
594 // it's not controlled by GC. 564 // it's not controlled by GC.
595 const int kApiStackSpace = 4; 565 const int kApiStackSpace = 4;
596 566
597 __ PrepareCallApiFunction(kApiStackSpace); 567 __ PrepareCallApiFunction(kApiStackSpace);
598 568
599 __ movq(StackSpaceOperand(0), rax); // FunctionCallbackInfo::implicit_args_. 569 __ movp(StackSpaceOperand(0), rax); // FunctionCallbackInfo::implicit_args_.
600 __ addq(rax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize)); 570 __ addq(rax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
601 __ movq(StackSpaceOperand(1), rax); // FunctionCallbackInfo::values_. 571 __ movp(StackSpaceOperand(1), rax); // FunctionCallbackInfo::values_.
602 __ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_. 572 __ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_.
603 // FunctionCallbackInfo::is_construct_call_. 573 // FunctionCallbackInfo::is_construct_call_.
604 __ Set(StackSpaceOperand(3), 0); 574 __ Set(StackSpaceOperand(3), 0);
605 575
606 #if defined(__MINGW64__) || defined(_WIN64) 576 #if defined(__MINGW64__) || defined(_WIN64)
607 Register arguments_arg = rcx; 577 Register arguments_arg = rcx;
608 Register callback_arg = rdx; 578 Register callback_arg = rdx;
609 #else 579 #else
610 Register arguments_arg = rdi; 580 Register arguments_arg = rdi;
611 Register callback_arg = rsi; 581 Register callback_arg = rsi;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 Register scratch2, 645 Register scratch2,
676 Register scratch3, 646 Register scratch3,
677 Handle<JSObject> interceptor_holder, 647 Handle<JSObject> interceptor_holder,
678 LookupResult* lookup, 648 LookupResult* lookup,
679 Handle<Name> name, 649 Handle<Name> name,
680 const CallOptimization& optimization, 650 const CallOptimization& optimization,
681 Label* miss_label) { 651 Label* miss_label) {
682 ASSERT(optimization.is_constant_call()); 652 ASSERT(optimization.is_constant_call());
683 ASSERT(!lookup->holder()->IsGlobalObject()); 653 ASSERT(!lookup->holder()->IsGlobalObject());
684 654
685 int depth1 = kInvalidProtoDepth;
686 int depth2 = kInvalidProtoDepth;
687 bool can_do_fast_api_call = false;
688 if (optimization.is_simple_api_call() &&
689 !lookup->holder()->IsGlobalObject()) {
690 depth1 = optimization.GetPrototypeDepthOfExpectedType(
691 object, interceptor_holder);
692 if (depth1 == kInvalidProtoDepth) {
693 depth2 = optimization.GetPrototypeDepthOfExpectedType(
694 interceptor_holder, Handle<JSObject>(lookup->holder()));
695 }
696 can_do_fast_api_call =
697 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
698 }
699
700 Counters* counters = masm->isolate()->counters(); 655 Counters* counters = masm->isolate()->counters();
701 __ IncrementCounter(counters->call_const_interceptor(), 1); 656 __ IncrementCounter(counters->call_const_interceptor(), 1);
702 657
703 if (can_do_fast_api_call) {
704 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
705 ReserveSpaceForFastApiCall(masm, scratch1);
706 }
707
708 // Check that the maps from receiver to interceptor's holder 658 // Check that the maps from receiver to interceptor's holder
709 // haven't changed and thus we can invoke interceptor. 659 // haven't changed and thus we can invoke interceptor.
710 Label miss_cleanup; 660 Label miss_cleanup;
711 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
712 Register holder = 661 Register holder =
713 stub_compiler_->CheckPrototypes( 662 stub_compiler_->CheckPrototypes(
714 IC::CurrentTypeOf(object, masm->isolate()), receiver, 663 IC::CurrentTypeOf(object, masm->isolate()), receiver,
715 interceptor_holder, scratch1, scratch2, scratch3, 664 interceptor_holder, scratch1, scratch2, scratch3,
716 name, depth1, miss); 665 name, miss_label);
717 666
718 // Invoke an interceptor and if it provides a value, 667 // Invoke an interceptor and if it provides a value,
719 // branch to |regular_invoke|. 668 // branch to |regular_invoke|.
720 Label regular_invoke; 669 Label regular_invoke;
721 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, 670 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
722 &regular_invoke); 671 &regular_invoke);
723 672
724 // Interceptor returned nothing for this property. Try to use cached 673 // Interceptor returned nothing for this property. Try to use cached
725 // constant function. 674 // constant function.
726 675
727 // Check that the maps from interceptor's holder to constant function's 676 // Check that the maps from interceptor's holder to constant function's
728 // holder haven't changed and thus we can use cached constant function. 677 // holder haven't changed and thus we can use cached constant function.
729 if (*interceptor_holder != lookup->holder()) { 678 if (*interceptor_holder != lookup->holder()) {
730 stub_compiler_->CheckPrototypes( 679 stub_compiler_->CheckPrototypes(
731 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, 680 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
732 handle(lookup->holder()), scratch1, scratch2, scratch3, 681 handle(lookup->holder()), scratch1, scratch2, scratch3,
733 name, depth2, miss); 682 name, miss_label);
734 } else { 683 }
735 // CheckPrototypes has a side effect of fetching a 'holder' 684
736 // for API (object which is instanceof for the signature). It's 685 Handle<Map> lookup_map;
737 // safe to omit it here, as if present, it should be fetched 686 CallOptimization::HolderLookup holder_lookup =
738 // by the previous CheckPrototypes. 687 CallOptimization::kHolderNotFound;
739 ASSERT(depth2 == kInvalidProtoDepth); 688 if (optimization.is_simple_api_call() &&
689 !lookup->holder()->IsGlobalObject()) {
690 lookup_map = optimization.LookupHolderOfExpectedType(
691 object, object, interceptor_holder, &holder_lookup);
692 if (holder_lookup == CallOptimization::kHolderNotFound) {
693 lookup_map =
694 optimization.LookupHolderOfExpectedType(
695 object,
696 interceptor_holder,
697 Handle<JSObject>(lookup->holder()),
698 &holder_lookup);
699 }
740 } 700 }
741 701
742 // Invoke function. 702 // Invoke function.
743 if (can_do_fast_api_call) { 703 if (holder_lookup != CallOptimization::kHolderNotFound) {
744 GenerateFastApiCall(masm, optimization, arguments_.immediate()); 704 int argc = arguments_.immediate();
705 GenerateFastApiCall(masm,
706 optimization,
707 argc,
708 lookup_map,
709 holder_lookup);
745 } else { 710 } else {
746 Handle<JSFunction> fun = optimization.constant_function(); 711 Handle<JSFunction> fun = optimization.constant_function();
747 stub_compiler_->GenerateJumpFunction(object, fun); 712 stub_compiler_->GenerateJumpFunction(object, fun);
748 } 713 }
749 714
750 // Deferred code for fast API call case---clean preallocated space.
751 if (can_do_fast_api_call) {
752 __ bind(&miss_cleanup);
753 FreeSpaceForFastApiCall(masm, scratch1);
754 __ jmp(miss_label);
755 }
756
757 // Invoke a regular function. 715 // Invoke a regular function.
758 __ bind(&regular_invoke); 716 __ bind(&regular_invoke);
759 if (can_do_fast_api_call) {
760 FreeSpaceForFastApiCall(masm, scratch1);
761 }
762 } 717 }
763 718
764 void CompileRegular(MacroAssembler* masm, 719 void CompileRegular(MacroAssembler* masm,
765 Handle<JSObject> object, 720 Handle<JSObject> object,
766 Register receiver, 721 Register receiver,
767 Register scratch1, 722 Register scratch1,
768 Register scratch2, 723 Register scratch2,
769 Register scratch3, 724 Register scratch3,
770 Handle<Name> name, 725 Handle<Name> name,
771 Handle<JSObject> interceptor_holder, 726 Handle<JSObject> interceptor_holder,
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
925 __ TailCallExternalReference( 880 __ TailCallExternalReference(
926 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), 881 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
927 masm->isolate()), 882 masm->isolate()),
928 3, 883 3,
929 1); 884 1);
930 return; 885 return;
931 } 886 }
932 887
933 // Update the map of the object. 888 // Update the map of the object.
934 __ Move(scratch1, transition); 889 __ Move(scratch1, transition);
935 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); 890 __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
936 891
937 // Update the write barrier for the map field. 892 // Update the write barrier for the map field.
938 __ RecordWriteField(receiver_reg, 893 __ RecordWriteField(receiver_reg,
939 HeapObject::kMapOffset, 894 HeapObject::kMapOffset,
940 scratch1, 895 scratch1,
941 scratch2, 896 scratch2,
942 kDontSaveFPRegs, 897 kDontSaveFPRegs,
943 OMIT_REMEMBERED_SET, 898 OMIT_REMEMBERED_SET,
944 OMIT_SMI_CHECK); 899 OMIT_SMI_CHECK);
945 900
(...skipping 11 matching lines...) Expand all
957 // object and the number of in-object properties is not going to change. 912 // object and the number of in-object properties is not going to change.
958 index -= object->map()->inobject_properties(); 913 index -= object->map()->inobject_properties();
959 914
960 // TODO(verwaest): Share this code as a code stub. 915 // TODO(verwaest): Share this code as a code stub.
961 SmiCheck smi_check = representation.IsTagged() 916 SmiCheck smi_check = representation.IsTagged()
962 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; 917 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
963 if (index < 0) { 918 if (index < 0) {
964 // Set the property straight into the object. 919 // Set the property straight into the object.
965 int offset = object->map()->instance_size() + (index * kPointerSize); 920 int offset = object->map()->instance_size() + (index * kPointerSize);
966 if (FLAG_track_double_fields && representation.IsDouble()) { 921 if (FLAG_track_double_fields && representation.IsDouble()) {
967 __ movq(FieldOperand(receiver_reg, offset), storage_reg); 922 __ movp(FieldOperand(receiver_reg, offset), storage_reg);
968 } else { 923 } else {
969 __ movq(FieldOperand(receiver_reg, offset), value_reg); 924 __ movp(FieldOperand(receiver_reg, offset), value_reg);
970 } 925 }
971 926
972 if (!FLAG_track_fields || !representation.IsSmi()) { 927 if (!FLAG_track_fields || !representation.IsSmi()) {
973 // Update the write barrier for the array address. 928 // Update the write barrier for the array address.
974 if (!FLAG_track_double_fields || !representation.IsDouble()) { 929 if (!FLAG_track_double_fields || !representation.IsDouble()) {
975 __ movq(storage_reg, value_reg); 930 __ movp(storage_reg, value_reg);
976 } 931 }
977 __ RecordWriteField( 932 __ RecordWriteField(
978 receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs, 933 receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs,
979 EMIT_REMEMBERED_SET, smi_check); 934 EMIT_REMEMBERED_SET, smi_check);
980 } 935 }
981 } else { 936 } else {
982 // Write to the properties array. 937 // Write to the properties array.
983 int offset = index * kPointerSize + FixedArray::kHeaderSize; 938 int offset = index * kPointerSize + FixedArray::kHeaderSize;
984 // Get the properties array (optimistically). 939 // Get the properties array (optimistically).
985 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); 940 __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
986 if (FLAG_track_double_fields && representation.IsDouble()) { 941 if (FLAG_track_double_fields && representation.IsDouble()) {
987 __ movq(FieldOperand(scratch1, offset), storage_reg); 942 __ movp(FieldOperand(scratch1, offset), storage_reg);
988 } else { 943 } else {
989 __ movq(FieldOperand(scratch1, offset), value_reg); 944 __ movp(FieldOperand(scratch1, offset), value_reg);
990 } 945 }
991 946
992 if (!FLAG_track_fields || !representation.IsSmi()) { 947 if (!FLAG_track_fields || !representation.IsSmi()) {
993 // Update the write barrier for the array address. 948 // Update the write barrier for the array address.
994 if (!FLAG_track_double_fields || !representation.IsDouble()) { 949 if (!FLAG_track_double_fields || !representation.IsDouble()) {
995 __ movq(storage_reg, value_reg); 950 __ movp(storage_reg, value_reg);
996 } 951 }
997 __ RecordWriteField( 952 __ RecordWriteField(
998 scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs, 953 scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs,
999 EMIT_REMEMBERED_SET, smi_check); 954 EMIT_REMEMBERED_SET, smi_check);
1000 } 955 }
1001 } 956 }
1002 957
1003 // Return the value (register rax). 958 // Return the value (register rax).
1004 ASSERT(value_reg.is(rax)); 959 ASSERT(value_reg.is(rax));
1005 __ ret(0); 960 __ ret(0);
(...skipping 25 matching lines...) Expand all
1031 Representation representation = lookup->representation(); 986 Representation representation = lookup->representation();
1032 ASSERT(!representation.IsNone()); 987 ASSERT(!representation.IsNone());
1033 if (FLAG_track_fields && representation.IsSmi()) { 988 if (FLAG_track_fields && representation.IsSmi()) {
1034 __ JumpIfNotSmi(value_reg, miss_label); 989 __ JumpIfNotSmi(value_reg, miss_label);
1035 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { 990 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1036 __ JumpIfSmi(value_reg, miss_label); 991 __ JumpIfSmi(value_reg, miss_label);
1037 } else if (FLAG_track_double_fields && representation.IsDouble()) { 992 } else if (FLAG_track_double_fields && representation.IsDouble()) {
1038 // Load the double storage. 993 // Load the double storage.
1039 if (index < 0) { 994 if (index < 0) {
1040 int offset = object->map()->instance_size() + (index * kPointerSize); 995 int offset = object->map()->instance_size() + (index * kPointerSize);
1041 __ movq(scratch1, FieldOperand(receiver_reg, offset)); 996 __ movp(scratch1, FieldOperand(receiver_reg, offset));
1042 } else { 997 } else {
1043 __ movq(scratch1, 998 __ movp(scratch1,
1044 FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); 999 FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1045 int offset = index * kPointerSize + FixedArray::kHeaderSize; 1000 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1046 __ movq(scratch1, FieldOperand(scratch1, offset)); 1001 __ movp(scratch1, FieldOperand(scratch1, offset));
1047 } 1002 }
1048 1003
1049 // Store the value into the storage. 1004 // Store the value into the storage.
1050 Label do_store, heap_number; 1005 Label do_store, heap_number;
1051 __ JumpIfNotSmi(value_reg, &heap_number); 1006 __ JumpIfNotSmi(value_reg, &heap_number);
1052 __ SmiToInteger32(scratch2, value_reg); 1007 __ SmiToInteger32(scratch2, value_reg);
1053 __ Cvtlsi2sd(xmm0, scratch2); 1008 __ Cvtlsi2sd(xmm0, scratch2);
1054 __ jmp(&do_store); 1009 __ jmp(&do_store);
1055 1010
1056 __ bind(&heap_number); 1011 __ bind(&heap_number);
1057 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), 1012 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
1058 miss_label, DONT_DO_SMI_CHECK); 1013 miss_label, DONT_DO_SMI_CHECK);
1059 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); 1014 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
1060 __ bind(&do_store); 1015 __ bind(&do_store);
1061 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0); 1016 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1062 // Return the value (register rax). 1017 // Return the value (register rax).
1063 ASSERT(value_reg.is(rax)); 1018 ASSERT(value_reg.is(rax));
1064 __ ret(0); 1019 __ ret(0);
1065 return; 1020 return;
1066 } 1021 }
1067 1022
1068 // TODO(verwaest): Share this code as a code stub. 1023 // TODO(verwaest): Share this code as a code stub.
1069 SmiCheck smi_check = representation.IsTagged() 1024 SmiCheck smi_check = representation.IsTagged()
1070 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; 1025 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
1071 if (index < 0) { 1026 if (index < 0) {
1072 // Set the property straight into the object. 1027 // Set the property straight into the object.
1073 int offset = object->map()->instance_size() + (index * kPointerSize); 1028 int offset = object->map()->instance_size() + (index * kPointerSize);
1074 __ movq(FieldOperand(receiver_reg, offset), value_reg); 1029 __ movp(FieldOperand(receiver_reg, offset), value_reg);
1075 1030
1076 if (!FLAG_track_fields || !representation.IsSmi()) { 1031 if (!FLAG_track_fields || !representation.IsSmi()) {
1077 // Update the write barrier for the array address. 1032 // Update the write barrier for the array address.
1078 // Pass the value being stored in the now unused name_reg. 1033 // Pass the value being stored in the now unused name_reg.
1079 __ movq(name_reg, value_reg); 1034 __ movp(name_reg, value_reg);
1080 __ RecordWriteField( 1035 __ RecordWriteField(
1081 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs, 1036 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs,
1082 EMIT_REMEMBERED_SET, smi_check); 1037 EMIT_REMEMBERED_SET, smi_check);
1083 } 1038 }
1084 } else { 1039 } else {
1085 // Write to the properties array. 1040 // Write to the properties array.
1086 int offset = index * kPointerSize + FixedArray::kHeaderSize; 1041 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1087 // Get the properties array (optimistically). 1042 // Get the properties array (optimistically).
1088 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); 1043 __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1089 __ movq(FieldOperand(scratch1, offset), value_reg); 1044 __ movp(FieldOperand(scratch1, offset), value_reg);
1090 1045
1091 if (!FLAG_track_fields || !representation.IsSmi()) { 1046 if (!FLAG_track_fields || !representation.IsSmi()) {
1092 // Update the write barrier for the array address. 1047 // Update the write barrier for the array address.
1093 // Pass the value being stored in the now unused name_reg. 1048 // Pass the value being stored in the now unused name_reg.
1094 __ movq(name_reg, value_reg); 1049 __ movp(name_reg, value_reg);
1095 __ RecordWriteField( 1050 __ RecordWriteField(
1096 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs, 1051 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs,
1097 EMIT_REMEMBERED_SET, smi_check); 1052 EMIT_REMEMBERED_SET, smi_check);
1098 } 1053 }
1099 } 1054 }
1100 1055
1101 // Return the value (register rax). 1056 // Return the value (register rax).
1102 ASSERT(value_reg.is(rax)); 1057 ASSERT(value_reg.is(rax));
1103 __ ret(0); 1058 __ ret(0);
1104 } 1059 }
1105 1060
1106 1061
1107 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { 1062 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
1108 __ jmp(code, RelocInfo::CODE_TARGET); 1063 __ jmp(code, RelocInfo::CODE_TARGET);
1109 } 1064 }
1110 1065
1111 1066
1112 #undef __ 1067 #undef __
1113 #define __ ACCESS_MASM((masm())) 1068 #define __ ACCESS_MASM((masm()))
1114 1069
1115 1070
1116 Register StubCompiler::CheckPrototypes(Handle<Type> type, 1071 Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
1117 Register object_reg, 1072 Register object_reg,
1118 Handle<JSObject> holder, 1073 Handle<JSObject> holder,
1119 Register holder_reg, 1074 Register holder_reg,
1120 Register scratch1, 1075 Register scratch1,
1121 Register scratch2, 1076 Register scratch2,
1122 Handle<Name> name, 1077 Handle<Name> name,
1123 int save_at_depth,
1124 Label* miss, 1078 Label* miss,
1125 PrototypeCheckType check) { 1079 PrototypeCheckType check) {
1126 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); 1080 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
1127 // Make sure that the type feedback oracle harvests the receiver map. 1081 // Make sure that the type feedback oracle harvests the receiver map.
1128 // TODO(svenpanne) Remove this hack when all ICs are reworked. 1082 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1129 __ Move(scratch1, receiver_map); 1083 __ Move(scratch1, receiver_map);
1130 1084
1131 // Make sure there's no overlap between holder and object registers. 1085 // Make sure there's no overlap between holder and object registers.
1132 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); 1086 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1133 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) 1087 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1134 && !scratch2.is(scratch1)); 1088 && !scratch2.is(scratch1));
1135 1089
1136 // Keep track of the current object in register reg. On the first 1090 // Keep track of the current object in register reg. On the first
1137 // iteration, reg is an alias for object_reg, on later iterations, 1091 // iteration, reg is an alias for object_reg, on later iterations,
1138 // it is an alias for holder_reg. 1092 // it is an alias for holder_reg.
1139 Register reg = object_reg; 1093 Register reg = object_reg;
1140 int depth = 0; 1094 int depth = 0;
1141 1095
1142 StackArgumentsAccessor args(rsp, kFastApiCallArguments,
1143 ARGUMENTS_DONT_CONTAIN_RECEIVER);
1144 const int kHolderIndex = kFastApiCallArguments - 1 -
1145 FunctionCallbackArguments::kHolderIndex;
1146
1147 if (save_at_depth == depth) {
1148 __ movq(args.GetArgumentOperand(kHolderIndex), object_reg);
1149 }
1150
1151 Handle<JSObject> current = Handle<JSObject>::null(); 1096 Handle<JSObject> current = Handle<JSObject>::null();
1152 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); 1097 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
1153 Handle<JSObject> prototype = Handle<JSObject>::null(); 1098 Handle<JSObject> prototype = Handle<JSObject>::null();
1154 Handle<Map> current_map = receiver_map; 1099 Handle<Map> current_map = receiver_map;
1155 Handle<Map> holder_map(holder->map()); 1100 Handle<Map> holder_map(holder->map());
1156 // Traverse the prototype chain and check the maps in the prototype chain for 1101 // Traverse the prototype chain and check the maps in the prototype chain for
1157 // fast and global objects or do negative lookup for normal objects. 1102 // fast and global objects or do negative lookup for normal objects.
1158 while (!current_map.is_identical_to(holder_map)) { 1103 while (!current_map.is_identical_to(holder_map)) {
1159 ++depth; 1104 ++depth;
1160 1105
(...skipping 10 matching lines...) Expand all
1171 ASSERT(name->IsString()); 1116 ASSERT(name->IsString());
1172 name = factory()->InternalizeString(Handle<String>::cast(name)); 1117 name = factory()->InternalizeString(Handle<String>::cast(name));
1173 } 1118 }
1174 ASSERT(current.is_null() || 1119 ASSERT(current.is_null() ||
1175 current->property_dictionary()->FindEntry(*name) == 1120 current->property_dictionary()->FindEntry(*name) ==
1176 NameDictionary::kNotFound); 1121 NameDictionary::kNotFound);
1177 1122
1178 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, 1123 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1179 scratch1, scratch2); 1124 scratch1, scratch2);
1180 1125
1181 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 1126 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1182 reg = holder_reg; // From now on the object will be in holder_reg. 1127 reg = holder_reg; // From now on the object will be in holder_reg.
1183 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 1128 __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1184 } else { 1129 } else {
1185 bool in_new_space = heap()->InNewSpace(*prototype); 1130 bool in_new_space = heap()->InNewSpace(*prototype);
1186 if (in_new_space) { 1131 if (in_new_space) {
1187 // Save the map in scratch1 for later. 1132 // Save the map in scratch1 for later.
1188 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); 1133 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1189 } 1134 }
1190 if (depth != 1 || check == CHECK_ALL_MAPS) { 1135 if (depth != 1 || check == CHECK_ALL_MAPS) {
1191 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); 1136 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
1192 } 1137 }
1193 1138
1194 // Check access rights to the global object. This has to happen after 1139 // Check access rights to the global object. This has to happen after
1195 // the map check so that we know that the object is actually a global 1140 // the map check so that we know that the object is actually a global
1196 // object. 1141 // object.
1197 if (current_map->IsJSGlobalProxyMap()) { 1142 if (current_map->IsJSGlobalProxyMap()) {
1198 __ CheckAccessGlobalProxy(reg, scratch2, miss); 1143 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1199 } else if (current_map->IsJSGlobalObjectMap()) { 1144 } else if (current_map->IsJSGlobalObjectMap()) {
1200 GenerateCheckPropertyCell( 1145 GenerateCheckPropertyCell(
1201 masm(), Handle<JSGlobalObject>::cast(current), name, 1146 masm(), Handle<JSGlobalObject>::cast(current), name,
1202 scratch2, miss); 1147 scratch2, miss);
1203 } 1148 }
1204 reg = holder_reg; // From now on the object will be in holder_reg. 1149 reg = holder_reg; // From now on the object will be in holder_reg.
1205 1150
1206 if (in_new_space) { 1151 if (in_new_space) {
1207 // The prototype is in new space; we cannot store a reference to it 1152 // The prototype is in new space; we cannot store a reference to it
1208 // in the code. Load it from the map. 1153 // in the code. Load it from the map.
1209 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); 1154 __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1210 } else { 1155 } else {
1211 // The prototype is in old space; load it directly. 1156 // The prototype is in old space; load it directly.
1212 __ Move(reg, prototype); 1157 __ Move(reg, prototype);
1213 } 1158 }
1214 } 1159 }
1215 1160
1216 if (save_at_depth == depth) {
1217 __ movq(args.GetArgumentOperand(kHolderIndex), reg);
1218 }
1219
1220 // Go to the next object in the prototype chain. 1161 // Go to the next object in the prototype chain.
1221 current = prototype; 1162 current = prototype;
1222 current_map = handle(current->map()); 1163 current_map = handle(current->map());
1223 } 1164 }
1224 1165
1225 // Log the check depth. 1166 // Log the check depth.
1226 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); 1167 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1227 1168
1228 if (depth != 0 || check == CHECK_ALL_MAPS) { 1169 if (depth != 0 || check == CHECK_ALL_MAPS) {
1229 // Check the holder map. 1170 // Check the holder map.
(...skipping 28 matching lines...) Expand all
1258 Label success; 1199 Label success;
1259 __ jmp(&success); 1200 __ jmp(&success);
1260 GenerateRestoreName(masm(), miss, name); 1201 GenerateRestoreName(masm(), miss, name);
1261 TailCallBuiltin(masm(), MissBuiltin(kind())); 1202 TailCallBuiltin(masm(), MissBuiltin(kind()));
1262 __ bind(&success); 1203 __ bind(&success);
1263 } 1204 }
1264 } 1205 }
1265 1206
1266 1207
1267 Register LoadStubCompiler::CallbackHandlerFrontend( 1208 Register LoadStubCompiler::CallbackHandlerFrontend(
1268 Handle<Type> type, 1209 Handle<HeapType> type,
1269 Register object_reg, 1210 Register object_reg,
1270 Handle<JSObject> holder, 1211 Handle<JSObject> holder,
1271 Handle<Name> name, 1212 Handle<Name> name,
1272 Handle<Object> callback) { 1213 Handle<Object> callback) {
1273 Label miss; 1214 Label miss;
1274 1215
1275 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); 1216 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
1276 1217
1277 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { 1218 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1278 ASSERT(!reg.is(scratch2())); 1219 ASSERT(!reg.is(scratch2()));
1279 ASSERT(!reg.is(scratch3())); 1220 ASSERT(!reg.is(scratch3()));
1280 ASSERT(!reg.is(scratch4())); 1221 ASSERT(!reg.is(scratch4()));
1281 1222
1282 // Load the properties dictionary. 1223 // Load the properties dictionary.
1283 Register dictionary = scratch4(); 1224 Register dictionary = scratch4();
1284 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); 1225 __ movp(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1285 1226
1286 // Probe the dictionary. 1227 // Probe the dictionary.
1287 Label probe_done; 1228 Label probe_done;
1288 NameDictionaryLookupStub::GeneratePositiveLookup(masm(), 1229 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1289 &miss, 1230 &miss,
1290 &probe_done, 1231 &probe_done,
1291 dictionary, 1232 dictionary,
1292 this->name(), 1233 this->name(),
1293 scratch2(), 1234 scratch2(),
1294 scratch3()); 1235 scratch3());
1295 __ bind(&probe_done); 1236 __ bind(&probe_done);
1296 1237
1297 // If probing finds an entry in the dictionary, scratch3 contains the 1238 // If probing finds an entry in the dictionary, scratch3 contains the
1298 // index into the dictionary. Check that the value is the callback. 1239 // index into the dictionary. Check that the value is the callback.
1299 Register index = scratch3(); 1240 Register index = scratch3();
1300 const int kElementsStartOffset = 1241 const int kElementsStartOffset =
1301 NameDictionary::kHeaderSize + 1242 NameDictionary::kHeaderSize +
1302 NameDictionary::kElementsStartIndex * kPointerSize; 1243 NameDictionary::kElementsStartIndex * kPointerSize;
1303 const int kValueOffset = kElementsStartOffset + kPointerSize; 1244 const int kValueOffset = kElementsStartOffset + kPointerSize;
1304 __ movq(scratch2(), 1245 __ movp(scratch2(),
1305 Operand(dictionary, index, times_pointer_size, 1246 Operand(dictionary, index, times_pointer_size,
1306 kValueOffset - kHeapObjectTag)); 1247 kValueOffset - kHeapObjectTag));
1307 __ Move(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT); 1248 __ Move(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT);
1308 __ cmpq(scratch2(), scratch3()); 1249 __ cmpq(scratch2(), scratch3());
1309 __ j(not_equal, &miss); 1250 __ j(not_equal, &miss);
1310 } 1251 }
1311 1252
1312 HandlerFrontendFooter(name, &miss); 1253 HandlerFrontendFooter(name, &miss);
1313 return reg; 1254 return reg;
1314 } 1255 }
1315 1256
1316 1257
1317 void LoadStubCompiler::GenerateLoadField(Register reg, 1258 void LoadStubCompiler::GenerateLoadField(Register reg,
1318 Handle<JSObject> holder, 1259 Handle<JSObject> holder,
1319 PropertyIndex field, 1260 PropertyIndex field,
1320 Representation representation) { 1261 Representation representation) {
1321 if (!reg.is(receiver())) __ movq(receiver(), reg); 1262 if (!reg.is(receiver())) __ movp(receiver(), reg);
1322 if (kind() == Code::LOAD_IC) { 1263 if (kind() == Code::LOAD_IC) {
1323 LoadFieldStub stub(field.is_inobject(holder), 1264 LoadFieldStub stub(field.is_inobject(holder),
1324 field.translate(holder), 1265 field.translate(holder),
1325 representation); 1266 representation);
1326 GenerateTailCall(masm(), stub.GetCode(isolate())); 1267 GenerateTailCall(masm(), stub.GetCode(isolate()));
1327 } else { 1268 } else {
1328 KeyedLoadFieldStub stub(field.is_inobject(holder), 1269 KeyedLoadFieldStub stub(field.is_inobject(holder),
1329 field.translate(holder), 1270 field.translate(holder),
1330 representation); 1271 representation);
1331 GenerateTailCall(masm(), stub.GetCode(isolate())); 1272 GenerateTailCall(masm(), stub.GetCode(isolate()));
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1380 Register getter_arg = r8; 1321 Register getter_arg = r8;
1381 Register accessor_info_arg = rdx; 1322 Register accessor_info_arg = rdx;
1382 Register name_arg = rcx; 1323 Register name_arg = rcx;
1383 #else 1324 #else
1384 Register getter_arg = rdx; 1325 Register getter_arg = rdx;
1385 Register accessor_info_arg = rsi; 1326 Register accessor_info_arg = rsi;
1386 Register name_arg = rdi; 1327 Register name_arg = rdi;
1387 #endif 1328 #endif
1388 1329
1389 ASSERT(!name_arg.is(scratch4())); 1330 ASSERT(!name_arg.is(scratch4()));
1390 __ movq(name_arg, rsp); 1331 __ movp(name_arg, rsp);
1391 __ PushReturnAddressFrom(scratch4()); 1332 __ PushReturnAddressFrom(scratch4());
1392 1333
1393 // v8::Arguments::values_ and handler for name. 1334 // v8::Arguments::values_ and handler for name.
1394 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1; 1335 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
1395 1336
1396 // Allocate v8::AccessorInfo in non-GCed stack space. 1337 // Allocate v8::AccessorInfo in non-GCed stack space.
1397 const int kArgStackSpace = 1; 1338 const int kArgStackSpace = 1;
1398 1339
1399 __ PrepareCallApiFunction(kArgStackSpace); 1340 __ PrepareCallApiFunction(kArgStackSpace);
1400 __ lea(rax, Operand(name_arg, 1 * kPointerSize)); 1341 __ lea(rax, Operand(name_arg, 1 * kPointerSize));
1401 1342
1402 // v8::PropertyAccessorInfo::args_. 1343 // v8::PropertyAccessorInfo::args_.
1403 __ movq(StackSpaceOperand(0), rax); 1344 __ movp(StackSpaceOperand(0), rax);
1404 1345
1405 // The context register (rsi) has been saved in PrepareCallApiFunction and 1346 // The context register (rsi) has been saved in PrepareCallApiFunction and
1406 // could be used to pass arguments. 1347 // could be used to pass arguments.
1407 __ lea(accessor_info_arg, StackSpaceOperand(0)); 1348 __ lea(accessor_info_arg, StackSpaceOperand(0));
1408 1349
1409 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); 1350 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
1410 1351
1411 // The name handler is counted as an argument. 1352 // The name handler is counted as an argument.
1412 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength); 1353 StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
1413 Operand return_value_operand = args.GetArgumentOperand( 1354 Operand return_value_operand = args.GetArgumentOperand(
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 __ j(not_equal, miss); 1477 __ j(not_equal, miss);
1537 } 1478 }
1538 1479
1539 1480
1540 void CallStubCompiler::GenerateLoadFunctionFromCell( 1481 void CallStubCompiler::GenerateLoadFunctionFromCell(
1541 Handle<Cell> cell, 1482 Handle<Cell> cell,
1542 Handle<JSFunction> function, 1483 Handle<JSFunction> function,
1543 Label* miss) { 1484 Label* miss) {
1544 // Get the value from the cell. 1485 // Get the value from the cell.
1545 __ Move(rdi, cell); 1486 __ Move(rdi, cell);
1546 __ movq(rdi, FieldOperand(rdi, Cell::kValueOffset)); 1487 __ movp(rdi, FieldOperand(rdi, Cell::kValueOffset));
1547 1488
1548 // Check that the cell contains the same function. 1489 // Check that the cell contains the same function.
1549 if (heap()->InNewSpace(*function)) { 1490 if (heap()->InNewSpace(*function)) {
1550 // We can't embed a pointer to a function in new space so we have 1491 // We can't embed a pointer to a function in new space so we have
1551 // to verify that the shared function info is unchanged. This has 1492 // to verify that the shared function info is unchanged. This has
1552 // the nice side effect that multiple closures based on the same 1493 // the nice side effect that multiple closures based on the same
1553 // function can all use this call IC. Before we load through the 1494 // function can all use this call IC. Before we load through the
1554 // function, we have to verify that it still is a function. 1495 // function, we have to verify that it still is a function.
1555 GenerateFunctionCheck(rdi, rax, miss); 1496 GenerateFunctionCheck(rdi, rax, miss);
1556 1497
(...skipping 29 matching lines...) Expand all
1586 index.translate(holder), Representation::Tagged()); 1527 index.translate(holder), Representation::Tagged());
1587 GenerateJumpFunction(object, rdi, &miss); 1528 GenerateJumpFunction(object, rdi, &miss);
1588 1529
1589 HandlerFrontendFooter(&miss); 1530 HandlerFrontendFooter(&miss);
1590 1531
1591 // Return the generated code. 1532 // Return the generated code.
1592 return GetCode(Code::FAST, name); 1533 return GetCode(Code::FAST, name);
1593 } 1534 }
1594 1535
1595 1536
1596 Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1597 Handle<Object> object,
1598 Handle<JSObject> holder,
1599 Handle<Cell> cell,
1600 Handle<JSFunction> function,
1601 Handle<String> name,
1602 Code::StubType type) {
1603 Label miss;
1604
1605 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1606 if (!cell.is_null()) {
1607 ASSERT(cell->value() == *function);
1608 GenerateLoadFunctionFromCell(cell, function, &miss);
1609 }
1610
1611 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
1612 site->SetElementsKind(GetInitialFastElementsKind());
1613 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
1614 const int argc = arguments().immediate();
1615 __ movq(rax, Immediate(argc));
1616 __ Move(rbx, site_feedback_cell);
1617 __ Move(rdi, function);
1618
1619 ArrayConstructorStub stub(isolate());
1620 __ TailCallStub(&stub);
1621
1622 HandlerFrontendFooter(&miss);
1623
1624 // Return the generated code.
1625 return GetCode(type, name);
1626 }
1627
1628
1629 Handle<Code> CallStubCompiler::CompileArrayPushCall(
1630 Handle<Object> object,
1631 Handle<JSObject> holder,
1632 Handle<Cell> cell,
1633 Handle<JSFunction> function,
1634 Handle<String> name,
1635 Code::StubType type) {
1636 // If object is not an array or is observed or sealed, bail out to regular
1637 // call.
1638 if (!object->IsJSArray() ||
1639 !cell.is_null() ||
1640 Handle<JSArray>::cast(object)->map()->is_observed() ||
1641 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
1642 return Handle<Code>::null();
1643 }
1644
1645 Label miss;
1646
1647 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1648
1649 const int argc = arguments().immediate();
1650 StackArgumentsAccessor args(rsp, argc);
1651 if (argc == 0) {
1652 // Noop, return the length.
1653 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1654 __ ret((argc + 1) * kPointerSize);
1655 } else {
1656 Label call_builtin;
1657
1658 if (argc == 1) { // Otherwise fall through to call builtin.
1659 Label attempt_to_grow_elements, with_write_barrier, check_double;
1660
1661 // Get the elements array of the object.
1662 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1663
1664 // Check that the elements are in fast mode and writable.
1665 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1666 factory()->fixed_array_map());
1667 __ j(not_equal, &check_double);
1668
1669 // Get the array's length into rax and calculate new length.
1670 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1671 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1672 __ addl(rax, Immediate(argc));
1673
1674 // Get the elements' length into rcx.
1675 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1676
1677 // Check if we could survive without allocation.
1678 __ cmpl(rax, rcx);
1679 __ j(greater, &attempt_to_grow_elements);
1680
1681 // Check if value is a smi.
1682 __ movq(rcx, args.GetArgumentOperand(1));
1683 __ JumpIfNotSmi(rcx, &with_write_barrier);
1684
1685 // Save new length.
1686 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1687
1688 // Store the value.
1689 __ movq(FieldOperand(rdi,
1690 rax,
1691 times_pointer_size,
1692 FixedArray::kHeaderSize - argc * kPointerSize),
1693 rcx);
1694
1695 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1696 __ ret((argc + 1) * kPointerSize);
1697
1698 __ bind(&check_double);
1699
1700 // Check that the elements are in double mode.
1701 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
1702 factory()->fixed_double_array_map());
1703 __ j(not_equal, &call_builtin);
1704
1705 // Get the array's length into rax and calculate new length.
1706 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset));
1707 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue);
1708 __ addl(rax, Immediate(argc));
1709
1710 // Get the elements' length into rcx.
1711 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
1712
1713 // Check if we could survive without allocation.
1714 __ cmpl(rax, rcx);
1715 __ j(greater, &call_builtin);
1716
1717 __ movq(rcx, args.GetArgumentOperand(1));
1718 __ StoreNumberToDoubleElements(
1719 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
1720
1721 // Save new length.
1722 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1723 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1724 __ ret((argc + 1) * kPointerSize);
1725
1726 __ bind(&with_write_barrier);
1727
1728 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1729
1730 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1731 Label fast_object, not_fast_object;
1732 __ CheckFastObjectElements(rbx, &not_fast_object, Label::kNear);
1733 __ jmp(&fast_object);
1734 // In case of fast smi-only, convert to fast object, otherwise bail out.
1735 __ bind(&not_fast_object);
1736 __ CheckFastSmiElements(rbx, &call_builtin);
1737 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1738 factory()->heap_number_map());
1739 __ j(equal, &call_builtin);
1740 // rdx: receiver
1741 // rbx: map
1742
1743 Label try_holey_map;
1744 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1745 FAST_ELEMENTS,
1746 rbx,
1747 rdi,
1748 &try_holey_map);
1749
1750 ElementsTransitionGenerator::
1751 GenerateMapChangeElementsTransition(masm(),
1752 DONT_TRACK_ALLOCATION_SITE,
1753 NULL);
1754 // Restore edi.
1755 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1756 __ jmp(&fast_object);
1757
1758 __ bind(&try_holey_map);
1759 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1760 FAST_HOLEY_ELEMENTS,
1761 rbx,
1762 rdi,
1763 &call_builtin);
1764 ElementsTransitionGenerator::
1765 GenerateMapChangeElementsTransition(masm(),
1766 DONT_TRACK_ALLOCATION_SITE,
1767 NULL);
1768 __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
1769 __ bind(&fast_object);
1770 } else {
1771 __ CheckFastObjectElements(rbx, &call_builtin);
1772 }
1773
1774 // Save new length.
1775 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1776
1777 // Store the value.
1778 __ lea(rdx, FieldOperand(rdi,
1779 rax, times_pointer_size,
1780 FixedArray::kHeaderSize - argc * kPointerSize));
1781 __ movq(Operand(rdx, 0), rcx);
1782
1783 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
1784 OMIT_SMI_CHECK);
1785
1786 __ Integer32ToSmi(rax, rax); // Return new length as smi.
1787 __ ret((argc + 1) * kPointerSize);
1788
1789 __ bind(&attempt_to_grow_elements);
1790 if (!FLAG_inline_new) {
1791 __ jmp(&call_builtin);
1792 }
1793
1794 __ movq(rbx, args.GetArgumentOperand(1));
1795 // Growing elements that are SMI-only requires special handling in case
1796 // the new element is non-Smi. For now, delegate to the builtin.
1797 Label no_fast_elements_check;
1798 __ JumpIfSmi(rbx, &no_fast_elements_check);
1799 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1800 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar);
1801 __ bind(&no_fast_elements_check);
1802
1803 ExternalReference new_space_allocation_top =
1804 ExternalReference::new_space_allocation_top_address(isolate());
1805 ExternalReference new_space_allocation_limit =
1806 ExternalReference::new_space_allocation_limit_address(isolate());
1807
1808 const int kAllocationDelta = 4;
1809 // Load top.
1810 __ Load(rcx, new_space_allocation_top);
1811
1812 // Check if it's the end of elements.
1813 __ lea(rdx, FieldOperand(rdi,
1814 rax, times_pointer_size,
1815 FixedArray::kHeaderSize - argc * kPointerSize));
1816 __ cmpq(rdx, rcx);
1817 __ j(not_equal, &call_builtin);
1818 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
1819 Operand limit_operand =
1820 masm()->ExternalOperand(new_space_allocation_limit);
1821 __ cmpq(rcx, limit_operand);
1822 __ j(above, &call_builtin);
1823
1824 // We fit and could grow elements.
1825 __ Store(new_space_allocation_top, rcx);
1826
1827 // Push the argument...
1828 __ movq(Operand(rdx, 0), rbx);
1829 // ... and fill the rest with holes.
1830 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
1831 for (int i = 1; i < kAllocationDelta; i++) {
1832 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister);
1833 }
1834
1835 // We know the elements array is in new space so we don't need the
1836 // remembered set, but we just pushed a value onto it so we may have to
1837 // tell the incremental marker to rescan the object that we just grew. We
1838 // don't need to worry about the holes because they are in old space and
1839 // already marked black.
1840 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
1841
1842 // Restore receiver to rdx as finish sequence assumes it's here.
1843 __ movq(rdx, args.GetReceiverOperand());
1844
1845 // Increment element's and array's sizes.
1846 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
1847 Smi::FromInt(kAllocationDelta));
1848
1849 // Make new length a smi before returning it.
1850 __ Integer32ToSmi(rax, rax);
1851 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax);
1852
1853 __ ret((argc + 1) * kPointerSize);
1854 }
1855
1856 __ bind(&call_builtin);
1857 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1858 isolate()),
1859 argc + 1,
1860 1);
1861 }
1862
1863 HandlerFrontendFooter(&miss);
1864
1865 // Return the generated code.
1866 return GetCode(type, name);
1867 }
1868
1869
1870 Handle<Code> CallStubCompiler::CompileArrayPopCall(
1871 Handle<Object> object,
1872 Handle<JSObject> holder,
1873 Handle<Cell> cell,
1874 Handle<JSFunction> function,
1875 Handle<String> name,
1876 Code::StubType type) {
1877 // If object is not an array or is observed or sealed, bail out to regular
1878 // call.
1879 if (!object->IsJSArray() ||
1880 !cell.is_null() ||
1881 Handle<JSArray>::cast(object)->map()->is_observed() ||
1882 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
1883 return Handle<Code>::null();
1884 }
1885
1886 Label miss, return_undefined, call_builtin;
1887
1888 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1889
1890 // Get the elements array of the object.
1891 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1892
1893 // Check that the elements are in fast mode and writable.
1894 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1895 Heap::kFixedArrayMapRootIndex);
1896 __ j(not_equal, &call_builtin);
1897
1898 // Get the array's length into rcx and calculate new length.
1899 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
1900 __ subl(rcx, Immediate(1));
1901 __ j(negative, &return_undefined);
1902
1903 // Get the last element.
1904 __ LoadRoot(r9, Heap::kTheHoleValueRootIndex);
1905 __ movq(rax, FieldOperand(rbx,
1906 rcx, times_pointer_size,
1907 FixedArray::kHeaderSize));
1908 // Check if element is already the hole.
1909 __ cmpq(rax, r9);
1910 // If so, call slow-case to also check prototypes for value.
1911 __ j(equal, &call_builtin);
1912
1913 // Set the array's length.
1914 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
1915
1916 // Fill with the hole and return original value.
1917 __ movq(FieldOperand(rbx,
1918 rcx, times_pointer_size,
1919 FixedArray::kHeaderSize),
1920 r9);
1921 const int argc = arguments().immediate();
1922 __ ret((argc + 1) * kPointerSize);
1923
1924 __ bind(&return_undefined);
1925 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1926 __ ret((argc + 1) * kPointerSize);
1927
1928 __ bind(&call_builtin);
1929 __ TailCallExternalReference(
1930 ExternalReference(Builtins::c_ArrayPop, isolate()),
1931 argc + 1,
1932 1);
1933
1934 HandlerFrontendFooter(&miss);
1935
1936 // Return the generated code.
1937 return GetCode(type, name);
1938 }
1939
1940
1941 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1942 Handle<Object> object,
1943 Handle<JSObject> holder,
1944 Handle<Cell> cell,
1945 Handle<JSFunction> function,
1946 Handle<String> name,
1947 Code::StubType type) {
1948 // If object is not a string, bail out to regular call.
1949 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
1950
1951 Label miss;
1952 Label name_miss;
1953 Label index_out_of_range;
1954 Label* index_out_of_range_label = &index_out_of_range;
1955 if (kind_ == Code::CALL_IC &&
1956 (CallICBase::StringStubState::decode(extra_state()) ==
1957 DEFAULT_STRING_STUB)) {
1958 index_out_of_range_label = &miss;
1959 }
1960
1961 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
1962
1963 Register receiver = rbx;
1964 Register index = rdi;
1965 Register result = rax;
1966 const int argc = arguments().immediate();
1967 StackArgumentsAccessor args(rsp, argc);
1968
1969 __ movq(receiver, args.GetReceiverOperand());
1970 if (argc > 0) {
1971 __ movq(index, args.GetArgumentOperand(1));
1972 } else {
1973 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1974 }
1975
1976 StringCharCodeAtGenerator generator(receiver,
1977 index,
1978 result,
1979 &miss, // When not a string.
1980 &miss, // When not a number.
1981 index_out_of_range_label,
1982 STRING_INDEX_IS_NUMBER);
1983 generator.GenerateFast(masm());
1984 __ ret((argc + 1) * kPointerSize);
1985
1986 StubRuntimeCallHelper call_helper;
1987 generator.GenerateSlow(masm(), call_helper);
1988
1989 if (index_out_of_range.is_linked()) {
1990 __ bind(&index_out_of_range);
1991 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1992 __ ret((argc + 1) * kPointerSize);
1993 }
1994
1995 __ bind(&miss);
1996 // Restore function name in rcx.
1997 __ Move(rcx, name);
1998 HandlerFrontendFooter(&name_miss);
1999
2000 // Return the generated code.
2001 return GetCode(type, name);
2002 }
2003
2004
2005 Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2006 Handle<Object> object,
2007 Handle<JSObject> holder,
2008 Handle<Cell> cell,
2009 Handle<JSFunction> function,
2010 Handle<String> name,
2011 Code::StubType type) {
2012 // If object is not a string, bail out to regular call.
2013 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
2014
2015 const int argc = arguments().immediate();
2016 StackArgumentsAccessor args(rsp, argc);
2017
2018 Label miss;
2019 Label name_miss;
2020 Label index_out_of_range;
2021 Label* index_out_of_range_label = &index_out_of_range;
2022 if (kind_ == Code::CALL_IC &&
2023 (CallICBase::StringStubState::decode(extra_state()) ==
2024 DEFAULT_STRING_STUB)) {
2025 index_out_of_range_label = &miss;
2026 }
2027
2028 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
2029
2030 Register receiver = rax;
2031 Register index = rdi;
2032 Register scratch = rdx;
2033 Register result = rax;
2034 __ movq(receiver, args.GetReceiverOperand());
2035 if (argc > 0) {
2036 __ movq(index, args.GetArgumentOperand(1));
2037 } else {
2038 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2039 }
2040
2041 StringCharAtGenerator generator(receiver,
2042 index,
2043 scratch,
2044 result,
2045 &miss, // When not a string.
2046 &miss, // When not a number.
2047 index_out_of_range_label,
2048 STRING_INDEX_IS_NUMBER);
2049 generator.GenerateFast(masm());
2050 __ ret((argc + 1) * kPointerSize);
2051
2052 StubRuntimeCallHelper call_helper;
2053 generator.GenerateSlow(masm(), call_helper);
2054
2055 if (index_out_of_range.is_linked()) {
2056 __ bind(&index_out_of_range);
2057 __ LoadRoot(rax, Heap::kempty_stringRootIndex);
2058 __ ret((argc + 1) * kPointerSize);
2059 }
2060 __ bind(&miss);
2061 // Restore function name in rcx.
2062 __ Move(rcx, name);
2063 HandlerFrontendFooter(&name_miss);
2064
2065 // Return the generated code.
2066 return GetCode(type, name);
2067 }
2068
2069
2070 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2071 Handle<Object> object,
2072 Handle<JSObject> holder,
2073 Handle<Cell> cell,
2074 Handle<JSFunction> function,
2075 Handle<String> name,
2076 Code::StubType type) {
2077 // If the object is not a JSObject or we got an unexpected number of
2078 // arguments, bail out to the regular call.
2079 const int argc = arguments().immediate();
2080 StackArgumentsAccessor args(rsp, argc);
2081 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2082
2083 Label miss;
2084
2085 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2086 if (!cell.is_null()) {
2087 ASSERT(cell->value() == *function);
2088 GenerateLoadFunctionFromCell(cell, function, &miss);
2089 }
2090
2091 // Load the char code argument.
2092 Register code = rbx;
2093 __ movq(code, args.GetArgumentOperand(1));
2094
2095 // Check the code is a smi.
2096 Label slow;
2097 __ JumpIfNotSmi(code, &slow);
2098
2099 // Convert the smi code to uint16.
2100 __ SmiAndConstant(code, code, Smi::FromInt(0xffff));
2101
2102 StringCharFromCodeGenerator generator(code, rax);
2103 generator.GenerateFast(masm());
2104 __ ret(2 * kPointerSize);
2105
2106 StubRuntimeCallHelper call_helper;
2107 generator.GenerateSlow(masm(), call_helper);
2108
2109 __ bind(&slow);
2110 // We do not have to patch the receiver because the function makes no use of
2111 // it.
2112 GenerateJumpFunctionIgnoreReceiver(function);
2113
2114 HandlerFrontendFooter(&miss);
2115
2116 // Return the generated code.
2117 return GetCode(type, name);
2118 }
2119
2120
2121 Handle<Code> CallStubCompiler::CompileMathFloorCall(
2122 Handle<Object> object,
2123 Handle<JSObject> holder,
2124 Handle<Cell> cell,
2125 Handle<JSFunction> function,
2126 Handle<String> name,
2127 Code::StubType type) {
2128 const int argc = arguments().immediate();
2129 StackArgumentsAccessor args(rsp, argc);
2130
2131 // If the object is not a JSObject or we got an unexpected number of
2132 // arguments, bail out to the regular call.
2133 if (!object->IsJSObject() || argc != 1) {
2134 return Handle<Code>::null();
2135 }
2136
2137 Label miss, slow;
2138
2139 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2140 if (!cell.is_null()) {
2141 ASSERT(cell->value() == *function);
2142 GenerateLoadFunctionFromCell(cell, function, &miss);
2143 }
2144
2145 // Load the (only) argument into rax.
2146 __ movq(rax, args.GetArgumentOperand(1));
2147
2148 // Check if the argument is a smi.
2149 Label smi;
2150 STATIC_ASSERT(kSmiTag == 0);
2151 __ JumpIfSmi(rax, &smi);
2152
2153 // Check if the argument is a heap number and load its value into xmm0.
2154 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2155 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
2156
2157 // Check if the argument is strictly positive. Note this also discards NaN.
2158 __ xorpd(xmm1, xmm1);
2159 __ ucomisd(xmm0, xmm1);
2160 __ j(below_equal, &slow);
2161
2162 // Do a truncating conversion.
2163 __ cvttsd2si(rax, xmm0);
2164
2165 // Checks for 0x80000000 which signals a failed conversion.
2166 Label conversion_failure;
2167 __ cmpl(rax, Immediate(0x80000000));
2168 __ j(equal, &conversion_failure);
2169
2170 // Smi tag and return.
2171 __ Integer32ToSmi(rax, rax);
2172 __ bind(&smi);
2173 __ ret(2 * kPointerSize);
2174
2175 // Check if the argument is < 2^kMantissaBits.
2176 Label already_round;
2177 __ bind(&conversion_failure);
2178 int64_t kTwoMantissaBits= V8_INT64_C(0x4330000000000000);
2179 __ movq(rbx, kTwoMantissaBits);
2180 __ movq(xmm1, rbx);
2181 __ ucomisd(xmm0, xmm1);
2182 __ j(above_equal, &already_round);
2183
2184 // Save a copy of the argument.
2185 __ movaps(xmm2, xmm0);
2186
2187 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2188 __ addsd(xmm0, xmm1);
2189 __ subsd(xmm0, xmm1);
2190
2191 // Compare the argument and the tentative result to get the right mask:
2192 // if xmm2 < xmm0:
2193 // xmm2 = 1...1
2194 // else:
2195 // xmm2 = 0...0
2196 __ cmpltsd(xmm2, xmm0);
2197
2198 // Subtract 1 if the argument was less than the tentative result.
2199 int64_t kOne = V8_INT64_C(0x3ff0000000000000);
2200 __ movq(rbx, kOne);
2201 __ movq(xmm1, rbx);
2202 __ andpd(xmm1, xmm2);
2203 __ subsd(xmm0, xmm1);
2204
2205 // Return a new heap number.
2206 __ AllocateHeapNumber(rax, rbx, &slow);
2207 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
2208 __ ret(2 * kPointerSize);
2209
2210 // Return the argument (when it's an already round heap number).
2211 __ bind(&already_round);
2212 __ movq(rax, args.GetArgumentOperand(1));
2213 __ ret(2 * kPointerSize);
2214
2215 __ bind(&slow);
2216 // We do not have to patch the receiver because the function makes no use of
2217 // it.
2218 GenerateJumpFunctionIgnoreReceiver(function);
2219
2220 HandlerFrontendFooter(&miss);
2221
2222 // Return the generated code.
2223 return GetCode(type, name);
2224 }
2225
2226
2227 Handle<Code> CallStubCompiler::CompileMathAbsCall(
2228 Handle<Object> object,
2229 Handle<JSObject> holder,
2230 Handle<Cell> cell,
2231 Handle<JSFunction> function,
2232 Handle<String> name,
2233 Code::StubType type) {
2234 // If the object is not a JSObject or we got an unexpected number of
2235 // arguments, bail out to the regular call.
2236 const int argc = arguments().immediate();
2237 StackArgumentsAccessor args(rsp, argc);
2238 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
2239
2240 Label miss;
2241
2242 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2243 if (!cell.is_null()) {
2244 ASSERT(cell->value() == *function);
2245 GenerateLoadFunctionFromCell(cell, function, &miss);
2246 }
2247
2248 // Load the (only) argument into rax.
2249 __ movq(rax, args.GetArgumentOperand(1));
2250
2251 // Check if the argument is a smi.
2252 Label not_smi;
2253 STATIC_ASSERT(kSmiTag == 0);
2254 __ JumpIfNotSmi(rax, &not_smi);
2255
2256 // Branchless abs implementation, refer to below:
2257 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
2258 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2259 // otherwise.
2260 __ movq(rbx, rax);
2261 __ sar(rbx, Immediate(kBitsPerPointer - 1));
2262
2263 // Do bitwise not or do nothing depending on ebx.
2264 __ xor_(rax, rbx);
2265
2266 // Add 1 or do nothing depending on ebx.
2267 __ subq(rax, rbx);
2268
2269 // If the result is still negative, go to the slow case.
2270 // This only happens for the most negative smi.
2271 Label slow;
2272 __ j(negative, &slow);
2273
2274 __ ret(2 * kPointerSize);
2275
2276 // Check if the argument is a heap number and load its value.
2277 __ bind(&not_smi);
2278 __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
2279 __ MoveDouble(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
2280
2281 // Check the sign of the argument. If the argument is positive,
2282 // just return it.
2283 Label negative_sign;
2284 const int sign_mask_shift =
2285 (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte;
2286 __ Set(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift);
2287 __ testq(rbx, rdi);
2288 __ j(not_zero, &negative_sign);
2289 __ ret(2 * kPointerSize);
2290
2291 // If the argument is negative, clear the sign, and return a new
2292 // number. We still have the sign mask in rdi.
2293 __ bind(&negative_sign);
2294 __ xor_(rbx, rdi);
2295 __ AllocateHeapNumber(rax, rdx, &slow);
2296 __ MoveDouble(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
2297 __ ret(2 * kPointerSize);
2298
2299 __ bind(&slow);
2300 // We do not have to patch the receiver because the function makes no use of
2301 // it.
2302 GenerateJumpFunctionIgnoreReceiver(function);
2303
2304 HandlerFrontendFooter(&miss);
2305
2306 // Return the generated code.
2307 return GetCode(type, name);
2308 }
2309
2310
2311 Handle<Code> CallStubCompiler::CompileFastApiCall( 1537 Handle<Code> CallStubCompiler::CompileFastApiCall(
2312 const CallOptimization& optimization, 1538 const CallOptimization& optimization,
2313 Handle<Object> object, 1539 Handle<Object> object,
2314 Handle<JSObject> holder, 1540 Handle<JSObject> holder,
2315 Handle<Cell> cell, 1541 Handle<Cell> cell,
2316 Handle<JSFunction> function, 1542 Handle<JSFunction> function,
2317 Handle<String> name) { 1543 Handle<String> name) {
2318 ASSERT(optimization.is_simple_api_call()); 1544 ASSERT(optimization.is_simple_api_call());
2319 // Bail out if object is a global object as we don't want to 1545 // Bail out if object is a global object as we don't want to
2320 // repatch it to global receiver. 1546 // repatch it to global receiver.
2321 if (object->IsGlobalObject()) return Handle<Code>::null(); 1547 if (object->IsGlobalObject()) return Handle<Code>::null();
2322 if (!cell.is_null()) return Handle<Code>::null(); 1548 if (!cell.is_null()) return Handle<Code>::null();
2323 if (!object->IsJSObject()) return Handle<Code>::null(); 1549 if (!object->IsJSObject()) return Handle<Code>::null();
2324 int depth = optimization.GetPrototypeDepthOfExpectedType( 1550 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2325 Handle<JSObject>::cast(object), holder); 1551 CallOptimization::HolderLookup holder_lookup =
2326 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); 1552 CallOptimization::kHolderNotFound;
1553 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
1554 receiver, receiver, holder, &holder_lookup);
1555 if (holder_lookup == CallOptimization::kHolderNotFound) {
1556 return Handle<Code>::null();
1557 }
2327 1558
2328 Label miss, miss_before_stack_reserved; 1559 Label miss;
2329 GenerateNameCheck(name, &miss_before_stack_reserved); 1560 GenerateNameCheck(name, &miss);
2330 1561
2331 const int argc = arguments().immediate(); 1562 const int argc = arguments().immediate();
2332 StackArgumentsAccessor args(rsp, argc); 1563 StackArgumentsAccessor args(rsp, argc);
2333 __ movq(rdx, args.GetReceiverOperand()); 1564 __ movp(rdx, args.GetReceiverOperand());
2334 1565
2335 // Check that the receiver isn't a smi. 1566 // Check that the receiver isn't a smi.
2336 __ JumpIfSmi(rdx, &miss_before_stack_reserved); 1567 __ JumpIfSmi(rdx, &miss);
2337 1568
2338 Counters* counters = isolate()->counters(); 1569 Counters* counters = isolate()->counters();
2339 __ IncrementCounter(counters->call_const(), 1); 1570 __ IncrementCounter(counters->call_const(), 1);
2340 __ IncrementCounter(counters->call_const_fast_api(), 1);
2341
2342 // Allocate space for v8::Arguments implicit values. Must be initialized
2343 // before calling any runtime function.
2344 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2345 1571
2346 // Check that the maps haven't changed and find a Holder as a side effect. 1572 // Check that the maps haven't changed and find a Holder as a side effect.
2347 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder, 1573 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
2348 rbx, rax, rdi, name, depth, &miss); 1574 rbx, rax, rdi, name, &miss);
2349 1575
2350 // Move the return address on top of the stack. 1576 GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup);
2351 __ movq(rax,
2352 StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize));
2353 __ movq(StackOperandForReturnAddress(0), rax);
2354 1577
2355 GenerateFastApiCall(masm(), optimization, argc); 1578 HandlerFrontendFooter(&miss);
2356
2357 __ bind(&miss);
2358 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2359
2360 HandlerFrontendFooter(&miss_before_stack_reserved);
2361 1579
2362 // Return the generated code. 1580 // Return the generated code.
2363 return GetCode(function); 1581 return GetCode(function);
2364 } 1582 }
2365 1583
2366 1584
2367 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { 1585 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2368 Label success; 1586 Label success;
2369 // Check that the object is a boolean. 1587 // Check that the object is a boolean.
2370 __ CompareRoot(object, Heap::kTrueValueRootIndex); 1588 __ CompareRoot(object, Heap::kTrueValueRootIndex);
2371 __ j(equal, &success); 1589 __ j(equal, &success);
2372 __ CompareRoot(object, Heap::kFalseValueRootIndex); 1590 __ CompareRoot(object, Heap::kFalseValueRootIndex);
2373 __ j(not_equal, miss); 1591 __ j(not_equal, miss);
2374 __ bind(&success); 1592 __ bind(&success);
2375 } 1593 }
2376 1594
2377 1595
2378 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { 1596 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) {
2379 if (object->IsGlobalObject()) { 1597 if (object->IsGlobalObject()) {
2380 StackArgumentsAccessor args(rsp, arguments()); 1598 StackArgumentsAccessor args(rsp, arguments());
2381 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 1599 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
2382 __ movq(args.GetReceiverOperand(), rdx); 1600 __ movp(args.GetReceiverOperand(), rdx);
2383 } 1601 }
2384 } 1602 }
2385 1603
2386 1604
2387 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, 1605 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object,
2388 Handle<JSObject> holder, 1606 Handle<JSObject> holder,
2389 Handle<Name> name, 1607 Handle<Name> name,
2390 CheckType check, 1608 CheckType check,
2391 Label* miss) { 1609 Label* miss) {
2392 GenerateNameCheck(name, miss); 1610 GenerateNameCheck(name, miss);
2393 1611
2394 Register reg = rdx; 1612 Register reg = rdx;
2395 1613
2396 StackArgumentsAccessor args(rsp, arguments()); 1614 StackArgumentsAccessor args(rsp, arguments());
2397 __ movq(reg, args.GetReceiverOperand()); 1615 __ movp(reg, args.GetReceiverOperand());
2398 1616
2399 // Check that the receiver isn't a smi. 1617 // Check that the receiver isn't a smi.
2400 if (check != NUMBER_CHECK) { 1618 if (check != NUMBER_CHECK) {
2401 __ JumpIfSmi(reg, miss); 1619 __ JumpIfSmi(reg, miss);
2402 } 1620 }
2403 1621
2404 // Make sure that it's okay not to patch the on stack receiver 1622 // Make sure that it's okay not to patch the on stack receiver
2405 // unless we're doing a receiver map check. 1623 // unless we're doing a receiver map check.
2406 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); 1624 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2407 1625
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
2464 return reg; 1682 return reg;
2465 } 1683 }
2466 1684
2467 1685
2468 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, 1686 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
2469 Register function, 1687 Register function,
2470 Label* miss) { 1688 Label* miss) {
2471 // Check that the function really is a function. 1689 // Check that the function really is a function.
2472 GenerateFunctionCheck(function, rbx, miss); 1690 GenerateFunctionCheck(function, rbx, miss);
2473 1691
2474 if (!function.is(rdi)) __ movq(rdi, function); 1692 if (!function.is(rdi)) __ movp(rdi, function);
2475 PatchImplicitReceiver(object); 1693 PatchImplicitReceiver(object);
2476 1694
2477 // Invoke the function. 1695 // Invoke the function.
2478 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, NullCallWrapper()); 1696 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, NullCallWrapper());
2479 } 1697 }
2480 1698
2481 1699
2482 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, 1700 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2483 Handle<JSObject> holder, 1701 Handle<JSObject> holder,
2484 Handle<Name> name) { 1702 Handle<Name> name) {
2485 Label miss; 1703 Label miss;
2486 GenerateNameCheck(name, &miss); 1704 GenerateNameCheck(name, &miss);
2487 1705
2488 LookupResult lookup(isolate()); 1706 LookupResult lookup(isolate());
2489 LookupPostInterceptor(holder, name, &lookup); 1707 LookupPostInterceptor(holder, name, &lookup);
2490 1708
2491 // Get the receiver from the stack. 1709 // Get the receiver from the stack.
2492 StackArgumentsAccessor args(rsp, arguments()); 1710 StackArgumentsAccessor args(rsp, arguments());
2493 __ movq(rdx, args.GetReceiverOperand()); 1711 __ movp(rdx, args.GetReceiverOperand());
2494 1712
2495 CallInterceptorCompiler compiler(this, arguments(), rcx); 1713 CallInterceptorCompiler compiler(this, arguments(), rcx);
2496 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax, 1714 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
2497 &miss); 1715 &miss);
2498 1716
2499 // Restore receiver. 1717 // Restore receiver.
2500 __ movq(rdx, args.GetReceiverOperand()); 1718 __ movp(rdx, args.GetReceiverOperand());
2501 1719
2502 GenerateJumpFunction(object, rax, &miss); 1720 GenerateJumpFunction(object, rax, &miss);
2503 1721
2504 HandlerFrontendFooter(&miss); 1722 HandlerFrontendFooter(&miss);
2505 1723
2506 // Return the generated code. 1724 // Return the generated code.
2507 return GetCode(Code::FAST, name); 1725 return GetCode(Code::FAST, name);
2508 } 1726 }
2509 1727
2510 1728
(...skipping 24 matching lines...) Expand all
2535 // Return the generated code. 1753 // Return the generated code.
2536 return GetCode(Code::NORMAL, name); 1754 return GetCode(Code::NORMAL, name);
2537 } 1755 }
2538 1756
2539 1757
2540 Handle<Code> StoreStubCompiler::CompileStoreCallback( 1758 Handle<Code> StoreStubCompiler::CompileStoreCallback(
2541 Handle<JSObject> object, 1759 Handle<JSObject> object,
2542 Handle<JSObject> holder, 1760 Handle<JSObject> holder,
2543 Handle<Name> name, 1761 Handle<Name> name,
2544 Handle<ExecutableAccessorInfo> callback) { 1762 Handle<ExecutableAccessorInfo> callback) {
2545 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), 1763 Register holder_reg = HandlerFrontend(
2546 receiver(), holder, name); 1764 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
2547 1765
2548 __ PopReturnAddressTo(scratch1()); 1766 __ PopReturnAddressTo(scratch1());
2549 __ push(receiver()); 1767 __ push(receiver());
1768 __ push(holder_reg);
2550 __ Push(callback); // callback info 1769 __ Push(callback); // callback info
2551 __ Push(name); 1770 __ Push(name);
2552 __ push(value()); 1771 __ push(value());
2553 __ PushReturnAddressFrom(scratch1()); 1772 __ PushReturnAddressFrom(scratch1());
2554 1773
2555 // Do tail-call to the runtime system. 1774 // Do tail-call to the runtime system.
2556 ExternalReference store_callback_property = 1775 ExternalReference store_callback_property =
2557 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); 1776 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
2558 __ TailCallExternalReference(store_callback_property, 4, 1); 1777 __ TailCallExternalReference(store_callback_property, 5, 1);
2559 1778
2560 // Return the generated code. 1779 // Return the generated code.
2561 return GetCode(kind(), Code::FAST, name); 1780 return GetCode(kind(), Code::FAST, name);
2562 } 1781 }
2563 1782
2564 1783
2565 Handle<Code> StoreStubCompiler::CompileStoreCallback( 1784 Handle<Code> StoreStubCompiler::CompileStoreCallback(
2566 Handle<JSObject> object, 1785 Handle<JSObject> object,
2567 Handle<JSObject> holder, 1786 Handle<JSObject> holder,
2568 Handle<Name> name, 1787 Handle<Name> name,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
2610 } else { 1829 } else {
2611 // If we generate a global code snippet for deoptimization only, remember 1830 // If we generate a global code snippet for deoptimization only, remember
2612 // the place to continue after deoptimization. 1831 // the place to continue after deoptimization.
2613 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); 1832 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2614 } 1833 }
2615 1834
2616 // We have to return the passed value, not the return value of the setter. 1835 // We have to return the passed value, not the return value of the setter.
2617 __ pop(rax); 1836 __ pop(rax);
2618 1837
2619 // Restore context register. 1838 // Restore context register.
2620 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1839 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2621 } 1840 }
2622 __ ret(0); 1841 __ ret(0);
2623 } 1842 }
2624 1843
2625 1844
2626 #undef __ 1845 #undef __
2627 #define __ ACCESS_MASM(masm()) 1846 #define __ ACCESS_MASM(masm())
2628 1847
2629 1848
2630 Handle<Code> StoreStubCompiler::CompileStoreInterceptor( 1849 Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
(...skipping 15 matching lines...) Expand all
2646 } 1865 }
2647 1866
2648 1867
2649 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic( 1868 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2650 MapHandleList* receiver_maps, 1869 MapHandleList* receiver_maps,
2651 CodeHandleList* handler_stubs, 1870 CodeHandleList* handler_stubs,
2652 MapHandleList* transitioned_maps) { 1871 MapHandleList* transitioned_maps) {
2653 Label miss; 1872 Label miss;
2654 __ JumpIfSmi(receiver(), &miss, Label::kNear); 1873 __ JumpIfSmi(receiver(), &miss, Label::kNear);
2655 1874
2656 __ movq(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); 1875 __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
2657 int receiver_count = receiver_maps->length(); 1876 int receiver_count = receiver_maps->length();
2658 for (int i = 0; i < receiver_count; ++i) { 1877 for (int i = 0; i < receiver_count; ++i) {
2659 // Check map and tail call if there's a match 1878 // Check map and tail call if there's a match
2660 __ Cmp(scratch1(), receiver_maps->at(i)); 1879 __ Cmp(scratch1(), receiver_maps->at(i));
2661 if (transitioned_maps->at(i).is_null()) { 1880 if (transitioned_maps->at(i).is_null()) {
2662 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET); 1881 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
2663 } else { 1882 } else {
2664 Label next_map; 1883 Label next_map;
2665 __ j(not_equal, &next_map, Label::kNear); 1884 __ j(not_equal, &next_map, Label::kNear);
2666 __ Move(transition_map(), 1885 __ Move(transition_map(),
2667 transitioned_maps->at(i), 1886 transitioned_maps->at(i),
2668 RelocInfo::EMBEDDED_OBJECT); 1887 RelocInfo::EMBEDDED_OBJECT);
2669 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); 1888 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
2670 __ bind(&next_map); 1889 __ bind(&next_map);
2671 } 1890 }
2672 } 1891 }
2673 1892
2674 __ bind(&miss); 1893 __ bind(&miss);
2675 1894
2676 TailCallBuiltin(masm(), MissBuiltin(kind())); 1895 TailCallBuiltin(masm(), MissBuiltin(kind()));
2677 1896
2678 // Return the generated code. 1897 // Return the generated code.
2679 return GetICCode( 1898 return GetICCode(
2680 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); 1899 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
2681 } 1900 }
2682 1901
2683 1902
2684 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, 1903 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type,
2685 Handle<JSObject> last, 1904 Handle<JSObject> last,
2686 Handle<Name> name) { 1905 Handle<Name> name) {
2687 NonexistentHandlerFrontend(type, last, name); 1906 NonexistentHandlerFrontend(type, last, name);
2688 1907
2689 // Return undefined if maps of the full prototype chain are still the 1908 // Return undefined if maps of the full prototype chain are still the
2690 // same and no global property with this name contains a value. 1909 // same and no global property with this name contains a value.
2691 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 1910 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2692 __ ret(0); 1911 __ ret(0);
2693 1912
2694 // Return the generated code. 1913 // Return the generated code.
(...skipping 22 matching lines...) Expand all
2717 } 1936 }
2718 1937
2719 1938
2720 Register* KeyedStoreStubCompiler::registers() { 1939 Register* KeyedStoreStubCompiler::registers() {
2721 // receiver, name, value, scratch1, scratch2, scratch3. 1940 // receiver, name, value, scratch1, scratch2, scratch3.
2722 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 }; 1941 static Register registers[] = { rdx, rcx, rax, rbx, rdi, r8 };
2723 return registers; 1942 return registers;
2724 } 1943 }
2725 1944
2726 1945
2727 void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
2728 Register name_reg,
2729 Label* miss) {
2730 __ Cmp(name_reg, name);
2731 __ j(not_equal, miss);
2732 }
2733
2734
2735 void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2736 Register name_reg,
2737 Label* miss) {
2738 __ Cmp(name_reg, name);
2739 __ j(not_equal, miss);
2740 }
2741
2742
2743 #undef __ 1946 #undef __
2744 #define __ ACCESS_MASM(masm) 1947 #define __ ACCESS_MASM(masm)
2745 1948
2746 1949
2747 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, 1950 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2748 Register receiver, 1951 Register receiver,
2749 Handle<JSFunction> getter) { 1952 Handle<JSFunction> getter) {
2750 // ----------- S t a t e ------------- 1953 // ----------- S t a t e -------------
2751 // -- rax : receiver 1954 // -- rax : receiver
2752 // -- rcx : name 1955 // -- rcx : name
2753 // -- rsp[0] : return address 1956 // -- rsp[0] : return address
2754 // ----------------------------------- 1957 // -----------------------------------
2755 { 1958 {
2756 FrameScope scope(masm, StackFrame::INTERNAL); 1959 FrameScope scope(masm, StackFrame::INTERNAL);
2757 1960
2758 if (!getter.is_null()) { 1961 if (!getter.is_null()) {
2759 // Call the JavaScript getter with the receiver on the stack. 1962 // Call the JavaScript getter with the receiver on the stack.
2760 __ push(receiver); 1963 __ push(receiver);
2761 ParameterCount actual(0); 1964 ParameterCount actual(0);
2762 ParameterCount expected(getter); 1965 ParameterCount expected(getter);
2763 __ InvokeFunction(getter, expected, actual, 1966 __ InvokeFunction(getter, expected, actual,
2764 CALL_FUNCTION, NullCallWrapper()); 1967 CALL_FUNCTION, NullCallWrapper());
2765 } else { 1968 } else {
2766 // If we generate a global code snippet for deoptimization only, remember 1969 // If we generate a global code snippet for deoptimization only, remember
2767 // the place to continue after deoptimization. 1970 // the place to continue after deoptimization.
2768 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); 1971 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2769 } 1972 }
2770 1973
2771 // Restore context register. 1974 // Restore context register.
2772 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1975 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2773 } 1976 }
2774 __ ret(0); 1977 __ ret(0);
2775 } 1978 }
2776 1979
2777 1980
2778 #undef __ 1981 #undef __
2779 #define __ ACCESS_MASM(masm()) 1982 #define __ ACCESS_MASM(masm())
2780 1983
2781 1984
2782 Handle<Code> LoadStubCompiler::CompileLoadGlobal( 1985 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2783 Handle<Type> type, 1986 Handle<HeapType> type,
2784 Handle<GlobalObject> global, 1987 Handle<GlobalObject> global,
2785 Handle<PropertyCell> cell, 1988 Handle<PropertyCell> cell,
2786 Handle<Name> name, 1989 Handle<Name> name,
2787 bool is_dont_delete) { 1990 bool is_dont_delete) {
2788 Label miss; 1991 Label miss;
2789 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since 1992 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since
2790 // rax is used as receiver(), which we would otherwise clobber before a 1993 // rax is used as receiver(), which we would otherwise clobber before a
2791 // potential miss. 1994 // potential miss.
2792 HandlerFrontendHeader(type, receiver(), global, name, &miss); 1995 HandlerFrontendHeader(type, receiver(), global, name, &miss);
2793 1996
2794 // Get the value from the cell. 1997 // Get the value from the cell.
2795 __ Move(rbx, cell); 1998 __ Move(rbx, cell);
2796 __ movq(rbx, FieldOperand(rbx, PropertyCell::kValueOffset)); 1999 __ movp(rbx, FieldOperand(rbx, PropertyCell::kValueOffset));
2797 2000
2798 // Check for deleted property if property can actually be deleted. 2001 // Check for deleted property if property can actually be deleted.
2799 if (!is_dont_delete) { 2002 if (!is_dont_delete) {
2800 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 2003 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2801 __ j(equal, &miss); 2004 __ j(equal, &miss);
2802 } else if (FLAG_debug_code) { 2005 } else if (FLAG_debug_code) {
2803 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 2006 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2804 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); 2007 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
2805 } 2008 }
2806 2009
2807 HandlerFrontendFooter(name, &miss); 2010 HandlerFrontendFooter(name, &miss);
2808 2011
2809 Counters* counters = isolate()->counters(); 2012 Counters* counters = isolate()->counters();
2810 __ IncrementCounter(counters->named_load_global_stub(), 1); 2013 __ IncrementCounter(counters->named_load_global_stub(), 1);
2811 __ movq(rax, rbx); 2014 __ movp(rax, rbx);
2812 __ ret(0); 2015 __ ret(0);
2813 2016
2814 // Return the generated code. 2017 // Return the generated code.
2815 return GetCode(kind(), Code::NORMAL, name); 2018 return GetCode(kind(), Code::NORMAL, name);
2816 } 2019 }
2817 2020
2818 2021
2819 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( 2022 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
2820 TypeHandleList* types, 2023 TypeHandleList* types,
2821 CodeHandleList* handlers, 2024 CodeHandleList* handlers,
2822 Handle<Name> name, 2025 Handle<Name> name,
2823 Code::StubType type, 2026 Code::StubType type,
2824 IcCheckType check) { 2027 IcCheckType check) {
2825 Label miss; 2028 Label miss;
2826 2029
2827 if (check == PROPERTY) { 2030 if (check == PROPERTY &&
2828 GenerateNameCheck(name, this->name(), &miss); 2031 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
2032 __ Cmp(this->name(), name);
2033 __ j(not_equal, &miss);
2829 } 2034 }
2830 2035
2831 Label number_case; 2036 Label number_case;
2832 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; 2037 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
2833 __ JumpIfSmi(receiver(), smi_target); 2038 __ JumpIfSmi(receiver(), smi_target);
2834 2039
2835 Register map_reg = scratch1(); 2040 Register map_reg = scratch1();
2836 __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); 2041 __ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
2837 int receiver_count = types->length(); 2042 int receiver_count = types->length();
2838 int number_of_handled_maps = 0; 2043 int number_of_handled_maps = 0;
2839 for (int current = 0; current < receiver_count; ++current) { 2044 for (int current = 0; current < receiver_count; ++current) {
2840 Handle<Type> type = types->at(current); 2045 Handle<HeapType> type = types->at(current);
2841 Handle<Map> map = IC::TypeToMap(*type, isolate()); 2046 Handle<Map> map = IC::TypeToMap(*type, isolate());
2842 if (!map->is_deprecated()) { 2047 if (!map->is_deprecated()) {
2843 number_of_handled_maps++; 2048 number_of_handled_maps++;
2844 // Check map and tail call if there's a match 2049 // Check map and tail call if there's a match
2845 __ Cmp(map_reg, map); 2050 __ Cmp(map_reg, map);
2846 if (type->Is(Type::Number())) { 2051 if (type->Is(HeapType::Number())) {
2847 ASSERT(!number_case.is_unused()); 2052 ASSERT(!number_case.is_unused());
2848 __ bind(&number_case); 2053 __ bind(&number_case);
2849 } 2054 }
2850 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET); 2055 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
2851 } 2056 }
2852 } 2057 }
2853 ASSERT(number_of_handled_maps > 0); 2058 ASSERT(number_of_handled_maps > 0);
2854 2059
2855 __ bind(&miss); 2060 __ bind(&miss);
2856 TailCallBuiltin(masm(), MissBuiltin(kind())); 2061 TailCallBuiltin(masm(), MissBuiltin(kind()));
(...skipping 16 matching lines...) Expand all
2873 // -- rdx : receiver 2078 // -- rdx : receiver
2874 // -- rsp[0] : return address 2079 // -- rsp[0] : return address
2875 // ----------------------------------- 2080 // -----------------------------------
2876 Label slow, miss; 2081 Label slow, miss;
2877 2082
2878 // This stub is meant to be tail-jumped to, the receiver must already 2083 // This stub is meant to be tail-jumped to, the receiver must already
2879 // have been verified by the caller to not be a smi. 2084 // have been verified by the caller to not be a smi.
2880 2085
2881 __ JumpIfNotSmi(rax, &miss); 2086 __ JumpIfNotSmi(rax, &miss);
2882 __ SmiToInteger32(rbx, rax); 2087 __ SmiToInteger32(rbx, rax);
2883 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); 2088 __ movp(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
2884 2089
2885 // Check whether the elements is a number dictionary. 2090 // Check whether the elements is a number dictionary.
2886 // rdx: receiver 2091 // rdx: receiver
2887 // rax: key 2092 // rax: key
2888 // rbx: key as untagged int32 2093 // rbx: key as untagged int32
2889 // rcx: elements 2094 // rcx: elements
2890 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax); 2095 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
2891 __ ret(0); 2096 __ ret(0);
2892 2097
2893 __ bind(&slow); 2098 __ bind(&slow);
(...skipping 12 matching lines...) Expand all
2906 // ----------------------------------- 2111 // -----------------------------------
2907 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); 2112 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
2908 } 2113 }
2909 2114
2910 2115
2911 #undef __ 2116 #undef __
2912 2117
2913 } } // namespace v8::internal 2118 } } // namespace v8::internal
2914 2119
2915 #endif // V8_TARGET_ARCH_X64 2120 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/regexp-macro-assembler-x64.cc ('k') | test/cctest/cctest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698