| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 miss_label, | 146 miss_label, |
| 147 &done, | 147 &done, |
| 148 properties, | 148 properties, |
| 149 name, | 149 name, |
| 150 r1); | 150 r1); |
| 151 __ bind(&done); | 151 __ bind(&done); |
| 152 __ DecrementCounter(counters->negative_lookups_miss(), 1); | 152 __ DecrementCounter(counters->negative_lookups_miss(), 1); |
| 153 } | 153 } |
| 154 | 154 |
| 155 | 155 |
| 156 // TODO(kmillikin): Eliminate this function when the stub cache is fully | |
| 157 // handlified. | |
| 158 static MaybeObject* TryGenerateDictionaryNegativeLookup(MacroAssembler* masm, | |
| 159 Label* miss_label, | |
| 160 Register receiver, | |
| 161 String* name, | |
| 162 Register r0, | |
| 163 Register r1) { | |
| 164 ASSERT(name->IsSymbol()); | |
| 165 Counters* counters = masm->isolate()->counters(); | |
| 166 __ IncrementCounter(counters->negative_lookups(), 1); | |
| 167 __ IncrementCounter(counters->negative_lookups_miss(), 1); | |
| 168 | |
| 169 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); | |
| 170 | |
| 171 const int kInterceptorOrAccessCheckNeededMask = | |
| 172 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | |
| 173 | |
| 174 // Bail out if the receiver has a named interceptor or requires access checks. | |
| 175 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), | |
| 176 kInterceptorOrAccessCheckNeededMask); | |
| 177 __ j(not_zero, miss_label); | |
| 178 | |
| 179 // Check that receiver is a JSObject. | |
| 180 __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE); | |
| 181 __ j(below, miss_label); | |
| 182 | |
| 183 // Load properties array. | |
| 184 Register properties = r0; | |
| 185 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
| 186 | |
| 187 // Check that the properties array is a dictionary. | |
| 188 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), | |
| 189 Immediate(masm->isolate()->factory()->hash_table_map())); | |
| 190 __ j(not_equal, miss_label); | |
| 191 | |
| 192 Label done; | |
| 193 MaybeObject* result = | |
| 194 StringDictionaryLookupStub::TryGenerateNegativeLookup(masm, | |
| 195 miss_label, | |
| 196 &done, | |
| 197 properties, | |
| 198 name, | |
| 199 r1); | |
| 200 if (result->IsFailure()) return result; | |
| 201 | |
| 202 __ bind(&done); | |
| 203 __ DecrementCounter(counters->negative_lookups_miss(), 1); | |
| 204 | |
| 205 return result; | |
| 206 } | |
| 207 | |
| 208 | |
| 209 void StubCache::GenerateProbe(MacroAssembler* masm, | 156 void StubCache::GenerateProbe(MacroAssembler* masm, |
| 210 Code::Flags flags, | 157 Code::Flags flags, |
| 211 Register receiver, | 158 Register receiver, |
| 212 Register name, | 159 Register name, |
| 213 Register scratch, | 160 Register scratch, |
| 214 Register extra, | 161 Register extra, |
| 215 Register extra2) { | 162 Register extra2) { |
| 216 Label miss; | 163 Label miss; |
| 217 | 164 |
| 218 // Assert that code is valid. The shifting code relies on the entry size | 165 // Assert that code is valid. The shifting code relies on the entry size |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 int index, | 214 int index, |
| 268 Register prototype) { | 215 Register prototype) { |
| 269 __ LoadGlobalFunction(index, prototype); | 216 __ LoadGlobalFunction(index, prototype); |
| 270 __ LoadGlobalFunctionInitialMap(prototype, prototype); | 217 __ LoadGlobalFunctionInitialMap(prototype, prototype); |
| 271 // Load the prototype from the initial map. | 218 // Load the prototype from the initial map. |
| 272 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 219 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 273 } | 220 } |
| 274 | 221 |
| 275 | 222 |
| 276 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 223 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 277 MacroAssembler* masm, int index, Register prototype, Label* miss) { | 224 MacroAssembler* masm, |
| 225 int index, |
| 226 Register prototype, |
| 227 Label* miss) { |
| 278 // Check we're still in the same context. | 228 // Check we're still in the same context. |
| 279 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), | 229 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), |
| 280 masm->isolate()->global()); | 230 masm->isolate()->global()); |
| 281 __ j(not_equal, miss); | 231 __ j(not_equal, miss); |
| 282 // Get the global function with the given index. | 232 // Get the global function with the given index. |
| 283 JSFunction* function = | 233 Handle<JSFunction> function( |
| 284 JSFunction::cast(masm->isolate()->global_context()->get(index)); | 234 JSFunction::cast(masm->isolate()->global_context()->get(index))); |
| 285 // Load its initial map. The global functions all have initial maps. | 235 // Load its initial map. The global functions all have initial maps. |
| 286 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); | 236 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); |
| 287 // Load the prototype from the initial map. | 237 // Load the prototype from the initial map. |
| 288 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 238 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 289 } | 239 } |
| 290 | 240 |
| 291 | 241 |
| 292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, | 242 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, |
| 293 Register receiver, | 243 Register receiver, |
| 294 Register scratch, | 244 Register scratch, |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset)); | 339 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset)); |
| 390 __ mov(dst, FieldOperand(dst, offset)); | 340 __ mov(dst, FieldOperand(dst, offset)); |
| 391 } | 341 } |
| 392 } | 342 } |
| 393 | 343 |
| 394 | 344 |
| 395 static void PushInterceptorArguments(MacroAssembler* masm, | 345 static void PushInterceptorArguments(MacroAssembler* masm, |
| 396 Register receiver, | 346 Register receiver, |
| 397 Register holder, | 347 Register holder, |
| 398 Register name, | 348 Register name, |
| 399 JSObject* holder_obj) { | 349 Handle<JSObject> holder_obj) { |
| 400 __ push(name); | 350 __ push(name); |
| 401 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); | 351 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |
| 402 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor)); | 352 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); |
| 403 Register scratch = name; | 353 Register scratch = name; |
| 404 __ mov(scratch, Immediate(Handle<Object>(interceptor))); | 354 __ mov(scratch, Immediate(interceptor)); |
| 405 __ push(scratch); | 355 __ push(scratch); |
| 406 __ push(receiver); | 356 __ push(receiver); |
| 407 __ push(holder); | 357 __ push(holder); |
| 408 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset)); | 358 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset)); |
| 409 } | 359 } |
| 410 | 360 |
| 411 | 361 |
| 412 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, | 362 static void CompileCallLoadPropertyWithInterceptor( |
| 413 Register receiver, | 363 MacroAssembler* masm, |
| 414 Register holder, | 364 Register receiver, |
| 415 Register name, | 365 Register holder, |
| 416 JSObject* holder_obj) { | 366 Register name, |
| 367 Handle<JSObject> holder_obj) { |
| 417 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 368 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 418 __ CallExternalReference( | 369 __ CallExternalReference( |
| 419 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), | 370 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), |
| 420 masm->isolate()), | 371 masm->isolate()), |
| 421 5); | 372 5); |
| 422 } | 373 } |
| 423 | 374 |
| 424 | 375 |
| 425 // Number of pointers to be reserved on stack for fast API call. | 376 // Number of pointers to be reserved on stack for fast API call. |
| 426 static const int kFastApiCallArguments = 3; | 377 static const int kFastApiCallArguments = 3; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 453 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal | 404 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal |
| 454 // frame. | 405 // frame. |
| 455 // ----------------------------------- | 406 // ----------------------------------- |
| 456 __ pop(scratch); | 407 __ pop(scratch); |
| 457 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); | 408 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); |
| 458 __ push(scratch); | 409 __ push(scratch); |
| 459 } | 410 } |
| 460 | 411 |
| 461 | 412 |
| 462 // Generates call to API function. | 413 // Generates call to API function. |
| 463 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, | 414 static void GenerateFastApiCall(MacroAssembler* masm, |
| 464 const CallOptimization& optimization, | 415 const CallOptimization& optimization, |
| 465 int argc) { | 416 int argc) { |
| 466 // ----------- S t a t e ------------- | 417 // ----------- S t a t e ------------- |
| 467 // -- esp[0] : return address | 418 // -- esp[0] : return address |
| 468 // -- esp[4] : object passing the type check | 419 // -- esp[4] : object passing the type check |
| 469 // (last fast api call extra argument, | 420 // (last fast api call extra argument, |
| 470 // set by CheckPrototypes) | 421 // set by CheckPrototypes) |
| 471 // -- esp[8] : api function | 422 // -- esp[8] : api function |
| 472 // (first fast api call extra argument) | 423 // (first fast api call extra argument) |
| 473 // -- esp[12] : api call data | 424 // -- esp[12] : api call data |
| 474 // -- esp[16] : last argument | 425 // -- esp[16] : last argument |
| 475 // -- ... | 426 // -- ... |
| 476 // -- esp[(argc + 3) * 4] : first argument | 427 // -- esp[(argc + 3) * 4] : first argument |
| 477 // -- esp[(argc + 4) * 4] : receiver | 428 // -- esp[(argc + 4) * 4] : receiver |
| 478 // ----------------------------------- | 429 // ----------------------------------- |
| 479 // Get the function and setup the context. | 430 // Get the function and setup the context. |
| 480 JSFunction* function = optimization.constant_function(); | 431 Handle<JSFunction> function = optimization.constant_function(); |
| 481 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 432 __ mov(edi, Immediate(function)); |
| 482 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 433 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 483 | 434 |
| 484 // Pass the additional arguments. | 435 // Pass the additional arguments. |
| 485 __ mov(Operand(esp, 2 * kPointerSize), edi); | 436 __ mov(Operand(esp, 2 * kPointerSize), edi); |
| 486 Object* call_data = optimization.api_call_info()->data(); | 437 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 487 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); | 438 Handle<Object> call_data(api_call_info->data()); |
| 488 if (masm->isolate()->heap()->InNewSpace(call_data)) { | 439 if (masm->isolate()->heap()->InNewSpace(*call_data)) { |
| 489 __ mov(ecx, api_call_info_handle); | 440 __ mov(ecx, api_call_info); |
| 490 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); | 441 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); |
| 491 __ mov(Operand(esp, 3 * kPointerSize), ebx); | 442 __ mov(Operand(esp, 3 * kPointerSize), ebx); |
| 492 } else { | 443 } else { |
| 493 __ mov(Operand(esp, 3 * kPointerSize), | 444 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data)); |
| 494 Immediate(Handle<Object>(call_data))); | |
| 495 } | 445 } |
| 496 | 446 |
| 497 // Prepare arguments. | 447 // Prepare arguments. |
| 498 __ lea(eax, Operand(esp, 3 * kPointerSize)); | 448 __ lea(eax, Operand(esp, 3 * kPointerSize)); |
| 499 | 449 |
| 500 Object* callback = optimization.api_call_info()->callback(); | |
| 501 Address api_function_address = v8::ToCData<Address>(callback); | |
| 502 ApiFunction fun(api_function_address); | |
| 503 | |
| 504 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. | 450 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. |
| 505 | 451 |
| 506 // Allocate the v8::Arguments structure in the arguments' space since | 452 // Allocate the v8::Arguments structure in the arguments' space since |
| 507 // it's not controlled by GC. | 453 // it's not controlled by GC. |
| 508 const int kApiStackSpace = 4; | 454 const int kApiStackSpace = 4; |
| 509 | 455 |
| 510 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); | 456 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
| 511 | 457 |
| 512 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. | 458 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. |
| 513 __ add(eax, Immediate(argc * kPointerSize)); | 459 __ add(eax, Immediate(argc * kPointerSize)); |
| 514 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. | 460 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. |
| 515 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. | 461 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. |
| 516 // v8::Arguments::is_construct_call_. | 462 // v8::Arguments::is_construct_call_. |
| 517 __ Set(ApiParameterOperand(4), Immediate(0)); | 463 __ Set(ApiParameterOperand(4), Immediate(0)); |
| 518 | 464 |
| 519 // v8::InvocationCallback's argument. | 465 // v8::InvocationCallback's argument. |
| 520 __ lea(eax, ApiParameterOperand(1)); | 466 __ lea(eax, ApiParameterOperand(1)); |
| 521 __ mov(ApiParameterOperand(0), eax); | 467 __ mov(ApiParameterOperand(0), eax); |
| 522 | 468 |
| 523 // Emitting a stub call may try to allocate (if the code is not | 469 // Function address is a foreign pointer outside V8's heap. |
| 524 // already generated). Do not allow the assembler to perform a | 470 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 525 // garbage collection but instead return the allocation failure | 471 __ CallApiFunctionAndReturn(function_address, |
| 526 // object. | 472 argc + kFastApiCallArguments + 1); |
| 527 return masm->TryCallApiFunctionAndReturn(&fun, | |
| 528 argc + kFastApiCallArguments + 1); | |
| 529 } | 473 } |
| 530 | 474 |
| 531 | 475 |
| 532 class CallInterceptorCompiler BASE_EMBEDDED { | 476 class CallInterceptorCompiler BASE_EMBEDDED { |
| 533 public: | 477 public: |
| 534 CallInterceptorCompiler(StubCompiler* stub_compiler, | 478 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 535 const ParameterCount& arguments, | 479 const ParameterCount& arguments, |
| 536 Register name, | 480 Register name, |
| 537 Code::ExtraICState extra_state) | 481 Code::ExtraICState extra_state) |
| 538 : stub_compiler_(stub_compiler), | 482 : stub_compiler_(stub_compiler), |
| 539 arguments_(arguments), | 483 arguments_(arguments), |
| 540 name_(name), | 484 name_(name), |
| 541 extra_state_(extra_state) {} | 485 extra_state_(extra_state) {} |
| 542 | 486 |
| 543 MaybeObject* Compile(MacroAssembler* masm, | 487 void Compile(MacroAssembler* masm, |
| 544 JSObject* object, | 488 Handle<JSObject> object, |
| 545 JSObject* holder, | 489 Handle<JSObject> holder, |
| 546 String* name, | 490 Handle<String> name, |
| 547 LookupResult* lookup, | 491 LookupResult* lookup, |
| 548 Register receiver, | 492 Register receiver, |
| 549 Register scratch1, | 493 Register scratch1, |
| 550 Register scratch2, | 494 Register scratch2, |
| 551 Register scratch3, | 495 Register scratch3, |
| 552 Label* miss) { | 496 Label* miss) { |
| 553 ASSERT(holder->HasNamedInterceptor()); | 497 ASSERT(holder->HasNamedInterceptor()); |
| 554 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 498 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 555 | 499 |
| 556 // Check that the receiver isn't a smi. | 500 // Check that the receiver isn't a smi. |
| 557 __ JumpIfSmi(receiver, miss); | 501 __ JumpIfSmi(receiver, miss); |
| 558 | 502 |
| 559 CallOptimization optimization(lookup); | 503 CallOptimization optimization(lookup); |
| 560 | |
| 561 if (optimization.is_constant_call()) { | 504 if (optimization.is_constant_call()) { |
| 562 return CompileCacheable(masm, | 505 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, |
| 563 object, | 506 holder, lookup, name, optimization, miss); |
| 564 receiver, | |
| 565 scratch1, | |
| 566 scratch2, | |
| 567 scratch3, | |
| 568 holder, | |
| 569 lookup, | |
| 570 name, | |
| 571 optimization, | |
| 572 miss); | |
| 573 } else { | 507 } else { |
| 574 CompileRegular(masm, | 508 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, |
| 575 object, | 509 name, holder, miss); |
| 576 receiver, | |
| 577 scratch1, | |
| 578 scratch2, | |
| 579 scratch3, | |
| 580 name, | |
| 581 holder, | |
| 582 miss); | |
| 583 return masm->isolate()->heap()->undefined_value(); // Success. | |
| 584 } | 510 } |
| 585 } | 511 } |
| 586 | 512 |
| 587 private: | 513 private: |
| 588 MaybeObject* CompileCacheable(MacroAssembler* masm, | 514 void CompileCacheable(MacroAssembler* masm, |
| 589 JSObject* object, | 515 Handle<JSObject> object, |
| 590 Register receiver, | 516 Register receiver, |
| 591 Register scratch1, | 517 Register scratch1, |
| 592 Register scratch2, | 518 Register scratch2, |
| 593 Register scratch3, | 519 Register scratch3, |
| 594 JSObject* interceptor_holder, | 520 Handle<JSObject> interceptor_holder, |
| 595 LookupResult* lookup, | 521 LookupResult* lookup, |
| 596 String* name, | 522 Handle<String> name, |
| 597 const CallOptimization& optimization, | 523 const CallOptimization& optimization, |
| 598 Label* miss_label) { | 524 Label* miss_label) { |
| 599 ASSERT(optimization.is_constant_call()); | 525 ASSERT(optimization.is_constant_call()); |
| 600 ASSERT(!lookup->holder()->IsGlobalObject()); | 526 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 601 | 527 |
| 602 int depth1 = kInvalidProtoDepth; | 528 int depth1 = kInvalidProtoDepth; |
| 603 int depth2 = kInvalidProtoDepth; | 529 int depth2 = kInvalidProtoDepth; |
| 604 bool can_do_fast_api_call = false; | 530 bool can_do_fast_api_call = false; |
| 605 if (optimization.is_simple_api_call() && | 531 if (optimization.is_simple_api_call() && |
| 606 !lookup->holder()->IsGlobalObject()) { | 532 !lookup->holder()->IsGlobalObject()) { |
| 607 depth1 = | 533 depth1 = optimization.GetPrototypeDepthOfExpectedType( |
| 608 optimization.GetPrototypeDepthOfExpectedType(object, | 534 object, interceptor_holder); |
| 609 interceptor_holder); | |
| 610 if (depth1 == kInvalidProtoDepth) { | 535 if (depth1 == kInvalidProtoDepth) { |
| 611 depth2 = | 536 depth2 = optimization.GetPrototypeDepthOfExpectedType( |
| 612 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, | 537 interceptor_holder, Handle<JSObject>(lookup->holder())); |
| 613 lookup->holder()); | |
| 614 } | 538 } |
| 615 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || | 539 can_do_fast_api_call = |
| 616 (depth2 != kInvalidProtoDepth); | 540 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; |
| 617 } | 541 } |
| 618 | 542 |
| 619 Counters* counters = masm->isolate()->counters(); | 543 Counters* counters = masm->isolate()->counters(); |
| 620 __ IncrementCounter(counters->call_const_interceptor(), 1); | 544 __ IncrementCounter(counters->call_const_interceptor(), 1); |
| 621 | 545 |
| 622 if (can_do_fast_api_call) { | 546 if (can_do_fast_api_call) { |
| 623 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); | 547 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); |
| 624 ReserveSpaceForFastApiCall(masm, scratch1); | 548 ReserveSpaceForFastApiCall(masm, scratch1); |
| 625 } | 549 } |
| 626 | 550 |
| 627 // Check that the maps from receiver to interceptor's holder | 551 // Check that the maps from receiver to interceptor's holder |
| 628 // haven't changed and thus we can invoke interceptor. | 552 // haven't changed and thus we can invoke interceptor. |
| 629 Label miss_cleanup; | 553 Label miss_cleanup; |
| 630 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 554 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
| 631 Register holder = | 555 Register holder = |
| 632 stub_compiler_->CheckPrototypes(object, receiver, | 556 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
| 633 interceptor_holder, scratch1, | 557 scratch1, scratch2, scratch3, |
| 634 scratch2, scratch3, name, depth1, miss); | 558 name, depth1, miss); |
| 635 | 559 |
| 636 // Invoke an interceptor and if it provides a value, | 560 // Invoke an interceptor and if it provides a value, |
| 637 // branch to |regular_invoke|. | 561 // branch to |regular_invoke|. |
| 638 Label regular_invoke; | 562 Label regular_invoke; |
| 639 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | 563 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
| 640 ®ular_invoke); | 564 ®ular_invoke); |
| 641 | 565 |
| 642 // Interceptor returned nothing for this property. Try to use cached | 566 // Interceptor returned nothing for this property. Try to use cached |
| 643 // constant function. | 567 // constant function. |
| 644 | 568 |
| 645 // Check that the maps from interceptor's holder to constant function's | 569 // Check that the maps from interceptor's holder to constant function's |
| 646 // holder haven't changed and thus we can use cached constant function. | 570 // holder haven't changed and thus we can use cached constant function. |
| 647 if (interceptor_holder != lookup->holder()) { | 571 if (*interceptor_holder != lookup->holder()) { |
| 648 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, | 572 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
| 649 lookup->holder(), scratch1, | 573 Handle<JSObject>(lookup->holder()), |
| 650 scratch2, scratch3, name, depth2, miss); | 574 scratch1, scratch2, scratch3, |
| 575 name, depth2, miss); |
| 651 } else { | 576 } else { |
| 652 // CheckPrototypes has a side effect of fetching a 'holder' | 577 // CheckPrototypes has a side effect of fetching a 'holder' |
| 653 // for API (object which is instanceof for the signature). It's | 578 // for API (object which is instanceof for the signature). It's |
| 654 // safe to omit it here, as if present, it should be fetched | 579 // safe to omit it here, as if present, it should be fetched |
| 655 // by the previous CheckPrototypes. | 580 // by the previous CheckPrototypes. |
| 656 ASSERT(depth2 == kInvalidProtoDepth); | 581 ASSERT(depth2 == kInvalidProtoDepth); |
| 657 } | 582 } |
| 658 | 583 |
| 659 // Invoke function. | 584 // Invoke function. |
| 660 if (can_do_fast_api_call) { | 585 if (can_do_fast_api_call) { |
| 661 MaybeObject* result = | 586 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
| 662 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | |
| 663 if (result->IsFailure()) return result; | |
| 664 } else { | 587 } else { |
| 665 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 588 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) |
| 666 ? CALL_AS_FUNCTION | 589 ? CALL_AS_FUNCTION |
| 667 : CALL_AS_METHOD; | 590 : CALL_AS_METHOD; |
| 668 __ InvokeFunction(optimization.constant_function(), arguments_, | 591 __ InvokeFunction(optimization.constant_function(), arguments_, |
| 669 JUMP_FUNCTION, NullCallWrapper(), call_kind); | 592 JUMP_FUNCTION, NullCallWrapper(), call_kind); |
| 670 } | 593 } |
| 671 | 594 |
| 672 // Deferred code for fast API call case---clean preallocated space. | 595 // Deferred code for fast API call case---clean preallocated space. |
| 673 if (can_do_fast_api_call) { | 596 if (can_do_fast_api_call) { |
| 674 __ bind(&miss_cleanup); | 597 __ bind(&miss_cleanup); |
| 675 FreeSpaceForFastApiCall(masm, scratch1); | 598 FreeSpaceForFastApiCall(masm, scratch1); |
| 676 __ jmp(miss_label); | 599 __ jmp(miss_label); |
| 677 } | 600 } |
| 678 | 601 |
| 679 // Invoke a regular function. | 602 // Invoke a regular function. |
| 680 __ bind(®ular_invoke); | 603 __ bind(®ular_invoke); |
| 681 if (can_do_fast_api_call) { | 604 if (can_do_fast_api_call) { |
| 682 FreeSpaceForFastApiCall(masm, scratch1); | 605 FreeSpaceForFastApiCall(masm, scratch1); |
| 683 } | 606 } |
| 684 | |
| 685 return masm->isolate()->heap()->undefined_value(); // Success. | |
| 686 } | 607 } |
| 687 | 608 |
| 688 void CompileRegular(MacroAssembler* masm, | 609 void CompileRegular(MacroAssembler* masm, |
| 689 JSObject* object, | 610 Handle<JSObject> object, |
| 690 Register receiver, | 611 Register receiver, |
| 691 Register scratch1, | 612 Register scratch1, |
| 692 Register scratch2, | 613 Register scratch2, |
| 693 Register scratch3, | 614 Register scratch3, |
| 694 String* name, | 615 Handle<String> name, |
| 695 JSObject* interceptor_holder, | 616 Handle<JSObject> interceptor_holder, |
| 696 Label* miss_label) { | 617 Label* miss_label) { |
| 697 Register holder = | 618 Register holder = |
| 698 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 619 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
| 699 scratch1, scratch2, scratch3, name, | 620 scratch1, scratch2, scratch3, |
| 700 miss_label); | 621 name, miss_label); |
| 701 | 622 |
| 702 FrameScope scope(masm, StackFrame::INTERNAL); | 623 FrameScope scope(masm, StackFrame::INTERNAL); |
| 703 // Save the name_ register across the call. | 624 // Save the name_ register across the call. |
| 704 __ push(name_); | 625 __ push(name_); |
| 705 | 626 |
| 706 PushInterceptorArguments(masm, | 627 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
| 707 receiver, | |
| 708 holder, | |
| 709 name_, | |
| 710 interceptor_holder); | |
| 711 | 628 |
| 712 __ CallExternalReference( | 629 __ CallExternalReference( |
| 713 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), | 630 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), |
| 714 masm->isolate()), | 631 masm->isolate()), |
| 715 5); | 632 5); |
| 716 | 633 |
| 717 // Restore the name_ register. | 634 // Restore the name_ register. |
| 718 __ pop(name_); | 635 __ pop(name_); |
| 719 | 636 |
| 720 // Leave the internal frame. | 637 // Leave the internal frame. |
| 721 } | 638 } |
| 722 | 639 |
| 723 void LoadWithInterceptor(MacroAssembler* masm, | 640 void LoadWithInterceptor(MacroAssembler* masm, |
| 724 Register receiver, | 641 Register receiver, |
| 725 Register holder, | 642 Register holder, |
| 726 JSObject* holder_obj, | 643 Handle<JSObject> holder_obj, |
| 727 Label* interceptor_succeeded) { | 644 Label* interceptor_succeeded) { |
| 728 { | 645 { |
| 729 FrameScope scope(masm, StackFrame::INTERNAL); | 646 FrameScope scope(masm, StackFrame::INTERNAL); |
| 730 __ push(holder); // Save the holder. | 647 __ push(holder); // Save the holder. |
| 731 __ push(name_); // Save the name. | 648 __ push(name_); // Save the name. |
| 732 | 649 |
| 733 CompileCallLoadPropertyWithInterceptor(masm, | 650 CompileCallLoadPropertyWithInterceptor(masm, |
| 734 receiver, | 651 receiver, |
| 735 holder, | 652 holder, |
| 736 name_, | 653 name_, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 755 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 672 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
| 756 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 673 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
| 757 Handle<Code> code = (kind == Code::LOAD_IC) | 674 Handle<Code> code = (kind == Code::LOAD_IC) |
| 758 ? masm->isolate()->builtins()->LoadIC_Miss() | 675 ? masm->isolate()->builtins()->LoadIC_Miss() |
| 759 : masm->isolate()->builtins()->KeyedLoadIC_Miss(); | 676 : masm->isolate()->builtins()->KeyedLoadIC_Miss(); |
| 760 __ jmp(code, RelocInfo::CODE_TARGET); | 677 __ jmp(code, RelocInfo::CODE_TARGET); |
| 761 } | 678 } |
| 762 | 679 |
| 763 | 680 |
| 764 void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) { | 681 void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) { |
| 765 Code* code = masm->isolate()->builtins()->builtin( | 682 Handle<Code> code = |
| 766 Builtins::kKeyedLoadIC_MissForceGeneric); | 683 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 767 Handle<Code> ic(code); | 684 __ jmp(code, RelocInfo::CODE_TARGET); |
| 768 __ jmp(ic, RelocInfo::CODE_TARGET); | |
| 769 } | 685 } |
| 770 | 686 |
| 771 | 687 |
| 772 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 688 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
| 773 // but may be destroyed if store is successful. | 689 // but may be destroyed if store is successful. |
| 774 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 690 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 775 Handle<JSObject> object, | 691 Handle<JSObject> object, |
| 776 int index, | 692 int index, |
| 777 Handle<Map> transition, | 693 Handle<Map> transition, |
| 778 Register receiver_reg, | 694 Register receiver_reg, |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 __ mov(scratch, Immediate(cell)); | 792 __ mov(scratch, Immediate(cell)); |
| 877 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | 793 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
| 878 Immediate(the_hole)); | 794 Immediate(the_hole)); |
| 879 } else { | 795 } else { |
| 880 __ cmp(Operand::Cell(cell), Immediate(the_hole)); | 796 __ cmp(Operand::Cell(cell), Immediate(the_hole)); |
| 881 } | 797 } |
| 882 __ j(not_equal, miss); | 798 __ j(not_equal, miss); |
| 883 } | 799 } |
| 884 | 800 |
| 885 | 801 |
| 886 // TODO(kmillikin): Eliminate this function when the stub cache is fully | |
| 887 // handlified. | |
| 888 MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCell( | |
| 889 MacroAssembler* masm, | |
| 890 GlobalObject* global, | |
| 891 String* name, | |
| 892 Register scratch, | |
| 893 Label* miss) { | |
| 894 Object* probe; | |
| 895 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); | |
| 896 if (!maybe_probe->ToObject(&probe)) return maybe_probe; | |
| 897 } | |
| 898 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | |
| 899 ASSERT(cell->value()->IsTheHole()); | |
| 900 if (Serializer::enabled()) { | |
| 901 __ mov(scratch, Immediate(Handle<Object>(cell))); | |
| 902 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | |
| 903 Immediate(masm->isolate()->factory()->the_hole_value())); | |
| 904 } else { | |
| 905 __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), | |
| 906 Immediate(masm->isolate()->factory()->the_hole_value())); | |
| 907 } | |
| 908 __ j(not_equal, miss); | |
| 909 return cell; | |
| 910 } | |
| 911 | |
| 912 | |
| 913 // Calls GenerateCheckPropertyCell for each global object in the prototype chain | 802 // Calls GenerateCheckPropertyCell for each global object in the prototype chain |
| 914 // from object to (but not including) holder. | 803 // from object to (but not including) holder. |
| 915 static void GenerateCheckPropertyCells(MacroAssembler* masm, | 804 static void GenerateCheckPropertyCells(MacroAssembler* masm, |
| 916 Handle<JSObject> object, | 805 Handle<JSObject> object, |
| 917 Handle<JSObject> holder, | 806 Handle<JSObject> holder, |
| 918 Handle<String> name, | 807 Handle<String> name, |
| 919 Register scratch, | 808 Register scratch, |
| 920 Label* miss) { | 809 Label* miss) { |
| 921 Handle<JSObject> current = object; | 810 Handle<JSObject> current = object; |
| 922 while (!current.is_identical_to(holder)) { | 811 while (!current.is_identical_to(holder)) { |
| 923 if (current->IsGlobalObject()) { | 812 if (current->IsGlobalObject()) { |
| 924 GenerateCheckPropertyCell(masm, | 813 GenerateCheckPropertyCell(masm, |
| 925 Handle<GlobalObject>::cast(current), | 814 Handle<GlobalObject>::cast(current), |
| 926 name, | 815 name, |
| 927 scratch, | 816 scratch, |
| 928 miss); | 817 miss); |
| 929 } | 818 } |
| 930 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); | 819 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); |
| 931 } | 820 } |
| 932 } | 821 } |
| 933 | 822 |
| 934 | |
| 935 // TODO(kmillikin): Eliminate this function when the stub cache is fully | |
| 936 // handlified. | |
| 937 MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCells( | |
| 938 MacroAssembler* masm, | |
| 939 JSObject* object, | |
| 940 JSObject* holder, | |
| 941 String* name, | |
| 942 Register scratch, | |
| 943 Label* miss) { | |
| 944 JSObject* current = object; | |
| 945 while (current != holder) { | |
| 946 if (current->IsGlobalObject()) { | |
| 947 // Returns a cell or a failure. | |
| 948 MaybeObject* result = TryGenerateCheckPropertyCell( | |
| 949 masm, | |
| 950 GlobalObject::cast(current), | |
| 951 name, | |
| 952 scratch, | |
| 953 miss); | |
| 954 if (result->IsFailure()) return result; | |
| 955 } | |
| 956 ASSERT(current->IsJSObject()); | |
| 957 current = JSObject::cast(current->GetPrototype()); | |
| 958 } | |
| 959 return NULL; | |
| 960 } | |
| 961 | |
| 962 | |
| 963 #undef __ | 823 #undef __ |
| 964 #define __ ACCESS_MASM(masm()) | 824 #define __ ACCESS_MASM(masm()) |
| 965 | 825 |
| 966 | 826 |
| 967 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, | 827 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, |
| 968 Register object_reg, | 828 Register object_reg, |
| 969 Handle<JSObject> holder, | 829 Handle<JSObject> holder, |
| 970 Register holder_reg, | 830 Register holder_reg, |
| 971 Register scratch1, | 831 Register scratch1, |
| 972 Register scratch2, | 832 Register scratch2, |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 // If we've skipped any global objects, it's not enough to verify that | 929 // If we've skipped any global objects, it's not enough to verify that |
| 1070 // their maps haven't changed. We also need to check that the property | 930 // their maps haven't changed. We also need to check that the property |
| 1071 // cell for the property is still empty. | 931 // cell for the property is still empty. |
| 1072 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | 932 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); |
| 1073 | 933 |
| 1074 // Return the register containing the holder. | 934 // Return the register containing the holder. |
| 1075 return reg; | 935 return reg; |
| 1076 } | 936 } |
| 1077 | 937 |
| 1078 | 938 |
| 1079 // TODO(kmillikin): Eliminate this function when the stub cache is fully | |
| 1080 // handlified. | |
| 1081 Register StubCompiler::CheckPrototypes(JSObject* object, | |
| 1082 Register object_reg, | |
| 1083 JSObject* holder, | |
| 1084 Register holder_reg, | |
| 1085 Register scratch1, | |
| 1086 Register scratch2, | |
| 1087 String* name, | |
| 1088 int save_at_depth, | |
| 1089 Label* miss) { | |
| 1090 // Make sure there's no overlap between holder and object registers. | |
| 1091 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | |
| 1092 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | |
| 1093 && !scratch2.is(scratch1)); | |
| 1094 | |
| 1095 // Keep track of the current object in register reg. | |
| 1096 Register reg = object_reg; | |
| 1097 JSObject* current = object; | |
| 1098 int depth = 0; | |
| 1099 | |
| 1100 if (save_at_depth == depth) { | |
| 1101 __ mov(Operand(esp, kPointerSize), reg); | |
| 1102 } | |
| 1103 | |
| 1104 // Traverse the prototype chain and check the maps in the prototype chain for | |
| 1105 // fast and global objects or do negative lookup for normal objects. | |
| 1106 while (current != holder) { | |
| 1107 depth++; | |
| 1108 | |
| 1109 // Only global objects and objects that do not require access | |
| 1110 // checks are allowed in stubs. | |
| 1111 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); | |
| 1112 | |
| 1113 ASSERT(current->GetPrototype()->IsJSObject()); | |
| 1114 JSObject* prototype = JSObject::cast(current->GetPrototype()); | |
| 1115 if (!current->HasFastProperties() && | |
| 1116 !current->IsJSGlobalObject() && | |
| 1117 !current->IsJSGlobalProxy()) { | |
| 1118 if (!name->IsSymbol()) { | |
| 1119 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name); | |
| 1120 Object* lookup_result = NULL; // Initialization to please compiler. | |
| 1121 if (!maybe_lookup_result->ToObject(&lookup_result)) { | |
| 1122 set_failure(Failure::cast(maybe_lookup_result)); | |
| 1123 return reg; | |
| 1124 } | |
| 1125 name = String::cast(lookup_result); | |
| 1126 } | |
| 1127 ASSERT(current->property_dictionary()->FindEntry(name) == | |
| 1128 StringDictionary::kNotFound); | |
| 1129 | |
| 1130 MaybeObject* negative_lookup = | |
| 1131 TryGenerateDictionaryNegativeLookup(masm(), miss, reg, name, | |
| 1132 scratch1, scratch2); | |
| 1133 if (negative_lookup->IsFailure()) { | |
| 1134 set_failure(Failure::cast(negative_lookup)); | |
| 1135 return reg; | |
| 1136 } | |
| 1137 | |
| 1138 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | |
| 1139 reg = holder_reg; // from now the object is in holder_reg | |
| 1140 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | |
| 1141 } else if (heap()->InNewSpace(prototype)) { | |
| 1142 // Get the map of the current object. | |
| 1143 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | |
| 1144 __ cmp(scratch1, Immediate(Handle<Map>(current->map()))); | |
| 1145 // Branch on the result of the map check. | |
| 1146 __ j(not_equal, miss); | |
| 1147 // Check access rights to the global object. This has to happen | |
| 1148 // after the map check so that we know that the object is | |
| 1149 // actually a global object. | |
| 1150 if (current->IsJSGlobalProxy()) { | |
| 1151 __ CheckAccessGlobalProxy(reg, scratch1, miss); | |
| 1152 | |
| 1153 // Restore scratch register to be the map of the object. | |
| 1154 // We load the prototype from the map in the scratch register. | |
| 1155 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | |
| 1156 } | |
| 1157 // The prototype is in new space; we cannot store a reference | |
| 1158 // to it in the code. Load it from the map. | |
| 1159 reg = holder_reg; // from now the object is in holder_reg | |
| 1160 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | |
| 1161 } else { | |
| 1162 // Check the map of the current object. | |
| 1163 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | |
| 1164 Immediate(Handle<Map>(current->map()))); | |
| 1165 // Branch on the result of the map check. | |
| 1166 __ j(not_equal, miss); | |
| 1167 // Check access rights to the global object. This has to happen | |
| 1168 // after the map check so that we know that the object is | |
| 1169 // actually a global object. | |
| 1170 if (current->IsJSGlobalProxy()) { | |
| 1171 __ CheckAccessGlobalProxy(reg, scratch1, miss); | |
| 1172 } | |
| 1173 // The prototype is in old space; load it directly. | |
| 1174 reg = holder_reg; // from now the object is in holder_reg | |
| 1175 __ mov(reg, Handle<JSObject>(prototype)); | |
| 1176 } | |
| 1177 | |
| 1178 if (save_at_depth == depth) { | |
| 1179 __ mov(Operand(esp, kPointerSize), reg); | |
| 1180 } | |
| 1181 | |
| 1182 // Go to the next object in the prototype chain. | |
| 1183 current = prototype; | |
| 1184 } | |
| 1185 ASSERT(current == holder); | |
| 1186 | |
| 1187 // Log the check depth. | |
| 1188 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | |
| 1189 | |
| 1190 // Check the holder map. | |
| 1191 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | |
| 1192 Immediate(Handle<Map>(holder->map()))); | |
| 1193 __ j(not_equal, miss); | |
| 1194 | |
| 1195 // Perform security check for access to the global object. | |
| 1196 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | |
| 1197 if (holder->IsJSGlobalProxy()) { | |
| 1198 __ CheckAccessGlobalProxy(reg, scratch1, miss); | |
| 1199 } | |
| 1200 | |
| 1201 // If we've skipped any global objects, it's not enough to verify | |
| 1202 // that their maps haven't changed. We also need to check that the | |
| 1203 // property cell for the property is still empty. | |
| 1204 MaybeObject* result = TryGenerateCheckPropertyCells(masm(), | |
| 1205 object, | |
| 1206 holder, | |
| 1207 name, | |
| 1208 scratch1, | |
| 1209 miss); | |
| 1210 if (result->IsFailure()) set_failure(Failure::cast(result)); | |
| 1211 | |
| 1212 // Return the register containing the holder. | |
| 1213 return reg; | |
| 1214 } | |
| 1215 | |
| 1216 | |
| 1217 void StubCompiler::GenerateLoadField(Handle<JSObject> object, | 939 void StubCompiler::GenerateLoadField(Handle<JSObject> object, |
| 1218 Handle<JSObject> holder, | 940 Handle<JSObject> holder, |
| 1219 Register receiver, | 941 Register receiver, |
| 1220 Register scratch1, | 942 Register scratch1, |
| 1221 Register scratch2, | 943 Register scratch2, |
| 1222 Register scratch3, | 944 Register scratch3, |
| 1223 int index, | 945 int index, |
| 1224 Handle<String> name, | 946 Handle<String> name, |
| 1225 Label* miss) { | 947 Label* miss) { |
| 1226 // Check that the receiver isn't a smi. | 948 // Check that the receiver isn't a smi. |
| 1227 __ JumpIfSmi(receiver, miss); | 949 __ JumpIfSmi(receiver, miss); |
| 1228 | 950 |
| 1229 // Check the prototype chain. | 951 // Check the prototype chain. |
| 1230 Register reg = CheckPrototypes( | 952 Register reg = CheckPrototypes( |
| 1231 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | 953 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); |
| 1232 | 954 |
| 1233 // Get the value from the properties. | 955 // Get the value from the properties. |
| 1234 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); | 956 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
| 1235 __ ret(0); | 957 __ ret(0); |
| 1236 } | 958 } |
| 1237 | 959 |
| 1238 | 960 |
| 1239 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, | 961 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, |
| 1240 JSObject* holder, | 962 Handle<JSObject> holder, |
| 1241 Register receiver, | 963 Register receiver, |
| 1242 Register name_reg, | 964 Register name_reg, |
| 1243 Register scratch1, | 965 Register scratch1, |
| 1244 Register scratch2, | 966 Register scratch2, |
| 1245 Register scratch3, | 967 Register scratch3, |
| 1246 AccessorInfo* callback, | 968 Handle<AccessorInfo> callback, |
| 1247 String* name, | 969 Handle<String> name, |
| 1248 Label* miss) { | 970 Label* miss) { |
| 1249 // Check that the receiver isn't a smi. | 971 // Check that the receiver isn't a smi. |
| 1250 __ JumpIfSmi(receiver, miss); | 972 __ JumpIfSmi(receiver, miss); |
| 1251 | 973 |
| 1252 // Check that the maps haven't changed. | 974 // Check that the maps haven't changed. |
| 1253 Register reg = | 975 Register reg = CheckPrototypes(object, receiver, holder, scratch1, |
| 1254 CheckPrototypes(object, receiver, holder, scratch1, | 976 scratch2, scratch3, name, miss); |
| 1255 scratch2, scratch3, name, miss); | |
| 1256 | |
| 1257 Handle<AccessorInfo> callback_handle(callback); | |
| 1258 | 977 |
| 1259 // Insert additional parameters into the stack frame above return address. | 978 // Insert additional parameters into the stack frame above return address. |
| 1260 ASSERT(!scratch3.is(reg)); | 979 ASSERT(!scratch3.is(reg)); |
| 1261 __ pop(scratch3); // Get return address to place it below. | 980 __ pop(scratch3); // Get return address to place it below. |
| 1262 | 981 |
| 1263 __ push(receiver); // receiver | 982 __ push(receiver); // receiver |
| 1264 __ mov(scratch2, esp); | 983 __ mov(scratch2, esp); |
| 1265 ASSERT(!scratch2.is(reg)); | 984 ASSERT(!scratch2.is(reg)); |
| 1266 __ push(reg); // holder | 985 __ push(reg); // holder |
| 1267 // Push data from AccessorInfo. | 986 // Push data from AccessorInfo. |
| 1268 if (isolate()->heap()->InNewSpace(callback_handle->data())) { | 987 if (isolate()->heap()->InNewSpace(callback->data())) { |
| 1269 __ mov(scratch1, Immediate(callback_handle)); | 988 __ mov(scratch1, Immediate(callback)); |
| 1270 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); | 989 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); |
| 1271 } else { | 990 } else { |
| 1272 __ push(Immediate(Handle<Object>(callback_handle->data()))); | 991 __ push(Immediate(Handle<Object>(callback->data()))); |
| 1273 } | 992 } |
| 1274 | 993 |
| 1275 // Save a pointer to where we pushed the arguments pointer. | 994 // Save a pointer to where we pushed the arguments pointer. |
| 1276 // This will be passed as the const AccessorInfo& to the C++ callback. | 995 // This will be passed as the const AccessorInfo& to the C++ callback. |
| 1277 __ push(scratch2); | 996 __ push(scratch2); |
| 1278 | 997 |
| 1279 __ push(name_reg); // name | 998 __ push(name_reg); // name |
| 1280 __ mov(ebx, esp); // esp points to reference to name (handler). | 999 __ mov(ebx, esp); // esp points to reference to name (handler). |
| 1281 | 1000 |
| 1282 __ push(scratch3); // Restore return address. | 1001 __ push(scratch3); // Restore return address. |
| 1283 | 1002 |
| 1284 // Do call through the api. | |
| 1285 Address getter_address = v8::ToCData<Address>(callback->getter()); | |
| 1286 ApiFunction fun(getter_address); | |
| 1287 | |
| 1288 // 3 elements array for v8::Agruments::values_, handler for name and pointer | 1003 // 3 elements array for v8::Agruments::values_, handler for name and pointer |
| 1289 // to the values (it considered as smi in GC). | 1004 // to the values (it considered as smi in GC). |
| 1290 const int kStackSpace = 5; | 1005 const int kStackSpace = 5; |
| 1291 const int kApiArgc = 2; | 1006 const int kApiArgc = 2; |
| 1292 | 1007 |
| 1293 __ PrepareCallApiFunction(kApiArgc); | 1008 __ PrepareCallApiFunction(kApiArgc); |
| 1294 __ mov(ApiParameterOperand(0), ebx); // name. | 1009 __ mov(ApiParameterOperand(0), ebx); // name. |
| 1295 __ add(ebx, Immediate(kPointerSize)); | 1010 __ add(ebx, Immediate(kPointerSize)); |
| 1296 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | 1011 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
| 1297 | 1012 |
| 1298 // Emitting a stub call may try to allocate (if the code is not | 1013 // Emitting a stub call may try to allocate (if the code is not |
| 1299 // already generated). Do not allow the assembler to perform a | 1014 // already generated). Do not allow the assembler to perform a |
| 1300 // garbage collection but instead return the allocation failure | 1015 // garbage collection but instead return the allocation failure |
| 1301 // object. | 1016 // object. |
| 1302 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); | 1017 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1018 __ CallApiFunctionAndReturn(getter_address, kStackSpace); |
| 1303 } | 1019 } |
| 1304 | 1020 |
| 1305 | 1021 |
| 1306 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, | 1022 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, |
| 1307 Handle<JSObject> holder, | 1023 Handle<JSObject> holder, |
| 1308 Register receiver, | 1024 Register receiver, |
| 1309 Register scratch1, | 1025 Register scratch1, |
| 1310 Register scratch2, | 1026 Register scratch2, |
| 1311 Register scratch3, | 1027 Register scratch3, |
| 1312 Handle<Object> value, | 1028 Handle<Object> value, |
| 1313 Handle<String> name, | 1029 Handle<String> name, |
| 1314 Label* miss) { | 1030 Label* miss) { |
| 1315 // Check that the receiver isn't a smi. | 1031 // Check that the receiver isn't a smi. |
| 1316 __ JumpIfSmi(receiver, miss); | 1032 __ JumpIfSmi(receiver, miss); |
| 1317 | 1033 |
| 1318 // Check that the maps haven't changed. | 1034 // Check that the maps haven't changed. |
| 1319 CheckPrototypes( | 1035 CheckPrototypes( |
| 1320 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | 1036 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); |
| 1321 | 1037 |
| 1322 // Return the constant value. | 1038 // Return the constant value. |
| 1323 __ mov(eax, value); | 1039 __ mov(eax, value); |
| 1324 __ ret(0); | 1040 __ ret(0); |
| 1325 } | 1041 } |
| 1326 | 1042 |
| 1327 | 1043 |
| 1328 void StubCompiler::GenerateLoadInterceptor(JSObject* object, | 1044 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
| 1329 JSObject* interceptor_holder, | 1045 Handle<JSObject> interceptor_holder, |
| 1330 LookupResult* lookup, | 1046 LookupResult* lookup, |
| 1331 Register receiver, | 1047 Register receiver, |
| 1332 Register name_reg, | 1048 Register name_reg, |
| 1333 Register scratch1, | 1049 Register scratch1, |
| 1334 Register scratch2, | 1050 Register scratch2, |
| 1335 Register scratch3, | 1051 Register scratch3, |
| 1336 String* name, | 1052 Handle<String> name, |
| 1337 Label* miss) { | 1053 Label* miss) { |
| 1338 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1054 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| 1339 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1055 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 1340 | 1056 |
| 1341 // Check that the receiver isn't a smi. | 1057 // Check that the receiver isn't a smi. |
| 1342 __ JumpIfSmi(receiver, miss); | 1058 __ JumpIfSmi(receiver, miss); |
| 1343 | 1059 |
| 1344 // So far the most popular follow ups for interceptor loads are FIELD | 1060 // So far the most popular follow ups for interceptor loads are FIELD |
| 1345 // and CALLBACKS, so inline only them, other cases may be added | 1061 // and CALLBACKS, so inline only them, other cases may be added |
| 1346 // later. | 1062 // later. |
| 1347 bool compile_followup_inline = false; | 1063 bool compile_followup_inline = false; |
| 1348 if (lookup->IsProperty() && lookup->IsCacheable()) { | 1064 if (lookup->IsProperty() && lookup->IsCacheable()) { |
| 1349 if (lookup->type() == FIELD) { | 1065 if (lookup->type() == FIELD) { |
| 1350 compile_followup_inline = true; | 1066 compile_followup_inline = true; |
| 1351 } else if (lookup->type() == CALLBACKS && | 1067 } else if (lookup->type() == CALLBACKS && |
| 1352 lookup->GetCallbackObject()->IsAccessorInfo() && | 1068 lookup->GetCallbackObject()->IsAccessorInfo()) { |
| 1353 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { | 1069 compile_followup_inline = |
| 1354 compile_followup_inline = true; | 1070 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL; |
| 1355 } | 1071 } |
| 1356 } | 1072 } |
| 1357 | 1073 |
| 1358 if (compile_followup_inline) { | 1074 if (compile_followup_inline) { |
| 1359 // Compile the interceptor call, followed by inline code to load the | 1075 // Compile the interceptor call, followed by inline code to load the |
| 1360 // property from further up the prototype chain if the call fails. | 1076 // property from further up the prototype chain if the call fails. |
| 1361 // Check that the maps haven't changed. | 1077 // Check that the maps haven't changed. |
| 1362 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1078 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
| 1363 scratch1, scratch2, scratch3, | 1079 scratch1, scratch2, scratch3, |
| 1364 name, miss); | 1080 name, miss); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1398 __ pop(holder_reg); | 1114 __ pop(holder_reg); |
| 1399 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | 1115 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
| 1400 __ pop(receiver); | 1116 __ pop(receiver); |
| 1401 } | 1117 } |
| 1402 | 1118 |
| 1403 // Leave the internal frame. | 1119 // Leave the internal frame. |
| 1404 } | 1120 } |
| 1405 | 1121 |
| 1406 // Check that the maps from interceptor's holder to lookup's holder | 1122 // Check that the maps from interceptor's holder to lookup's holder |
| 1407 // haven't changed. And load lookup's holder into holder_reg. | 1123 // haven't changed. And load lookup's holder into holder_reg. |
| 1408 if (interceptor_holder != lookup->holder()) { | 1124 if (*interceptor_holder != lookup->holder()) { |
| 1409 holder_reg = CheckPrototypes(interceptor_holder, | 1125 holder_reg = CheckPrototypes(interceptor_holder, |
| 1410 holder_reg, | 1126 holder_reg, |
| 1411 lookup->holder(), | 1127 Handle<JSObject>(lookup->holder()), |
| 1412 scratch1, | 1128 scratch1, |
| 1413 scratch2, | 1129 scratch2, |
| 1414 scratch3, | 1130 scratch3, |
| 1415 name, | 1131 name, |
| 1416 miss); | 1132 miss); |
| 1417 } | 1133 } |
| 1418 | 1134 |
| 1419 if (lookup->type() == FIELD) { | 1135 if (lookup->type() == FIELD) { |
| 1420 // We found FIELD property in prototype chain of interceptor's holder. | 1136 // We found FIELD property in prototype chain of interceptor's holder. |
| 1421 // Retrieve a field from field's holder. | 1137 // Retrieve a field from field's holder. |
| 1422 GenerateFastPropertyLoad(masm(), eax, holder_reg, | 1138 GenerateFastPropertyLoad(masm(), eax, holder_reg, |
| 1423 Handle<JSObject>(lookup->holder()), | 1139 Handle<JSObject>(lookup->holder()), |
| 1424 lookup->GetFieldIndex()); | 1140 lookup->GetFieldIndex()); |
| 1425 __ ret(0); | 1141 __ ret(0); |
| 1426 } else { | 1142 } else { |
| 1427 // We found CALLBACKS property in prototype chain of interceptor's | 1143 // We found CALLBACKS property in prototype chain of interceptor's |
| 1428 // holder. | 1144 // holder. |
| 1429 ASSERT(lookup->type() == CALLBACKS); | 1145 ASSERT(lookup->type() == CALLBACKS); |
| 1430 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | 1146 Handle<AccessorInfo> callback( |
| 1431 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1147 AccessorInfo::cast(lookup->GetCallbackObject())); |
| 1432 ASSERT(callback != NULL); | |
| 1433 ASSERT(callback->getter() != NULL); | 1148 ASSERT(callback->getter() != NULL); |
| 1434 | 1149 |
| 1435 // Tail call to runtime. | 1150 // Tail call to runtime. |
| 1436 // Important invariant in CALLBACKS case: the code above must be | 1151 // Important invariant in CALLBACKS case: the code above must be |
| 1437 // structured to never clobber |receiver| register. | 1152 // structured to never clobber |receiver| register. |
| 1438 __ pop(scratch2); // return address | 1153 __ pop(scratch2); // return address |
| 1439 __ push(receiver); | 1154 __ push(receiver); |
| 1440 __ push(holder_reg); | 1155 __ push(holder_reg); |
| 1441 __ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback))); | 1156 __ mov(holder_reg, Immediate(callback)); |
| 1442 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); | 1157 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); |
| 1443 __ push(holder_reg); | 1158 __ push(holder_reg); |
| 1444 __ push(name_reg); | 1159 __ push(name_reg); |
| 1445 __ push(scratch2); // restore return address | 1160 __ push(scratch2); // restore return address |
| 1446 | 1161 |
| 1447 ExternalReference ref = | 1162 ExternalReference ref = |
| 1448 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), | 1163 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), |
| 1449 masm()->isolate()); | 1164 masm()->isolate()); |
| 1450 __ TailCallExternalReference(ref, 5, 1); | 1165 __ TailCallExternalReference(ref, 5, 1); |
| 1451 } | 1166 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1469 | 1184 |
| 1470 | 1185 |
| 1471 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { | 1186 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
| 1472 if (kind_ == Code::KEYED_CALL_IC) { | 1187 if (kind_ == Code::KEYED_CALL_IC) { |
| 1473 __ cmp(ecx, Immediate(name)); | 1188 __ cmp(ecx, Immediate(name)); |
| 1474 __ j(not_equal, miss); | 1189 __ j(not_equal, miss); |
| 1475 } | 1190 } |
| 1476 } | 1191 } |
| 1477 | 1192 |
| 1478 | 1193 |
| 1479 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, | 1194 void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object, |
| 1480 JSObject* holder, | 1195 Handle<JSObject> holder, |
| 1481 String* name, | 1196 Handle<String> name, |
| 1482 Label* miss) { | 1197 Label* miss) { |
| 1483 ASSERT(holder->IsGlobalObject()); | 1198 ASSERT(holder->IsGlobalObject()); |
| 1484 | 1199 |
| 1485 // Get the number of arguments. | 1200 // Get the number of arguments. |
| 1486 const int argc = arguments().immediate(); | 1201 const int argc = arguments().immediate(); |
| 1487 | 1202 |
| 1488 // Get the receiver from the stack. | 1203 // Get the receiver from the stack. |
| 1489 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1204 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1490 | 1205 |
| 1491 // If the object is the holder then we know that it's a global | 1206 // If the object is the holder then we know that it's a global |
| 1492 // object which can only happen for contextual calls. In this case, | 1207 // object which can only happen for contextual calls. In this case, |
| 1493 // the receiver cannot be a smi. | 1208 // the receiver cannot be a smi. |
| 1494 if (object != holder) { | 1209 if (!object.is_identical_to(holder)) { |
| 1495 __ JumpIfSmi(edx, miss); | 1210 __ JumpIfSmi(edx, miss); |
| 1496 } | 1211 } |
| 1497 | 1212 |
| 1498 // Check that the maps haven't changed. | 1213 // Check that the maps haven't changed. |
| 1499 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); | 1214 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); |
| 1500 } | 1215 } |
| 1501 | 1216 |
| 1502 | 1217 |
| 1503 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, | 1218 void CallStubCompiler::GenerateLoadFunctionFromCell( |
| 1504 JSFunction* function, | 1219 Handle<JSGlobalPropertyCell> cell, |
| 1505 Label* miss) { | 1220 Handle<JSFunction> function, |
| 1221 Label* miss) { |
| 1506 // Get the value from the cell. | 1222 // Get the value from the cell. |
| 1507 if (Serializer::enabled()) { | 1223 if (Serializer::enabled()) { |
| 1508 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 1224 __ mov(edi, Immediate(cell)); |
| 1509 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); | 1225 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); |
| 1510 } else { | 1226 } else { |
| 1511 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 1227 __ mov(edi, Operand::Cell(cell)); |
| 1512 } | 1228 } |
| 1513 | 1229 |
| 1514 // Check that the cell contains the same function. | 1230 // Check that the cell contains the same function. |
| 1515 if (isolate()->heap()->InNewSpace(function)) { | 1231 if (isolate()->heap()->InNewSpace(*function)) { |
| 1516 // We can't embed a pointer to a function in new space so we have | 1232 // We can't embed a pointer to a function in new space so we have |
| 1517 // to verify that the shared function info is unchanged. This has | 1233 // to verify that the shared function info is unchanged. This has |
| 1518 // the nice side effect that multiple closures based on the same | 1234 // the nice side effect that multiple closures based on the same |
| 1519 // function can all use this call IC. Before we load through the | 1235 // function can all use this call IC. Before we load through the |
| 1520 // function, we have to verify that it still is a function. | 1236 // function, we have to verify that it still is a function. |
| 1521 __ JumpIfSmi(edi, miss); | 1237 __ JumpIfSmi(edi, miss); |
| 1522 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1238 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1523 __ j(not_equal, miss); | 1239 __ j(not_equal, miss); |
| 1524 | 1240 |
| 1525 // Check the shared function info. Make sure it hasn't changed. | 1241 // Check the shared function info. Make sure it hasn't changed. |
| 1526 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1242 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1527 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1243 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1528 __ j(not_equal, miss); | |
| 1529 } else { | 1244 } else { |
| 1530 __ cmp(edi, Immediate(Handle<JSFunction>(function))); | 1245 __ cmp(edi, Immediate(function)); |
| 1531 __ j(not_equal, miss); | |
| 1532 } | 1246 } |
| 1247 __ j(not_equal, miss); |
| 1533 } | 1248 } |
| 1534 | 1249 |
| 1535 | 1250 |
| 1536 void CallStubCompiler::GenerateMissBranch() { | 1251 void CallStubCompiler::GenerateMissBranch() { |
| 1537 Handle<Code> code = | 1252 Handle<Code> code = |
| 1538 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | 1253 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), |
| 1539 kind_, | 1254 kind_, |
| 1540 extra_state_); | 1255 extra_state_); |
| 1541 __ jmp(code, RelocInfo::CODE_TARGET); | 1256 __ jmp(code, RelocInfo::CODE_TARGET); |
| 1542 } | 1257 } |
| 1543 | 1258 |
| 1544 | 1259 |
| 1545 // TODO(kmillikin): Eliminate this function when the stub cache is fully | |
| 1546 // handlified. | |
| 1547 MaybeObject* CallStubCompiler::TryGenerateMissBranch() { | |
| 1548 MaybeObject* maybe_obj = | |
| 1549 isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(), | |
| 1550 kind_, | |
| 1551 extra_state_); | |
| 1552 Object* obj; | |
| 1553 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 1554 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); | |
| 1555 return obj; | |
| 1556 } | |
| 1557 | |
| 1558 | |
| 1559 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | 1260 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, |
| 1560 Handle<JSObject> holder, | 1261 Handle<JSObject> holder, |
| 1561 int index, | 1262 int index, |
| 1562 Handle<String> name) { | 1263 Handle<String> name) { |
| 1563 // ----------- S t a t e ------------- | 1264 // ----------- S t a t e ------------- |
| 1564 // -- ecx : name | 1265 // -- ecx : name |
| 1565 // -- esp[0] : return address | 1266 // -- esp[0] : return address |
| 1566 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1267 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1567 // -- ... | 1268 // -- ... |
| 1568 // -- esp[(argc + 1) * 4] : receiver | 1269 // -- esp[(argc + 1) * 4] : receiver |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 | 1306 |
| 1606 // Handle call cache miss. | 1307 // Handle call cache miss. |
| 1607 __ bind(&miss); | 1308 __ bind(&miss); |
| 1608 GenerateMissBranch(); | 1309 GenerateMissBranch(); |
| 1609 | 1310 |
| 1610 // Return the generated code. | 1311 // Return the generated code. |
| 1611 return GetCode(FIELD, name); | 1312 return GetCode(FIELD, name); |
| 1612 } | 1313 } |
| 1613 | 1314 |
| 1614 | 1315 |
| 1615 MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, | 1316 Handle<Code> CallStubCompiler::CompileArrayPushCall( |
| 1616 JSObject* holder, | 1317 Handle<Object> object, |
| 1617 JSGlobalPropertyCell* cell, | 1318 Handle<JSObject> holder, |
| 1618 JSFunction* function, | 1319 Handle<JSGlobalPropertyCell> cell, |
| 1619 String* name) { | 1320 Handle<JSFunction> function, |
| 1321 Handle<String> name) { |
| 1620 // ----------- S t a t e ------------- | 1322 // ----------- S t a t e ------------- |
| 1621 // -- ecx : name | 1323 // -- ecx : name |
| 1622 // -- esp[0] : return address | 1324 // -- esp[0] : return address |
| 1623 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1325 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1624 // -- ... | 1326 // -- ... |
| 1625 // -- esp[(argc + 1) * 4] : receiver | 1327 // -- esp[(argc + 1) * 4] : receiver |
| 1626 // ----------------------------------- | 1328 // ----------------------------------- |
| 1627 | 1329 |
| 1628 // If object is not an array, bail out to regular call. | 1330 // If object is not an array, bail out to regular call. |
| 1629 if (!object->IsJSArray() || cell != NULL) { | 1331 if (!object->IsJSArray() || !cell.is_null()) { |
| 1630 return isolate()->heap()->undefined_value(); | 1332 return Handle<Code>::null(); |
| 1631 } | 1333 } |
| 1632 | 1334 |
| 1633 Label miss; | 1335 Label miss; |
| 1634 | 1336 |
| 1635 GenerateNameCheck(Handle<String>(name), &miss); | 1337 GenerateNameCheck(name, &miss); |
| 1636 | 1338 |
| 1637 // Get the receiver from the stack. | 1339 // Get the receiver from the stack. |
| 1638 const int argc = arguments().immediate(); | 1340 const int argc = arguments().immediate(); |
| 1639 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1341 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1640 | 1342 |
| 1641 // Check that the receiver isn't a smi. | 1343 // Check that the receiver isn't a smi. |
| 1642 __ JumpIfSmi(edx, &miss); | 1344 __ JumpIfSmi(edx, &miss); |
| 1643 | 1345 |
| 1644 CheckPrototypes(JSObject::cast(object), edx, | 1346 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 1645 holder, ebx, | 1347 name, &miss); |
| 1646 eax, edi, name, &miss); | |
| 1647 | 1348 |
| 1648 if (argc == 0) { | 1349 if (argc == 0) { |
| 1649 // Noop, return the length. | 1350 // Noop, return the length. |
| 1650 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1351 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1651 __ ret((argc + 1) * kPointerSize); | 1352 __ ret((argc + 1) * kPointerSize); |
| 1652 } else { | 1353 } else { |
| 1653 Label call_builtin; | 1354 Label call_builtin; |
| 1654 | 1355 |
| 1655 // Get the elements array of the object. | 1356 // Get the elements array of the object. |
| 1656 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1357 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1698 | 1399 |
| 1699 // Save new length. | 1400 // Save new length. |
| 1700 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | 1401 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1701 | 1402 |
| 1702 // Push the element. | 1403 // Push the element. |
| 1703 __ lea(edx, FieldOperand(ebx, | 1404 __ lea(edx, FieldOperand(ebx, |
| 1704 eax, times_half_pointer_size, | 1405 eax, times_half_pointer_size, |
| 1705 FixedArray::kHeaderSize - argc * kPointerSize)); | 1406 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1706 __ mov(Operand(edx, 0), ecx); | 1407 __ mov(Operand(edx, 0), ecx); |
| 1707 | 1408 |
| 1708 __ RecordWrite( | 1409 __ RecordWrite(ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, |
| 1709 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 1410 OMIT_SMI_CHECK); |
| 1710 | 1411 |
| 1711 __ ret((argc + 1) * kPointerSize); | 1412 __ ret((argc + 1) * kPointerSize); |
| 1712 | 1413 |
| 1713 __ bind(&attempt_to_grow_elements); | 1414 __ bind(&attempt_to_grow_elements); |
| 1714 if (!FLAG_inline_new) { | 1415 if (!FLAG_inline_new) { |
| 1715 __ jmp(&call_builtin); | 1416 __ jmp(&call_builtin); |
| 1716 } | 1417 } |
| 1717 | 1418 |
| 1718 __ mov(edi, Operand(esp, argc * kPointerSize)); | 1419 __ mov(edi, Operand(esp, argc * kPointerSize)); |
| 1719 // Growing elements that are SMI-only requires special handling in case | 1420 // Growing elements that are SMI-only requires special handling in case |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1782 } | 1483 } |
| 1783 | 1484 |
| 1784 __ bind(&call_builtin); | 1485 __ bind(&call_builtin); |
| 1785 __ TailCallExternalReference( | 1486 __ TailCallExternalReference( |
| 1786 ExternalReference(Builtins::c_ArrayPush, isolate()), | 1487 ExternalReference(Builtins::c_ArrayPush, isolate()), |
| 1787 argc + 1, | 1488 argc + 1, |
| 1788 1); | 1489 1); |
| 1789 } | 1490 } |
| 1790 | 1491 |
| 1791 __ bind(&miss); | 1492 __ bind(&miss); |
| 1792 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1493 GenerateMissBranch(); |
| 1793 if (maybe_result->IsFailure()) return maybe_result; | |
| 1794 | 1494 |
| 1795 // Return the generated code. | 1495 // Return the generated code. |
| 1796 return TryGetCode(function); | 1496 return GetCode(function); |
| 1797 } | 1497 } |
| 1798 | 1498 |
| 1799 | 1499 |
| 1800 MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object, | 1500 Handle<Code> CallStubCompiler::CompileArrayPopCall( |
| 1801 JSObject* holder, | 1501 Handle<Object> object, |
| 1802 JSGlobalPropertyCell* cell, | 1502 Handle<JSObject> holder, |
| 1803 JSFunction* function, | 1503 Handle<JSGlobalPropertyCell> cell, |
| 1804 String* name) { | 1504 Handle<JSFunction> function, |
| 1505 Handle<String> name) { |
| 1805 // ----------- S t a t e ------------- | 1506 // ----------- S t a t e ------------- |
| 1806 // -- ecx : name | 1507 // -- ecx : name |
| 1807 // -- esp[0] : return address | 1508 // -- esp[0] : return address |
| 1808 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1509 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1809 // -- ... | 1510 // -- ... |
| 1810 // -- esp[(argc + 1) * 4] : receiver | 1511 // -- esp[(argc + 1) * 4] : receiver |
| 1811 // ----------------------------------- | 1512 // ----------------------------------- |
| 1812 | 1513 |
| 1813 // If object is not an array, bail out to regular call. | 1514 // If object is not an array, bail out to regular call. |
| 1814 if (!object->IsJSArray() || cell != NULL) { | 1515 if (!object->IsJSArray() || !cell.is_null()) { |
| 1815 return heap()->undefined_value(); | 1516 return Handle<Code>::null(); |
| 1816 } | 1517 } |
| 1817 | 1518 |
| 1818 Label miss, return_undefined, call_builtin; | 1519 Label miss, return_undefined, call_builtin; |
| 1819 | 1520 |
| 1820 GenerateNameCheck(Handle<String>(name), &miss); | 1521 GenerateNameCheck(name, &miss); |
| 1821 | 1522 |
| 1822 // Get the receiver from the stack. | 1523 // Get the receiver from the stack. |
| 1823 const int argc = arguments().immediate(); | 1524 const int argc = arguments().immediate(); |
| 1824 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1525 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1825 | 1526 |
| 1826 // Check that the receiver isn't a smi. | 1527 // Check that the receiver isn't a smi. |
| 1827 __ JumpIfSmi(edx, &miss); | 1528 __ JumpIfSmi(edx, &miss); |
| 1828 CheckPrototypes(JSObject::cast(object), edx, | 1529 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 1829 holder, ebx, | 1530 name, &miss); |
| 1830 eax, edi, name, &miss); | |
| 1831 | 1531 |
| 1832 // Get the elements array of the object. | 1532 // Get the elements array of the object. |
| 1833 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1533 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1834 | 1534 |
| 1835 // Check that the elements are in fast mode and writable. | 1535 // Check that the elements are in fast mode and writable. |
| 1836 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1536 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1837 Immediate(factory()->fixed_array_map())); | 1537 Immediate(factory()->fixed_array_map())); |
| 1838 __ j(not_equal, &call_builtin); | 1538 __ j(not_equal, &call_builtin); |
| 1839 | 1539 |
| 1840 // Get the array's length into ecx and calculate new length. | 1540 // Get the array's length into ecx and calculate new length. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1865 __ mov(eax, Immediate(factory()->undefined_value())); | 1565 __ mov(eax, Immediate(factory()->undefined_value())); |
| 1866 __ ret((argc + 1) * kPointerSize); | 1566 __ ret((argc + 1) * kPointerSize); |
| 1867 | 1567 |
| 1868 __ bind(&call_builtin); | 1568 __ bind(&call_builtin); |
| 1869 __ TailCallExternalReference( | 1569 __ TailCallExternalReference( |
| 1870 ExternalReference(Builtins::c_ArrayPop, isolate()), | 1570 ExternalReference(Builtins::c_ArrayPop, isolate()), |
| 1871 argc + 1, | 1571 argc + 1, |
| 1872 1); | 1572 1); |
| 1873 | 1573 |
| 1874 __ bind(&miss); | 1574 __ bind(&miss); |
| 1875 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1575 GenerateMissBranch(); |
| 1876 if (maybe_result->IsFailure()) return maybe_result; | |
| 1877 | 1576 |
| 1878 // Return the generated code. | 1577 // Return the generated code. |
| 1879 return TryGetCode(function); | 1578 return GetCode(function); |
| 1880 } | 1579 } |
| 1881 | 1580 |
| 1882 | 1581 |
| 1883 MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( | 1582 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( |
| 1884 Object* object, | 1583 Handle<Object> object, |
| 1885 JSObject* holder, | 1584 Handle<JSObject> holder, |
| 1886 JSGlobalPropertyCell* cell, | 1585 Handle<JSGlobalPropertyCell> cell, |
| 1887 JSFunction* function, | 1586 Handle<JSFunction> function, |
| 1888 String* name) { | 1587 Handle<String> name) { |
| 1889 // ----------- S t a t e ------------- | 1588 // ----------- S t a t e ------------- |
| 1890 // -- ecx : function name | 1589 // -- ecx : function name |
| 1891 // -- esp[0] : return address | 1590 // -- esp[0] : return address |
| 1892 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1591 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1893 // -- ... | 1592 // -- ... |
| 1894 // -- esp[(argc + 1) * 4] : receiver | 1593 // -- esp[(argc + 1) * 4] : receiver |
| 1895 // ----------------------------------- | 1594 // ----------------------------------- |
| 1896 | 1595 |
| 1897 // If object is not a string, bail out to regular call. | 1596 // If object is not a string, bail out to regular call. |
| 1898 if (!object->IsString() || cell != NULL) { | 1597 if (!object->IsString() || !cell.is_null()) { |
| 1899 return isolate()->heap()->undefined_value(); | 1598 return Handle<Code>::null(); |
| 1900 } | 1599 } |
| 1901 | 1600 |
| 1902 const int argc = arguments().immediate(); | 1601 const int argc = arguments().immediate(); |
| 1903 | 1602 |
| 1904 Label miss; | 1603 Label miss; |
| 1905 Label name_miss; | 1604 Label name_miss; |
| 1906 Label index_out_of_range; | 1605 Label index_out_of_range; |
| 1907 Label* index_out_of_range_label = &index_out_of_range; | 1606 Label* index_out_of_range_label = &index_out_of_range; |
| 1908 | 1607 |
| 1909 if (kind_ == Code::CALL_IC && | 1608 if (kind_ == Code::CALL_IC && |
| 1910 (CallICBase::StringStubState::decode(extra_state_) == | 1609 (CallICBase::StringStubState::decode(extra_state_) == |
| 1911 DEFAULT_STRING_STUB)) { | 1610 DEFAULT_STRING_STUB)) { |
| 1912 index_out_of_range_label = &miss; | 1611 index_out_of_range_label = &miss; |
| 1913 } | 1612 } |
| 1914 | 1613 |
| 1915 GenerateNameCheck(Handle<String>(name), &name_miss); | 1614 GenerateNameCheck(name, &name_miss); |
| 1916 | 1615 |
| 1917 // Check that the maps starting from the prototype haven't changed. | 1616 // Check that the maps starting from the prototype haven't changed. |
| 1918 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1617 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 1919 Context::STRING_FUNCTION_INDEX, | 1618 Context::STRING_FUNCTION_INDEX, |
| 1920 eax, | 1619 eax, |
| 1921 &miss); | 1620 &miss); |
| 1922 ASSERT(object != holder); | 1621 ASSERT(!object.is_identical_to(holder)); |
| 1923 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 1622 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())), |
| 1924 ebx, edx, edi, name, &miss); | 1623 eax, holder, ebx, edx, edi, name, &miss); |
| 1925 | 1624 |
| 1926 Register receiver = ebx; | 1625 Register receiver = ebx; |
| 1927 Register index = edi; | 1626 Register index = edi; |
| 1928 Register scratch = edx; | 1627 Register scratch = edx; |
| 1929 Register result = eax; | 1628 Register result = eax; |
| 1930 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1629 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 1931 if (argc > 0) { | 1630 if (argc > 0) { |
| 1932 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1631 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 1933 } else { | 1632 } else { |
| 1934 __ Set(index, Immediate(factory()->undefined_value())); | 1633 __ Set(index, Immediate(factory()->undefined_value())); |
| 1935 } | 1634 } |
| 1936 | 1635 |
| 1937 StringCharCodeAtGenerator char_code_at_generator(receiver, | 1636 StringCharCodeAtGenerator generator(receiver, |
| 1938 index, | 1637 index, |
| 1939 scratch, | 1638 scratch, |
| 1940 result, | 1639 result, |
| 1941 &miss, // When not a string. | 1640 &miss, // When not a string. |
| 1942 &miss, // When not a number. | 1641 &miss, // When not a number. |
| 1943 index_out_of_range_label, | 1642 index_out_of_range_label, |
| 1944 STRING_INDEX_IS_NUMBER); | 1643 STRING_INDEX_IS_NUMBER); |
| 1945 char_code_at_generator.GenerateFast(masm()); | 1644 generator.GenerateFast(masm()); |
| 1946 __ ret((argc + 1) * kPointerSize); | 1645 __ ret((argc + 1) * kPointerSize); |
| 1947 | 1646 |
| 1948 StubRuntimeCallHelper call_helper; | 1647 StubRuntimeCallHelper call_helper; |
| 1949 char_code_at_generator.GenerateSlow(masm(), call_helper); | 1648 generator.GenerateSlow(masm(), call_helper); |
| 1950 | 1649 |
| 1951 if (index_out_of_range.is_linked()) { | 1650 if (index_out_of_range.is_linked()) { |
| 1952 __ bind(&index_out_of_range); | 1651 __ bind(&index_out_of_range); |
| 1953 __ Set(eax, Immediate(factory()->nan_value())); | 1652 __ Set(eax, Immediate(factory()->nan_value())); |
| 1954 __ ret((argc + 1) * kPointerSize); | 1653 __ ret((argc + 1) * kPointerSize); |
| 1955 } | 1654 } |
| 1956 | 1655 |
| 1957 __ bind(&miss); | 1656 __ bind(&miss); |
| 1958 // Restore function name in ecx. | 1657 // Restore function name in ecx. |
| 1959 __ Set(ecx, Immediate(Handle<String>(name))); | 1658 __ Set(ecx, Immediate(name)); |
| 1960 __ bind(&name_miss); | 1659 __ bind(&name_miss); |
| 1961 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1660 GenerateMissBranch(); |
| 1962 if (maybe_result->IsFailure()) return maybe_result; | |
| 1963 | 1661 |
| 1964 // Return the generated code. | 1662 // Return the generated code. |
| 1965 return TryGetCode(function); | 1663 return GetCode(function); |
| 1966 } | 1664 } |
| 1967 | 1665 |
| 1968 | 1666 |
| 1969 MaybeObject* CallStubCompiler::CompileStringCharAtCall( | 1667 Handle<Code> CallStubCompiler::CompileStringCharAtCall( |
| 1970 Object* object, | 1668 Handle<Object> object, |
| 1971 JSObject* holder, | 1669 Handle<JSObject> holder, |
| 1972 JSGlobalPropertyCell* cell, | 1670 Handle<JSGlobalPropertyCell> cell, |
| 1973 JSFunction* function, | 1671 Handle<JSFunction> function, |
| 1974 String* name) { | 1672 Handle<String> name) { |
| 1975 // ----------- S t a t e ------------- | 1673 // ----------- S t a t e ------------- |
| 1976 // -- ecx : function name | 1674 // -- ecx : function name |
| 1977 // -- esp[0] : return address | 1675 // -- esp[0] : return address |
| 1978 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1676 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1979 // -- ... | 1677 // -- ... |
| 1980 // -- esp[(argc + 1) * 4] : receiver | 1678 // -- esp[(argc + 1) * 4] : receiver |
| 1981 // ----------------------------------- | 1679 // ----------------------------------- |
| 1982 | 1680 |
| 1983 // If object is not a string, bail out to regular call. | 1681 // If object is not a string, bail out to regular call. |
| 1984 if (!object->IsString() || cell != NULL) { | 1682 if (!object->IsString() || !cell.is_null()) { |
| 1985 return heap()->undefined_value(); | 1683 return Handle<Code>::null(); |
| 1986 } | 1684 } |
| 1987 | 1685 |
| 1988 const int argc = arguments().immediate(); | 1686 const int argc = arguments().immediate(); |
| 1989 | 1687 |
| 1990 Label miss; | 1688 Label miss; |
| 1991 Label name_miss; | 1689 Label name_miss; |
| 1992 Label index_out_of_range; | 1690 Label index_out_of_range; |
| 1993 Label* index_out_of_range_label = &index_out_of_range; | 1691 Label* index_out_of_range_label = &index_out_of_range; |
| 1994 | 1692 |
| 1995 if (kind_ == Code::CALL_IC && | 1693 if (kind_ == Code::CALL_IC && |
| 1996 (CallICBase::StringStubState::decode(extra_state_) == | 1694 (CallICBase::StringStubState::decode(extra_state_) == |
| 1997 DEFAULT_STRING_STUB)) { | 1695 DEFAULT_STRING_STUB)) { |
| 1998 index_out_of_range_label = &miss; | 1696 index_out_of_range_label = &miss; |
| 1999 } | 1697 } |
| 2000 | 1698 |
| 2001 GenerateNameCheck(Handle<String>(name), &name_miss); | 1699 GenerateNameCheck(name, &name_miss); |
| 2002 | 1700 |
| 2003 // Check that the maps starting from the prototype haven't changed. | 1701 // Check that the maps starting from the prototype haven't changed. |
| 2004 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1702 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 2005 Context::STRING_FUNCTION_INDEX, | 1703 Context::STRING_FUNCTION_INDEX, |
| 2006 eax, | 1704 eax, |
| 2007 &miss); | 1705 &miss); |
| 2008 ASSERT(object != holder); | 1706 ASSERT(!object.is_identical_to(holder)); |
| 2009 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 1707 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())), |
| 2010 ebx, edx, edi, name, &miss); | 1708 eax, holder, ebx, edx, edi, name, &miss); |
| 2011 | 1709 |
| 2012 Register receiver = eax; | 1710 Register receiver = eax; |
| 2013 Register index = edi; | 1711 Register index = edi; |
| 2014 Register scratch1 = ebx; | 1712 Register scratch1 = ebx; |
| 2015 Register scratch2 = edx; | 1713 Register scratch2 = edx; |
| 2016 Register result = eax; | 1714 Register result = eax; |
| 2017 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1715 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 2018 if (argc > 0) { | 1716 if (argc > 0) { |
| 2019 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1717 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 2020 } else { | 1718 } else { |
| 2021 __ Set(index, Immediate(factory()->undefined_value())); | 1719 __ Set(index, Immediate(factory()->undefined_value())); |
| 2022 } | 1720 } |
| 2023 | 1721 |
| 2024 StringCharAtGenerator char_at_generator(receiver, | 1722 StringCharAtGenerator generator(receiver, |
| 2025 index, | 1723 index, |
| 2026 scratch1, | 1724 scratch1, |
| 2027 scratch2, | 1725 scratch2, |
| 2028 result, | 1726 result, |
| 2029 &miss, // When not a string. | 1727 &miss, // When not a string. |
| 2030 &miss, // When not a number. | 1728 &miss, // When not a number. |
| 2031 index_out_of_range_label, | 1729 index_out_of_range_label, |
| 2032 STRING_INDEX_IS_NUMBER); | 1730 STRING_INDEX_IS_NUMBER); |
| 2033 char_at_generator.GenerateFast(masm()); | 1731 generator.GenerateFast(masm()); |
| 2034 __ ret((argc + 1) * kPointerSize); | 1732 __ ret((argc + 1) * kPointerSize); |
| 2035 | 1733 |
| 2036 StubRuntimeCallHelper call_helper; | 1734 StubRuntimeCallHelper call_helper; |
| 2037 char_at_generator.GenerateSlow(masm(), call_helper); | 1735 generator.GenerateSlow(masm(), call_helper); |
| 2038 | 1736 |
| 2039 if (index_out_of_range.is_linked()) { | 1737 if (index_out_of_range.is_linked()) { |
| 2040 __ bind(&index_out_of_range); | 1738 __ bind(&index_out_of_range); |
| 2041 __ Set(eax, Immediate(factory()->empty_string())); | 1739 __ Set(eax, Immediate(factory()->empty_string())); |
| 2042 __ ret((argc + 1) * kPointerSize); | 1740 __ ret((argc + 1) * kPointerSize); |
| 2043 } | 1741 } |
| 2044 | 1742 |
| 2045 __ bind(&miss); | 1743 __ bind(&miss); |
| 2046 // Restore function name in ecx. | 1744 // Restore function name in ecx. |
| 2047 __ Set(ecx, Immediate(Handle<String>(name))); | 1745 __ Set(ecx, Immediate(name)); |
| 2048 __ bind(&name_miss); | 1746 __ bind(&name_miss); |
| 2049 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1747 GenerateMissBranch(); |
| 2050 if (maybe_result->IsFailure()) return maybe_result; | |
| 2051 | 1748 |
| 2052 // Return the generated code. | 1749 // Return the generated code. |
| 2053 return TryGetCode(function); | 1750 return GetCode(function); |
| 2054 } | 1751 } |
| 2055 | 1752 |
| 2056 | 1753 |
| 2057 MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( | 1754 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( |
| 2058 Object* object, | 1755 Handle<Object> object, |
| 2059 JSObject* holder, | 1756 Handle<JSObject> holder, |
| 2060 JSGlobalPropertyCell* cell, | 1757 Handle<JSGlobalPropertyCell> cell, |
| 2061 JSFunction* function, | 1758 Handle<JSFunction> function, |
| 2062 String* name) { | 1759 Handle<String> name) { |
| 2063 // ----------- S t a t e ------------- | 1760 // ----------- S t a t e ------------- |
| 2064 // -- ecx : function name | 1761 // -- ecx : function name |
| 2065 // -- esp[0] : return address | 1762 // -- esp[0] : return address |
| 2066 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1763 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2067 // -- ... | 1764 // -- ... |
| 2068 // -- esp[(argc + 1) * 4] : receiver | 1765 // -- esp[(argc + 1) * 4] : receiver |
| 2069 // ----------------------------------- | 1766 // ----------------------------------- |
| 2070 | 1767 |
| 2071 const int argc = arguments().immediate(); | 1768 const int argc = arguments().immediate(); |
| 2072 | 1769 |
| 2073 // If the object is not a JSObject or we got an unexpected number of | 1770 // If the object is not a JSObject or we got an unexpected number of |
| 2074 // arguments, bail out to the regular call. | 1771 // arguments, bail out to the regular call. |
| 2075 if (!object->IsJSObject() || argc != 1) { | 1772 if (!object->IsJSObject() || argc != 1) { |
| 2076 return isolate()->heap()->undefined_value(); | 1773 return Handle<Code>::null(); |
| 2077 } | 1774 } |
| 2078 | 1775 |
| 2079 Label miss; | 1776 Label miss; |
| 2080 GenerateNameCheck(Handle<String>(name), &miss); | 1777 GenerateNameCheck(name, &miss); |
| 2081 | 1778 |
| 2082 if (cell == NULL) { | 1779 if (cell.is_null()) { |
| 2083 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1780 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2084 | |
| 2085 STATIC_ASSERT(kSmiTag == 0); | 1781 STATIC_ASSERT(kSmiTag == 0); |
| 2086 __ JumpIfSmi(edx, &miss); | 1782 __ JumpIfSmi(edx, &miss); |
| 2087 | 1783 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 2088 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 1784 name, &miss); |
| 2089 &miss); | |
| 2090 } else { | 1785 } else { |
| 2091 ASSERT(cell->value() == function); | 1786 ASSERT(cell->value() == *function); |
| 2092 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 1787 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, |
| 1788 &miss); |
| 2093 GenerateLoadFunctionFromCell(cell, function, &miss); | 1789 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2094 } | 1790 } |
| 2095 | 1791 |
| 2096 // Load the char code argument. | 1792 // Load the char code argument. |
| 2097 Register code = ebx; | 1793 Register code = ebx; |
| 2098 __ mov(code, Operand(esp, 1 * kPointerSize)); | 1794 __ mov(code, Operand(esp, 1 * kPointerSize)); |
| 2099 | 1795 |
| 2100 // Check the code is a smi. | 1796 // Check the code is a smi. |
| 2101 Label slow; | 1797 Label slow; |
| 2102 STATIC_ASSERT(kSmiTag == 0); | 1798 STATIC_ASSERT(kSmiTag == 0); |
| 2103 __ JumpIfNotSmi(code, &slow); | 1799 __ JumpIfNotSmi(code, &slow); |
| 2104 | 1800 |
| 2105 // Convert the smi code to uint16. | 1801 // Convert the smi code to uint16. |
| 2106 __ and_(code, Immediate(Smi::FromInt(0xffff))); | 1802 __ and_(code, Immediate(Smi::FromInt(0xffff))); |
| 2107 | 1803 |
| 2108 StringCharFromCodeGenerator char_from_code_generator(code, eax); | 1804 StringCharFromCodeGenerator generator(code, eax); |
| 2109 char_from_code_generator.GenerateFast(masm()); | 1805 generator.GenerateFast(masm()); |
| 2110 __ ret(2 * kPointerSize); | 1806 __ ret(2 * kPointerSize); |
| 2111 | 1807 |
| 2112 StubRuntimeCallHelper call_helper; | 1808 StubRuntimeCallHelper call_helper; |
| 2113 char_from_code_generator.GenerateSlow(masm(), call_helper); | 1809 generator.GenerateSlow(masm(), call_helper); |
| 2114 | 1810 |
| 2115 // Tail call the full function. We do not have to patch the receiver | 1811 // Tail call the full function. We do not have to patch the receiver |
| 2116 // because the function makes no use of it. | 1812 // because the function makes no use of it. |
| 2117 __ bind(&slow); | 1813 __ bind(&slow); |
| 2118 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 1814 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) |
| 2119 ? CALL_AS_FUNCTION | 1815 ? CALL_AS_FUNCTION |
| 2120 : CALL_AS_METHOD; | 1816 : CALL_AS_METHOD; |
| 2121 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, | 1817 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2122 NullCallWrapper(), call_kind); | 1818 NullCallWrapper(), call_kind); |
| 2123 | 1819 |
| 2124 __ bind(&miss); | 1820 __ bind(&miss); |
| 2125 // ecx: function name. | 1821 // ecx: function name. |
| 2126 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1822 GenerateMissBranch(); |
| 2127 if (maybe_result->IsFailure()) return maybe_result; | |
| 2128 | 1823 |
| 2129 // Return the generated code. | 1824 // Return the generated code. |
| 2130 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); | 1825 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name); |
| 2131 } | 1826 } |
| 2132 | 1827 |
| 2133 | 1828 |
| 2134 MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object, | 1829 Handle<Code> CallStubCompiler::CompileMathFloorCall( |
| 2135 JSObject* holder, | 1830 Handle<Object> object, |
| 2136 JSGlobalPropertyCell* cell, | 1831 Handle<JSObject> holder, |
| 2137 JSFunction* function, | 1832 Handle<JSGlobalPropertyCell> cell, |
| 2138 String* name) { | 1833 Handle<JSFunction> function, |
| 1834 Handle<String> name) { |
| 2139 // ----------- S t a t e ------------- | 1835 // ----------- S t a t e ------------- |
| 2140 // -- ecx : name | 1836 // -- ecx : name |
| 2141 // -- esp[0] : return address | 1837 // -- esp[0] : return address |
| 2142 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1838 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2143 // -- ... | 1839 // -- ... |
| 2144 // -- esp[(argc + 1) * 4] : receiver | 1840 // -- esp[(argc + 1) * 4] : receiver |
| 2145 // ----------------------------------- | 1841 // ----------------------------------- |
| 2146 | 1842 |
| 2147 if (!CpuFeatures::IsSupported(SSE2)) { | 1843 if (!CpuFeatures::IsSupported(SSE2)) { |
| 2148 return isolate()->heap()->undefined_value(); | 1844 return Handle<Code>::null(); |
| 2149 } | 1845 } |
| 2150 | 1846 |
| 2151 CpuFeatures::Scope use_sse2(SSE2); | 1847 CpuFeatures::Scope use_sse2(SSE2); |
| 2152 | 1848 |
| 2153 const int argc = arguments().immediate(); | 1849 const int argc = arguments().immediate(); |
| 2154 | 1850 |
| 2155 // If the object is not a JSObject or we got an unexpected number of | 1851 // If the object is not a JSObject or we got an unexpected number of |
| 2156 // arguments, bail out to the regular call. | 1852 // arguments, bail out to the regular call. |
| 2157 if (!object->IsJSObject() || argc != 1) { | 1853 if (!object->IsJSObject() || argc != 1) { |
| 2158 return isolate()->heap()->undefined_value(); | 1854 return Handle<Code>::null(); |
| 2159 } | 1855 } |
| 2160 | 1856 |
| 2161 Label miss; | 1857 Label miss; |
| 2162 GenerateNameCheck(Handle<String>(name), &miss); | 1858 GenerateNameCheck(name, &miss); |
| 2163 | 1859 |
| 2164 if (cell == NULL) { | 1860 if (cell.is_null()) { |
| 2165 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1861 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2166 | 1862 |
| 2167 STATIC_ASSERT(kSmiTag == 0); | 1863 STATIC_ASSERT(kSmiTag == 0); |
| 2168 __ JumpIfSmi(edx, &miss); | 1864 __ JumpIfSmi(edx, &miss); |
| 2169 | 1865 |
| 2170 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 1866 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 2171 &miss); | 1867 name, &miss); |
| 2172 } else { | 1868 } else { |
| 2173 ASSERT(cell->value() == function); | 1869 ASSERT(cell->value() == *function); |
| 2174 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 1870 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, |
| 1871 &miss); |
| 2175 GenerateLoadFunctionFromCell(cell, function, &miss); | 1872 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2176 } | 1873 } |
| 2177 | 1874 |
| 2178 // Load the (only) argument into eax. | 1875 // Load the (only) argument into eax. |
| 2179 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 1876 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2180 | 1877 |
| 2181 // Check if the argument is a smi. | 1878 // Check if the argument is a smi. |
| 2182 Label smi; | 1879 Label smi; |
| 2183 STATIC_ASSERT(kSmiTag == 0); | 1880 STATIC_ASSERT(kSmiTag == 0); |
| 2184 __ JumpIfSmi(eax, &smi); | 1881 __ JumpIfSmi(eax, &smi); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 __ ret(2 * kPointerSize); | 1942 __ ret(2 * kPointerSize); |
| 2246 | 1943 |
| 2247 // Tail call the full function. We do not have to patch the receiver | 1944 // Tail call the full function. We do not have to patch the receiver |
| 2248 // because the function makes no use of it. | 1945 // because the function makes no use of it. |
| 2249 __ bind(&slow); | 1946 __ bind(&slow); |
| 2250 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, | 1947 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2251 NullCallWrapper(), CALL_AS_METHOD); | 1948 NullCallWrapper(), CALL_AS_METHOD); |
| 2252 | 1949 |
| 2253 __ bind(&miss); | 1950 __ bind(&miss); |
| 2254 // ecx: function name. | 1951 // ecx: function name. |
| 2255 MaybeObject* maybe_result = TryGenerateMissBranch(); | 1952 GenerateMissBranch(); |
| 2256 if (maybe_result->IsFailure()) return maybe_result; | |
| 2257 | 1953 |
| 2258 // Return the generated code. | 1954 // Return the generated code. |
| 2259 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); | 1955 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name); |
| 2260 } | 1956 } |
| 2261 | 1957 |
| 2262 | 1958 |
| 2263 MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, | 1959 Handle<Code> CallStubCompiler::CompileMathAbsCall( |
| 2264 JSObject* holder, | 1960 Handle<Object> object, |
| 2265 JSGlobalPropertyCell* cell, | 1961 Handle<JSObject> holder, |
| 2266 JSFunction* function, | 1962 Handle<JSGlobalPropertyCell> cell, |
| 2267 String* name) { | 1963 Handle<JSFunction> function, |
| 1964 Handle<String> name) { |
| 2268 // ----------- S t a t e ------------- | 1965 // ----------- S t a t e ------------- |
| 2269 // -- ecx : name | 1966 // -- ecx : name |
| 2270 // -- esp[0] : return address | 1967 // -- esp[0] : return address |
| 2271 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1968 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2272 // -- ... | 1969 // -- ... |
| 2273 // -- esp[(argc + 1) * 4] : receiver | 1970 // -- esp[(argc + 1) * 4] : receiver |
| 2274 // ----------------------------------- | 1971 // ----------------------------------- |
| 2275 | 1972 |
| 2276 const int argc = arguments().immediate(); | 1973 const int argc = arguments().immediate(); |
| 2277 | 1974 |
| 2278 // If the object is not a JSObject or we got an unexpected number of | 1975 // If the object is not a JSObject or we got an unexpected number of |
| 2279 // arguments, bail out to the regular call. | 1976 // arguments, bail out to the regular call. |
| 2280 if (!object->IsJSObject() || argc != 1) { | 1977 if (!object->IsJSObject() || argc != 1) { |
| 2281 return isolate()->heap()->undefined_value(); | 1978 return Handle<Code>::null(); |
| 2282 } | 1979 } |
| 2283 | 1980 |
| 2284 Label miss; | 1981 Label miss; |
| 2285 GenerateNameCheck(Handle<String>(name), &miss); | 1982 GenerateNameCheck(name, &miss); |
| 2286 | 1983 |
| 2287 if (cell == NULL) { | 1984 if (cell.is_null()) { |
| 2288 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1985 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2289 | 1986 |
| 2290 STATIC_ASSERT(kSmiTag == 0); | 1987 STATIC_ASSERT(kSmiTag == 0); |
| 2291 __ JumpIfSmi(edx, &miss); | 1988 __ JumpIfSmi(edx, &miss); |
| 2292 | 1989 |
| 2293 CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, | 1990 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 2294 &miss); | 1991 name, &miss); |
| 2295 } else { | 1992 } else { |
| 2296 ASSERT(cell->value() == function); | 1993 ASSERT(cell->value() == *function); |
| 2297 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); | 1994 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, |
| 1995 &miss); |
| 2298 GenerateLoadFunctionFromCell(cell, function, &miss); | 1996 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2299 } | 1997 } |
| 2300 | 1998 |
| 2301 // Load the (only) argument into eax. | 1999 // Load the (only) argument into eax. |
| 2302 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2000 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2303 | 2001 |
| 2304 // Check if the argument is a smi. | 2002 // Check if the argument is a smi. |
| 2305 Label not_smi; | 2003 Label not_smi; |
| 2306 STATIC_ASSERT(kSmiTag == 0); | 2004 STATIC_ASSERT(kSmiTag == 0); |
| 2307 __ JumpIfNotSmi(eax, ¬_smi); | 2005 __ JumpIfNotSmi(eax, ¬_smi); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2349 __ ret(2 * kPointerSize); | 2047 __ ret(2 * kPointerSize); |
| 2350 | 2048 |
| 2351 // Tail call the full function. We do not have to patch the receiver | 2049 // Tail call the full function. We do not have to patch the receiver |
| 2352 // because the function makes no use of it. | 2050 // because the function makes no use of it. |
| 2353 __ bind(&slow); | 2051 __ bind(&slow); |
| 2354 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, | 2052 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2355 NullCallWrapper(), CALL_AS_METHOD); | 2053 NullCallWrapper(), CALL_AS_METHOD); |
| 2356 | 2054 |
| 2357 __ bind(&miss); | 2055 __ bind(&miss); |
| 2358 // ecx: function name. | 2056 // ecx: function name. |
| 2359 MaybeObject* maybe_result = TryGenerateMissBranch(); | 2057 GenerateMissBranch(); |
| 2360 if (maybe_result->IsFailure()) return maybe_result; | |
| 2361 | 2058 |
| 2362 // Return the generated code. | 2059 // Return the generated code. |
| 2363 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name); | 2060 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name); |
| 2364 } | 2061 } |
| 2365 | 2062 |
| 2366 | 2063 |
| 2367 MaybeObject* CallStubCompiler::CompileFastApiCall( | 2064 Handle<Code> CallStubCompiler::CompileFastApiCall( |
| 2368 const CallOptimization& optimization, | 2065 const CallOptimization& optimization, |
| 2369 Object* object, | 2066 Handle<Object> object, |
| 2370 JSObject* holder, | 2067 Handle<JSObject> holder, |
| 2371 JSGlobalPropertyCell* cell, | 2068 Handle<JSGlobalPropertyCell> cell, |
| 2372 JSFunction* function, | 2069 Handle<JSFunction> function, |
| 2373 String* name) { | 2070 Handle<String> name) { |
| 2374 ASSERT(optimization.is_simple_api_call()); | 2071 ASSERT(optimization.is_simple_api_call()); |
| 2375 // Bail out if object is a global object as we don't want to | 2072 // Bail out if object is a global object as we don't want to |
| 2376 // repatch it to global receiver. | 2073 // repatch it to global receiver. |
| 2377 if (object->IsGlobalObject()) return heap()->undefined_value(); | 2074 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 2378 if (cell != NULL) return heap()->undefined_value(); | 2075 if (!cell.is_null()) return Handle<Code>::null(); |
| 2379 if (!object->IsJSObject()) return heap()->undefined_value(); | 2076 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 2380 int depth = optimization.GetPrototypeDepthOfExpectedType( | 2077 int depth = optimization.GetPrototypeDepthOfExpectedType( |
| 2381 JSObject::cast(object), holder); | 2078 Handle<JSObject>::cast(object), holder); |
| 2382 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); | 2079 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); |
| 2383 | 2080 |
| 2384 Label miss, miss_before_stack_reserved; | 2081 Label miss, miss_before_stack_reserved; |
| 2385 | 2082 |
| 2386 GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved); | 2083 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 2387 | 2084 |
| 2388 // Get the receiver from the stack. | 2085 // Get the receiver from the stack. |
| 2389 const int argc = arguments().immediate(); | 2086 const int argc = arguments().immediate(); |
| 2390 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2087 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2391 | 2088 |
| 2392 // Check that the receiver isn't a smi. | 2089 // Check that the receiver isn't a smi. |
| 2393 __ JumpIfSmi(edx, &miss_before_stack_reserved); | 2090 __ JumpIfSmi(edx, &miss_before_stack_reserved); |
| 2394 | 2091 |
| 2395 Counters* counters = isolate()->counters(); | 2092 Counters* counters = isolate()->counters(); |
| 2396 __ IncrementCounter(counters->call_const(), 1); | 2093 __ IncrementCounter(counters->call_const(), 1); |
| 2397 __ IncrementCounter(counters->call_const_fast_api(), 1); | 2094 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 2398 | 2095 |
| 2399 // Allocate space for v8::Arguments implicit values. Must be initialized | 2096 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2400 // before calling any runtime function. | 2097 // before calling any runtime function. |
| 2401 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); | 2098 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2402 | 2099 |
| 2403 // Check that the maps haven't changed and find a Holder as a side effect. | 2100 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2404 CheckPrototypes(JSObject::cast(object), edx, holder, | 2101 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, |
| 2405 ebx, eax, edi, name, depth, &miss); | 2102 name, depth, &miss); |
| 2406 | 2103 |
| 2407 // Move the return address on top of the stack. | 2104 // Move the return address on top of the stack. |
| 2408 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 2105 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 2409 __ mov(Operand(esp, 0 * kPointerSize), eax); | 2106 __ mov(Operand(esp, 0 * kPointerSize), eax); |
| 2410 | 2107 |
| 2411 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 2108 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains |
| 2412 // duplicate of return address and will be overwritten. | 2109 // duplicate of return address and will be overwritten. |
| 2413 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); | 2110 GenerateFastApiCall(masm(), optimization, argc); |
| 2414 if (result->IsFailure()) return result; | |
| 2415 | 2111 |
| 2416 __ bind(&miss); | 2112 __ bind(&miss); |
| 2417 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); | 2113 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2418 | 2114 |
| 2419 __ bind(&miss_before_stack_reserved); | 2115 __ bind(&miss_before_stack_reserved); |
| 2420 MaybeObject* maybe_result = TryGenerateMissBranch(); | 2116 GenerateMissBranch(); |
| 2421 if (maybe_result->IsFailure()) return maybe_result; | |
| 2422 | 2117 |
| 2423 // Return the generated code. | 2118 // Return the generated code. |
| 2424 return TryGetCode(function); | 2119 return GetCode(function); |
| 2425 } | 2120 } |
| 2426 | 2121 |
| 2427 | 2122 |
| 2428 MaybeObject* CallStubCompiler::CompileCallConstant( | 2123 Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, |
| 2429 Object* object, | 2124 Handle<JSObject> holder, |
| 2430 JSObject* holder, | 2125 Handle<JSFunction> function, |
| 2431 JSFunction* function, | 2126 Handle<String> name, |
| 2432 String* name, | 2127 CheckType check) { |
| 2433 CheckType check) { | |
| 2434 // ----------- S t a t e ------------- | 2128 // ----------- S t a t e ------------- |
| 2435 // -- ecx : name | 2129 // -- ecx : name |
| 2436 // -- esp[0] : return address | 2130 // -- esp[0] : return address |
| 2437 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2131 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2438 // -- ... | 2132 // -- ... |
| 2439 // -- esp[(argc + 1) * 4] : receiver | 2133 // -- esp[(argc + 1) * 4] : receiver |
| 2440 // ----------------------------------- | 2134 // ----------------------------------- |
| 2441 | 2135 |
| 2442 if (HasCustomCallGenerator(function)) { | 2136 if (HasCustomCallGenerator(function)) { |
| 2443 MaybeObject* maybe_result = CompileCustomCall( | 2137 Handle<Code> code = CompileCustomCall(object, holder, |
| 2444 object, holder, NULL, function, name); | 2138 Handle<JSGlobalPropertyCell>::null(), |
| 2445 Object* result; | 2139 function, name); |
| 2446 if (!maybe_result->ToObject(&result)) return maybe_result; | 2140 // A null handle means bail out to the regular compiler code below. |
| 2447 // undefined means bail out to regular compiler. | 2141 if (!code.is_null()) return code; |
| 2448 if (!result->IsUndefined()) return result; | |
| 2449 } | 2142 } |
| 2450 | 2143 |
| 2451 Label miss; | 2144 Label miss; |
| 2452 | 2145 GenerateNameCheck(name, &miss); |
| 2453 GenerateNameCheck(Handle<String>(name), &miss); | |
| 2454 | 2146 |
| 2455 // Get the receiver from the stack. | 2147 // Get the receiver from the stack. |
| 2456 const int argc = arguments().immediate(); | 2148 const int argc = arguments().immediate(); |
| 2457 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2149 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2458 | 2150 |
| 2459 // Check that the receiver isn't a smi. | 2151 // Check that the receiver isn't a smi. |
| 2460 if (check != NUMBER_CHECK) { | 2152 if (check != NUMBER_CHECK) { |
| 2461 __ JumpIfSmi(edx, &miss); | 2153 __ JumpIfSmi(edx, &miss); |
| 2462 } | 2154 } |
| 2463 | 2155 |
| 2464 // Make sure that it's okay not to patch the on stack receiver | 2156 // Make sure that it's okay not to patch the on stack receiver |
| 2465 // unless we're doing a receiver map check. | 2157 // unless we're doing a receiver map check. |
| 2466 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 2158 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 2467 | |
| 2468 SharedFunctionInfo* function_info = function->shared(); | |
| 2469 switch (check) { | 2159 switch (check) { |
| 2470 case RECEIVER_MAP_CHECK: | 2160 case RECEIVER_MAP_CHECK: |
| 2471 __ IncrementCounter(isolate()->counters()->call_const(), 1); | 2161 __ IncrementCounter(isolate()->counters()->call_const(), 1); |
| 2472 | 2162 |
| 2473 // Check that the maps haven't changed. | 2163 // Check that the maps haven't changed. |
| 2474 CheckPrototypes(JSObject::cast(object), edx, holder, | 2164 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, |
| 2475 ebx, eax, edi, name, &miss); | 2165 edi, name, &miss); |
| 2476 | 2166 |
| 2477 // Patch the receiver on the stack with the global proxy if | 2167 // Patch the receiver on the stack with the global proxy if |
| 2478 // necessary. | 2168 // necessary. |
| 2479 if (object->IsGlobalObject()) { | 2169 if (object->IsGlobalObject()) { |
| 2480 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2170 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2481 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2171 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2482 } | 2172 } |
| 2483 break; | 2173 break; |
| 2484 | 2174 |
| 2485 case STRING_CHECK: | 2175 case STRING_CHECK: |
| 2486 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2176 if (function->IsBuiltin() || function->shared()->strict_mode()) { |
| 2487 // Calling non-strict non-builtins with a value as the receiver | |
| 2488 // requires boxing. | |
| 2489 __ jmp(&miss); | |
| 2490 } else { | |
| 2491 // Check that the object is a string or a symbol. | 2177 // Check that the object is a string or a symbol. |
| 2492 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); | 2178 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); |
| 2493 __ j(above_equal, &miss); | 2179 __ j(above_equal, &miss); |
| 2494 // Check that the maps starting from the prototype haven't changed. | 2180 // Check that the maps starting from the prototype haven't changed. |
| 2495 GenerateDirectLoadGlobalFunctionPrototype( | 2181 GenerateDirectLoadGlobalFunctionPrototype( |
| 2496 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); | 2182 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); |
| 2497 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2183 CheckPrototypes( |
| 2498 ebx, edx, edi, name, &miss); | 2184 Handle<JSObject>(JSObject::cast(object->GetPrototype())), |
| 2185 eax, holder, ebx, edx, edi, name, &miss); |
| 2186 } else { |
| 2187 // Calling non-strict non-builtins with a value as the receiver |
| 2188 // requires boxing. |
| 2189 __ jmp(&miss); |
| 2499 } | 2190 } |
| 2500 break; | 2191 break; |
| 2501 | 2192 |
| 2502 case NUMBER_CHECK: { | 2193 case NUMBER_CHECK: |
| 2503 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2194 if (function->IsBuiltin() || function->shared()->strict_mode()) { |
| 2504 // Calling non-strict non-builtins with a value as the receiver | |
| 2505 // requires boxing. | |
| 2506 __ jmp(&miss); | |
| 2507 } else { | |
| 2508 Label fast; | 2195 Label fast; |
| 2509 // Check that the object is a smi or a heap number. | 2196 // Check that the object is a smi or a heap number. |
| 2510 __ JumpIfSmi(edx, &fast); | 2197 __ JumpIfSmi(edx, &fast); |
| 2511 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); | 2198 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); |
| 2512 __ j(not_equal, &miss); | 2199 __ j(not_equal, &miss); |
| 2513 __ bind(&fast); | 2200 __ bind(&fast); |
| 2514 // Check that the maps starting from the prototype haven't changed. | 2201 // Check that the maps starting from the prototype haven't changed. |
| 2515 GenerateDirectLoadGlobalFunctionPrototype( | 2202 GenerateDirectLoadGlobalFunctionPrototype( |
| 2516 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); | 2203 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); |
| 2517 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2204 CheckPrototypes( |
| 2518 ebx, edx, edi, name, &miss); | 2205 Handle<JSObject>(JSObject::cast(object->GetPrototype())), |
| 2519 } | 2206 eax, holder, ebx, edx, edi, name, &miss); |
| 2520 break; | 2207 } else { |
| 2521 } | |
| 2522 | |
| 2523 case BOOLEAN_CHECK: { | |
| 2524 if (!function->IsBuiltin() && !function_info->strict_mode()) { | |
| 2525 // Calling non-strict non-builtins with a value as the receiver | 2208 // Calling non-strict non-builtins with a value as the receiver |
| 2526 // requires boxing. | 2209 // requires boxing. |
| 2527 __ jmp(&miss); | 2210 __ jmp(&miss); |
| 2528 } else { | 2211 } |
| 2212 break; |
| 2213 |
| 2214 case BOOLEAN_CHECK: |
| 2215 if (function->IsBuiltin() || function->shared()->strict_mode()) { |
| 2529 Label fast; | 2216 Label fast; |
| 2530 // Check that the object is a boolean. | 2217 // Check that the object is a boolean. |
| 2531 __ cmp(edx, factory()->true_value()); | 2218 __ cmp(edx, factory()->true_value()); |
| 2532 __ j(equal, &fast); | 2219 __ j(equal, &fast); |
| 2533 __ cmp(edx, factory()->false_value()); | 2220 __ cmp(edx, factory()->false_value()); |
| 2534 __ j(not_equal, &miss); | 2221 __ j(not_equal, &miss); |
| 2535 __ bind(&fast); | 2222 __ bind(&fast); |
| 2536 // Check that the maps starting from the prototype haven't changed. | 2223 // Check that the maps starting from the prototype haven't changed. |
| 2537 GenerateDirectLoadGlobalFunctionPrototype( | 2224 GenerateDirectLoadGlobalFunctionPrototype( |
| 2538 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); | 2225 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); |
| 2539 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2226 CheckPrototypes( |
| 2540 ebx, edx, edi, name, &miss); | 2227 Handle<JSObject>(JSObject::cast(object->GetPrototype())), |
| 2228 eax, holder, ebx, edx, edi, name, &miss); |
| 2229 } else { |
| 2230 // Calling non-strict non-builtins with a value as the receiver |
| 2231 // requires boxing. |
| 2232 __ jmp(&miss); |
| 2541 } | 2233 } |
| 2542 break; | 2234 break; |
| 2543 } | |
| 2544 | |
| 2545 default: | |
| 2546 UNREACHABLE(); | |
| 2547 } | 2235 } |
| 2548 | 2236 |
| 2549 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 2237 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) |
| 2550 ? CALL_AS_FUNCTION | 2238 ? CALL_AS_FUNCTION |
| 2551 : CALL_AS_METHOD; | 2239 : CALL_AS_METHOD; |
| 2552 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, | 2240 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, |
| 2553 NullCallWrapper(), call_kind); | 2241 NullCallWrapper(), call_kind); |
| 2554 | 2242 |
| 2555 // Handle call cache miss. | 2243 // Handle call cache miss. |
| 2556 __ bind(&miss); | 2244 __ bind(&miss); |
| 2557 MaybeObject* maybe_result = TryGenerateMissBranch(); | 2245 GenerateMissBranch(); |
| 2558 if (maybe_result->IsFailure()) return maybe_result; | |
| 2559 | 2246 |
| 2560 // Return the generated code. | 2247 // Return the generated code. |
| 2561 return TryGetCode(function); | 2248 return GetCode(function); |
| 2562 } | 2249 } |
| 2563 | 2250 |
| 2564 | 2251 |
| 2565 MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, | 2252 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, |
| 2566 JSObject* holder, | 2253 Handle<JSObject> holder, |
| 2567 String* name) { | 2254 Handle<String> name) { |
| 2568 // ----------- S t a t e ------------- | 2255 // ----------- S t a t e ------------- |
| 2569 // -- ecx : name | 2256 // -- ecx : name |
| 2570 // -- esp[0] : return address | 2257 // -- esp[0] : return address |
| 2571 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2258 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2572 // -- ... | 2259 // -- ... |
| 2573 // -- esp[(argc + 1) * 4] : receiver | 2260 // -- esp[(argc + 1) * 4] : receiver |
| 2574 // ----------------------------------- | 2261 // ----------------------------------- |
| 2575 Label miss; | 2262 Label miss; |
| 2576 | 2263 |
| 2577 GenerateNameCheck(Handle<String>(name), &miss); | 2264 GenerateNameCheck(name, &miss); |
| 2578 | 2265 |
| 2579 // Get the number of arguments. | 2266 // Get the number of arguments. |
| 2580 const int argc = arguments().immediate(); | 2267 const int argc = arguments().immediate(); |
| 2581 | 2268 |
| 2582 LookupResult lookup(isolate()); | 2269 LookupResult lookup(isolate()); |
| 2583 LookupPostInterceptor(holder, name, &lookup); | 2270 LookupPostInterceptor(holder, name, &lookup); |
| 2584 | 2271 |
| 2585 // Get the receiver from the stack. | 2272 // Get the receiver from the stack. |
| 2586 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2273 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2587 | 2274 |
| 2588 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_); | 2275 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_); |
| 2589 MaybeObject* result = compiler.Compile(masm(), | 2276 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax, |
| 2590 object, | 2277 &miss); |
| 2591 holder, | |
| 2592 name, | |
| 2593 &lookup, | |
| 2594 edx, | |
| 2595 ebx, | |
| 2596 edi, | |
| 2597 eax, | |
| 2598 &miss); | |
| 2599 if (result->IsFailure()) return result; | |
| 2600 | 2278 |
| 2601 // Restore receiver. | 2279 // Restore receiver. |
| 2602 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2280 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2603 | 2281 |
| 2604 // Check that the function really is a function. | 2282 // Check that the function really is a function. |
| 2605 __ JumpIfSmi(eax, &miss); | 2283 __ JumpIfSmi(eax, &miss); |
| 2606 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2284 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2607 __ j(not_equal, &miss); | 2285 __ j(not_equal, &miss); |
| 2608 | 2286 |
| 2609 // Patch the receiver on the stack with the global proxy if | 2287 // Patch the receiver on the stack with the global proxy if |
| 2610 // necessary. | 2288 // necessary. |
| 2611 if (object->IsGlobalObject()) { | 2289 if (object->IsGlobalObject()) { |
| 2612 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2290 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2613 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2291 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2614 } | 2292 } |
| 2615 | 2293 |
| 2616 // Invoke the function. | 2294 // Invoke the function. |
| 2617 __ mov(edi, eax); | 2295 __ mov(edi, eax); |
| 2618 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 2296 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) |
| 2619 ? CALL_AS_FUNCTION | 2297 ? CALL_AS_FUNCTION |
| 2620 : CALL_AS_METHOD; | 2298 : CALL_AS_METHOD; |
| 2621 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, | 2299 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, |
| 2622 NullCallWrapper(), call_kind); | 2300 NullCallWrapper(), call_kind); |
| 2623 | 2301 |
| 2624 // Handle load cache miss. | 2302 // Handle load cache miss. |
| 2625 __ bind(&miss); | 2303 __ bind(&miss); |
| 2626 MaybeObject* maybe_result = TryGenerateMissBranch(); | 2304 GenerateMissBranch(); |
| 2627 if (maybe_result->IsFailure()) return maybe_result; | |
| 2628 | 2305 |
| 2629 // Return the generated code. | 2306 // Return the generated code. |
| 2630 return TryGetCode(INTERCEPTOR, name); | 2307 return GetCode(INTERCEPTOR, name); |
| 2631 } | 2308 } |
| 2632 | 2309 |
| 2633 | 2310 |
| 2634 MaybeObject* CallStubCompiler::CompileCallGlobal( | 2311 Handle<Code> CallStubCompiler::CompileCallGlobal( |
| 2635 JSObject* object, | 2312 Handle<JSObject> object, |
| 2636 GlobalObject* holder, | 2313 Handle<GlobalObject> holder, |
| 2637 JSGlobalPropertyCell* cell, | 2314 Handle<JSGlobalPropertyCell> cell, |
| 2638 JSFunction* function, | 2315 Handle<JSFunction> function, |
| 2639 String* name) { | 2316 Handle<String> name) { |
| 2640 // ----------- S t a t e ------------- | 2317 // ----------- S t a t e ------------- |
| 2641 // -- ecx : name | 2318 // -- ecx : name |
| 2642 // -- esp[0] : return address | 2319 // -- esp[0] : return address |
| 2643 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2320 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2644 // -- ... | 2321 // -- ... |
| 2645 // -- esp[(argc + 1) * 4] : receiver | 2322 // -- esp[(argc + 1) * 4] : receiver |
| 2646 // ----------------------------------- | 2323 // ----------------------------------- |
| 2647 | 2324 |
| 2648 if (HasCustomCallGenerator(function)) { | 2325 if (HasCustomCallGenerator(function)) { |
| 2649 MaybeObject* maybe_result = CompileCustomCall( | 2326 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name); |
| 2650 object, holder, cell, function, name); | 2327 // A null handle means bail out to the regular compiler code below. |
| 2651 Object* result; | 2328 if (!code.is_null()) return code; |
| 2652 if (!maybe_result->ToObject(&result)) return maybe_result; | |
| 2653 // undefined means bail out to regular compiler. | |
| 2654 if (!result->IsUndefined()) return result; | |
| 2655 } | 2329 } |
| 2656 | 2330 |
| 2657 Label miss; | 2331 Label miss; |
| 2658 | 2332 GenerateNameCheck(name, &miss); |
| 2659 GenerateNameCheck(Handle<String>(name), &miss); | |
| 2660 | 2333 |
| 2661 // Get the number of arguments. | 2334 // Get the number of arguments. |
| 2662 const int argc = arguments().immediate(); | 2335 const int argc = arguments().immediate(); |
| 2663 | |
| 2664 GenerateGlobalReceiverCheck(object, holder, name, &miss); | 2336 GenerateGlobalReceiverCheck(object, holder, name, &miss); |
| 2665 | |
| 2666 GenerateLoadFunctionFromCell(cell, function, &miss); | 2337 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2667 | 2338 |
| 2668 // Patch the receiver on the stack with the global proxy. | 2339 // Patch the receiver on the stack with the global proxy. |
| 2669 if (object->IsGlobalObject()) { | 2340 if (object->IsGlobalObject()) { |
| 2670 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2341 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2671 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2342 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2672 } | 2343 } |
| 2673 | 2344 |
| 2674 // Setup the context (function already in edi). | 2345 // Setup the context (function already in edi). |
| 2675 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 2346 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 2676 | 2347 |
| 2677 // Jump to the cached code (tail call). | 2348 // Jump to the cached code (tail call). |
| 2678 Counters* counters = isolate()->counters(); | 2349 Counters* counters = isolate()->counters(); |
| 2679 __ IncrementCounter(counters->call_global_inline(), 1); | 2350 __ IncrementCounter(counters->call_global_inline(), 1); |
| 2680 ParameterCount expected(function->shared()->formal_parameter_count()); | 2351 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2681 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 2352 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) |
| 2682 ? CALL_AS_FUNCTION | 2353 ? CALL_AS_FUNCTION |
| 2683 : CALL_AS_METHOD; | 2354 : CALL_AS_METHOD; |
| 2684 // We call indirectly through the code field in the function to | 2355 // We call indirectly through the code field in the function to |
| 2685 // allow recompilation to take effect without changing any of the | 2356 // allow recompilation to take effect without changing any of the |
| 2686 // call sites. | 2357 // call sites. |
| 2687 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 2358 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 2688 expected, arguments(), JUMP_FUNCTION, | 2359 expected, arguments(), JUMP_FUNCTION, |
| 2689 NullCallWrapper(), call_kind); | 2360 NullCallWrapper(), call_kind); |
| 2690 | 2361 |
| 2691 // Handle call cache miss. | 2362 // Handle call cache miss. |
| 2692 __ bind(&miss); | 2363 __ bind(&miss); |
| 2693 __ IncrementCounter(counters->call_global_inline_miss(), 1); | 2364 __ IncrementCounter(counters->call_global_inline_miss(), 1); |
| 2694 MaybeObject* maybe_result = TryGenerateMissBranch(); | 2365 GenerateMissBranch(); |
| 2695 if (maybe_result->IsFailure()) return maybe_result; | |
| 2696 | 2366 |
| 2697 // Return the generated code. | 2367 // Return the generated code. |
| 2698 return TryGetCode(NORMAL, name); | 2368 return GetCode(NORMAL, name); |
| 2699 } | 2369 } |
| 2700 | 2370 |
| 2701 | 2371 |
| 2702 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, | 2372 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, |
| 2703 int index, | 2373 int index, |
| 2704 Handle<Map> transition, | 2374 Handle<Map> transition, |
| 2705 Handle<String> name) { | 2375 Handle<String> name) { |
| 2706 // ----------- S t a t e ------------- | 2376 // ----------- S t a t e ------------- |
| 2707 // -- eax : value | 2377 // -- eax : value |
| 2708 // -- ecx : name | 2378 // -- ecx : name |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3032 | 2702 |
| 3033 GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss); | 2703 GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss); |
| 3034 __ bind(&miss); | 2704 __ bind(&miss); |
| 3035 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2705 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 3036 | 2706 |
| 3037 // Return the generated code. | 2707 // Return the generated code. |
| 3038 return GetCode(FIELD, name); | 2708 return GetCode(FIELD, name); |
| 3039 } | 2709 } |
| 3040 | 2710 |
| 3041 | 2711 |
| 3042 MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, | 2712 Handle<Code> LoadStubCompiler::CompileLoadCallback( |
| 3043 JSObject* object, | 2713 Handle<String> name, |
| 3044 JSObject* holder, | 2714 Handle<JSObject> object, |
| 3045 AccessorInfo* callback) { | 2715 Handle<JSObject> holder, |
| 2716 Handle<AccessorInfo> callback) { |
| 3046 // ----------- S t a t e ------------- | 2717 // ----------- S t a t e ------------- |
| 3047 // -- eax : receiver | 2718 // -- eax : receiver |
| 3048 // -- ecx : name | 2719 // -- ecx : name |
| 3049 // -- esp[0] : return address | 2720 // -- esp[0] : return address |
| 3050 // ----------------------------------- | 2721 // ----------------------------------- |
| 3051 Label miss; | 2722 Label miss; |
| 3052 | 2723 |
| 3053 MaybeObject* result = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, | 2724 GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, callback, |
| 3054 edi, callback, name, &miss); | 2725 name, &miss); |
| 3055 if (result->IsFailure()) { | |
| 3056 miss.Unuse(); | |
| 3057 return result; | |
| 3058 } | |
| 3059 | |
| 3060 __ bind(&miss); | 2726 __ bind(&miss); |
| 3061 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2727 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 3062 | 2728 |
| 3063 // Return the generated code. | 2729 // Return the generated code. |
| 3064 return TryGetCode(CALLBACKS, name); | 2730 return GetCode(CALLBACKS, name); |
| 3065 } | 2731 } |
| 3066 | 2732 |
| 3067 | 2733 |
| 3068 Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object, | 2734 Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object, |
| 3069 Handle<JSObject> holder, | 2735 Handle<JSObject> holder, |
| 3070 Handle<Object> value, | 2736 Handle<Object> value, |
| 3071 Handle<String> name) { | 2737 Handle<String> name) { |
| 3072 // ----------- S t a t e ------------- | 2738 // ----------- S t a t e ------------- |
| 3073 // -- eax : receiver | 2739 // -- eax : receiver |
| 3074 // -- ecx : name | 2740 // -- ecx : name |
| 3075 // -- esp[0] : return address | 2741 // -- esp[0] : return address |
| 3076 // ----------------------------------- | 2742 // ----------------------------------- |
| 3077 Label miss; | 2743 Label miss; |
| 3078 | 2744 |
| 3079 GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss); | 2745 GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss); |
| 3080 __ bind(&miss); | 2746 __ bind(&miss); |
| 3081 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2747 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 3082 | 2748 |
| 3083 // Return the generated code. | 2749 // Return the generated code. |
| 3084 return GetCode(CONSTANT_FUNCTION, name); | 2750 return GetCode(CONSTANT_FUNCTION, name); |
| 3085 } | 2751 } |
| 3086 | 2752 |
| 3087 | 2753 |
| 3088 MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, | 2754 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver, |
| 3089 JSObject* holder, | 2755 Handle<JSObject> holder, |
| 3090 String* name) { | 2756 Handle<String> name) { |
| 3091 // ----------- S t a t e ------------- | 2757 // ----------- S t a t e ------------- |
| 3092 // -- eax : receiver | 2758 // -- eax : receiver |
| 3093 // -- ecx : name | 2759 // -- ecx : name |
| 3094 // -- esp[0] : return address | 2760 // -- esp[0] : return address |
| 3095 // ----------------------------------- | 2761 // ----------------------------------- |
| 3096 Label miss; | 2762 Label miss; |
| 3097 | 2763 |
| 3098 LookupResult lookup(isolate()); | 2764 LookupResult lookup(isolate()); |
| 3099 LookupPostInterceptor(holder, name, &lookup); | 2765 LookupPostInterceptor(holder, name, &lookup); |
| 3100 | 2766 |
| 3101 // TODO(368): Compile in the whole chain: all the interceptors in | 2767 // TODO(368): Compile in the whole chain: all the interceptors in |
| 3102 // prototypes and ultimate answer. | 2768 // prototypes and ultimate answer. |
| 3103 GenerateLoadInterceptor(receiver, | 2769 GenerateLoadInterceptor(receiver, holder, &lookup, eax, ecx, edx, ebx, edi, |
| 3104 holder, | 2770 name, &miss); |
| 3105 &lookup, | |
| 3106 eax, | |
| 3107 ecx, | |
| 3108 edx, | |
| 3109 ebx, | |
| 3110 edi, | |
| 3111 name, | |
| 3112 &miss); | |
| 3113 | 2771 |
| 3114 __ bind(&miss); | 2772 __ bind(&miss); |
| 3115 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2773 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 3116 | 2774 |
| 3117 // Return the generated code. | 2775 // Return the generated code. |
| 3118 return TryGetCode(INTERCEPTOR, name); | 2776 return GetCode(INTERCEPTOR, name); |
| 3119 } | 2777 } |
| 3120 | 2778 |
| 3121 | 2779 |
| 3122 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2780 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 3123 Handle<JSObject> object, | 2781 Handle<JSObject> object, |
| 3124 Handle<GlobalObject> holder, | 2782 Handle<GlobalObject> holder, |
| 3125 Handle<JSGlobalPropertyCell> cell, | 2783 Handle<JSGlobalPropertyCell> cell, |
| 3126 Handle<String> name, | 2784 Handle<String> name, |
| 3127 bool is_dont_delete) { | 2785 bool is_dont_delete) { |
| 3128 // ----------- S t a t e ------------- | 2786 // ----------- S t a t e ------------- |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3195 | 2853 |
| 3196 __ bind(&miss); | 2854 __ bind(&miss); |
| 3197 __ DecrementCounter(counters->keyed_load_field(), 1); | 2855 __ DecrementCounter(counters->keyed_load_field(), 1); |
| 3198 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2856 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3199 | 2857 |
| 3200 // Return the generated code. | 2858 // Return the generated code. |
| 3201 return GetCode(FIELD, name); | 2859 return GetCode(FIELD, name); |
| 3202 } | 2860 } |
| 3203 | 2861 |
| 3204 | 2862 |
| 3205 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( | 2863 Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback( |
| 3206 String* name, | 2864 Handle<String> name, |
| 3207 JSObject* receiver, | 2865 Handle<JSObject> receiver, |
| 3208 JSObject* holder, | 2866 Handle<JSObject> holder, |
| 3209 AccessorInfo* callback) { | 2867 Handle<AccessorInfo> callback) { |
| 3210 // ----------- S t a t e ------------- | 2868 // ----------- S t a t e ------------- |
| 3211 // -- eax : key | 2869 // -- eax : key |
| 3212 // -- edx : receiver | 2870 // -- edx : receiver |
| 3213 // -- esp[0] : return address | 2871 // -- esp[0] : return address |
| 3214 // ----------------------------------- | 2872 // ----------------------------------- |
| 3215 Label miss; | 2873 Label miss; |
| 3216 | 2874 |
| 3217 Counters* counters = isolate()->counters(); | 2875 Counters* counters = isolate()->counters(); |
| 3218 __ IncrementCounter(counters->keyed_load_callback(), 1); | 2876 __ IncrementCounter(counters->keyed_load_callback(), 1); |
| 3219 | 2877 |
| 3220 // Check that the name has not changed. | 2878 // Check that the name has not changed. |
| 3221 __ cmp(eax, Immediate(Handle<String>(name))); | 2879 __ cmp(eax, Immediate(name)); |
| 3222 __ j(not_equal, &miss); | 2880 __ j(not_equal, &miss); |
| 3223 | 2881 |
| 3224 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, | 2882 GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, callback, |
| 3225 ecx, edi, callback, name, &miss); | 2883 name, &miss); |
| 3226 if (result->IsFailure()) { | |
| 3227 miss.Unuse(); | |
| 3228 return result; | |
| 3229 } | |
| 3230 | 2884 |
| 3231 __ bind(&miss); | 2885 __ bind(&miss); |
| 3232 | |
| 3233 __ DecrementCounter(counters->keyed_load_callback(), 1); | 2886 __ DecrementCounter(counters->keyed_load_callback(), 1); |
| 3234 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2887 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3235 | 2888 |
| 3236 // Return the generated code. | 2889 // Return the generated code. |
| 3237 return TryGetCode(CALLBACKS, name); | 2890 return GetCode(CALLBACKS, name); |
| 3238 } | 2891 } |
| 3239 | 2892 |
| 3240 | 2893 |
| 3241 Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant( | 2894 Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant( |
| 3242 Handle<String> name, | 2895 Handle<String> name, |
| 3243 Handle<JSObject> receiver, | 2896 Handle<JSObject> receiver, |
| 3244 Handle<JSObject> holder, | 2897 Handle<JSObject> holder, |
| 3245 Handle<Object> value) { | 2898 Handle<Object> value) { |
| 3246 // ----------- S t a t e ------------- | 2899 // ----------- S t a t e ------------- |
| 3247 // -- eax : key | 2900 // -- eax : key |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3261 receiver, holder, edx, ebx, ecx, edi, value, name, &miss); | 2914 receiver, holder, edx, ebx, ecx, edi, value, name, &miss); |
| 3262 __ bind(&miss); | 2915 __ bind(&miss); |
| 3263 __ DecrementCounter(counters->keyed_load_constant_function(), 1); | 2916 __ DecrementCounter(counters->keyed_load_constant_function(), 1); |
| 3264 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2917 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3265 | 2918 |
| 3266 // Return the generated code. | 2919 // Return the generated code. |
| 3267 return GetCode(CONSTANT_FUNCTION, name); | 2920 return GetCode(CONSTANT_FUNCTION, name); |
| 3268 } | 2921 } |
| 3269 | 2922 |
| 3270 | 2923 |
| 3271 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, | 2924 Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor( |
| 3272 JSObject* holder, | 2925 Handle<JSObject> receiver, |
| 3273 String* name) { | 2926 Handle<JSObject> holder, |
| 2927 Handle<String> name) { |
| 3274 // ----------- S t a t e ------------- | 2928 // ----------- S t a t e ------------- |
| 3275 // -- eax : key | 2929 // -- eax : key |
| 3276 // -- edx : receiver | 2930 // -- edx : receiver |
| 3277 // -- esp[0] : return address | 2931 // -- esp[0] : return address |
| 3278 // ----------------------------------- | 2932 // ----------------------------------- |
| 3279 Label miss; | 2933 Label miss; |
| 3280 | 2934 |
| 3281 Counters* counters = isolate()->counters(); | 2935 Counters* counters = isolate()->counters(); |
| 3282 __ IncrementCounter(counters->keyed_load_interceptor(), 1); | 2936 __ IncrementCounter(counters->keyed_load_interceptor(), 1); |
| 3283 | 2937 |
| 3284 // Check that the name has not changed. | 2938 // Check that the name has not changed. |
| 3285 __ cmp(eax, Immediate(Handle<String>(name))); | 2939 __ cmp(eax, Immediate(name)); |
| 3286 __ j(not_equal, &miss); | 2940 __ j(not_equal, &miss); |
| 3287 | 2941 |
| 3288 LookupResult lookup(isolate()); | 2942 LookupResult lookup(isolate()); |
| 3289 LookupPostInterceptor(holder, name, &lookup); | 2943 LookupPostInterceptor(holder, name, &lookup); |
| 3290 GenerateLoadInterceptor(receiver, | 2944 GenerateLoadInterceptor(receiver, holder, &lookup, edx, eax, ecx, ebx, edi, |
| 3291 holder, | 2945 name, &miss); |
| 3292 &lookup, | |
| 3293 edx, | |
| 3294 eax, | |
| 3295 ecx, | |
| 3296 ebx, | |
| 3297 edi, | |
| 3298 name, | |
| 3299 &miss); | |
| 3300 __ bind(&miss); | 2946 __ bind(&miss); |
| 3301 __ DecrementCounter(counters->keyed_load_interceptor(), 1); | 2947 __ DecrementCounter(counters->keyed_load_interceptor(), 1); |
| 3302 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2948 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3303 | 2949 |
| 3304 // Return the generated code. | 2950 // Return the generated code. |
| 3305 return TryGetCode(INTERCEPTOR, name); | 2951 return GetCode(INTERCEPTOR, name); |
| 3306 } | 2952 } |
| 3307 | 2953 |
| 3308 | 2954 |
| 3309 Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( | 2955 Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( |
| 3310 Handle<String> name) { | 2956 Handle<String> name) { |
| 3311 // ----------- S t a t e ------------- | 2957 // ----------- S t a t e ------------- |
| 3312 // -- eax : key | 2958 // -- eax : key |
| 3313 // -- edx : receiver | 2959 // -- edx : receiver |
| 3314 // -- esp[0] : return address | 2960 // -- esp[0] : return address |
| 3315 // ----------------------------------- | 2961 // ----------------------------------- |
| (...skipping 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4209 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); | 3855 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
| 4210 __ jmp(ic_miss, RelocInfo::CODE_TARGET); | 3856 __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| 4211 } | 3857 } |
| 4212 | 3858 |
| 4213 | 3859 |
| 4214 #undef __ | 3860 #undef __ |
| 4215 | 3861 |
| 4216 } } // namespace v8::internal | 3862 } } // namespace v8::internal |
| 4217 | 3863 |
| 4218 #endif // V8_TARGET_ARCH_IA32 | 3864 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |